module Padrino::Helpers::FormatHelpers

def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})


distance_of_time_in_words(Time.now, Time.now) # => less than a minute
distance_of_time_in_words(to_time, from_time, true) # => about 6 years
distance_of_time_in_words(from_time, to_time, true) # => about 6 years
to_time = Time.now + 6.years + 19.days

distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => about 4 years
distance_of_time_in_words(from_time, from_time + 3.years + 6.months) # => over 3 years
distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 year
distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute
distance_of_time_in_words(from_time, from_time - 45.seconds, true) # => less than a minute
distance_of_time_in_words(from_time, from_time + 45.seconds, true) # => less than a minute
distance_of_time_in_words(from_time, from_time + 60.hours) # => about 3 days
distance_of_time_in_words(from_time, 3.years.from_now) # => about 3 years
distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds
distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute
distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour
distance_of_time_in_words(from_time, from_time + 50.minutes) # => about 1 hour
from_time = Time.now

==== Examples

60-89 secs # => 1 minute
40-59 secs # => less than a minute
20-39 secs # => half a minute
10-19 secs # => less than 20 seconds
5-9 secs # => less than 10 seconds
0-4 secs # => less than 5 seconds
With include_seconds = true and the difference < 1 minute 29 seconds:

2 yrs <-> max time or date # => (same rules as 1 yr)
1 yr, 9 months <-> 2 yr minus 1 sec # => almost 2 years
1 yr, 3 months <-> 1 yr, 9 months # => over 1 year
1 yr <-> 1 yr, 3 months # => about 1 year
59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months
29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month
47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days
23 hrs, 59 mins, 29 secs <-> 47 hrs, 59 mins, 29 secs # => 1 day
89 mins, 29 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours
44 mins, 30 secs <-> 89 mins, 29 secs # => about 1 hour
1 min, 30 secs <-> 44 mins, 29 secs # => [2..44] minutes
30 secs <-> 1 min, 29 secs # => 1 minute
0 <-> 29 secs # => less than a minute

Distances are reported based on the following table:
Set include_seconds to true if you want more detailed approximations when distance < 1 min, 29 secs
Reports the approximate distance in time between two Time or Date objects or integers as seconds.
#
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
  from_time = from_time.to_time if from_time.respond_to?(:to_time)
  to_time = to_time.to_time if to_time.respond_to?(:to_time)
  distance_in_minutes = (((to_time - from_time).abs)/60).round
  distance_in_seconds = ((to_time - from_time).abs).round
  I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|
    case distance_in_minutes
      when 0..1
        return distance_in_minutes == 0 ?
               locale.t(:less_than_x_minutes, :count => 1) :
               locale.t(:x_minutes, :count => distance_in_minutes) unless include_seconds
        case distance_in_seconds
          when 0..4   then locale.t :less_than_x_seconds, :count => 5
          when 5..9   then locale.t :less_than_x_seconds, :count => 10
          when 10..19 then locale.t :less_than_x_seconds, :count => 20
          when 20..39 then locale.t :half_a_minute
          when 40..59 then locale.t :less_than_x_minutes, :count => 1
          else             locale.t :x_minutes,           :count => 1
        end
      when 2..44           then locale.t :x_minutes,      :count => distance_in_minutes
      when 45..89          then locale.t :about_x_hours,  :count => 1
      when 90..1439        then locale.t :about_x_hours,  :count => (distance_in_minutes.to_f / 60.0).round
      when 1440..2529      then locale.t :x_days,         :count => 1
      when 2530..43199     then locale.t :x_days,         :count => (distance_in_minutes.to_f / 1440.0).round
      when 43200..86399    then locale.t :about_x_months, :count => 1
      when 86400..525599   then locale.t :x_months,       :count => (distance_in_minutes.to_f / 43200.0).round
      else
        distance_in_years           = distance_in_minutes / 525600
        minute_offset_for_leap_year = (distance_in_years / 4) * 1440
        remainder                   = ((distance_in_minutes - minute_offset_for_leap_year) % 525600)
        if remainder < 131400
          locale.t(:about_x_years,  :count => distance_in_years)
        elsif remainder < 394200
          locale.t(:over_x_years,   :count => distance_in_years)
        else
          locale.t(:almost_x_years, :count => distance_in_years + 1)
        end
    end
  end
end

def escape_html(text)


Returns escaped text to protect against malicious content
#
def escape_html(text)
  Rack::Utils.escape_html(text)
end

def escape_javascript(html_content)


Remove unsafe chars from our javascript
#
def escape_javascript(html_content)
  return '' unless html_content
  javascript_mapping = { '\\' => '\\\\', '</' => '<\/', "\r\n" => '\n', "\n" => '\n' }
  javascript_mapping.merge("\r" => '\n', '"' => '\\"', "'" => "\\'")
  escaped_string = html_content.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { javascript_mapping[$1] }
  escaped_string
end

def h!(text, blank_text = '&nbsp;')


Returns blank if the text is empty
Returns escaped text to protect against malicious content
#
def h!(text, blank_text = '&nbsp;')
  return blank_text if text.nil? || text.empty?
  h text
end

def js_escape_html(html_content)


js_escape_html("

Hey

")

Used in xxxx.js.erb files to escape html so that it can be passed to javascript from Padrino
#
def js_escape_html(html_content)
  "\"#{escape_javascript(html_content)}\""
end

def pluralize(count, singular, plural = nil)


pluralize(2, 'person') => '2 people'

==== Examples

otherwise it will use the Inflector to determine the plural form
Attempts to pluralize the singular word unless count is 1. If plural is supplied, it will use that when count is > 1,
#
def pluralize(count, singular, plural = nil)
  "#{count || 0} " + ((count == 1 || count == '1') ? singular : (plural || singular.pluralize))
end

def simple_format(text, html_options={})


simple_format("hello\nworld") # => "

hello
world

"

==== Examples

This method does not remove the newlines from the text.
as a paragraph and wrapped in

tags. One newline (\n) is considered as a linebreak and a
tag is appended.
Returns text transformed into HTML using simple formatting rules. Two or more consecutive newlines(\n\n) are considered
#

def simple_format(text, html_options={})
  start_tag = tag('p', html_options.merge(:open => true))
  text = text.to_s.dup
  text.gsub!(/\r\n?/, "\n")                    # \r\n and \r -> \n
  text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}")  # 2+ newline  -> paragraph
  text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline   -> br
  text.insert 0, start_tag
  text << "</p>"
end

def time_ago_in_words(from_time, include_seconds = false)


from_time = Time.now - 3.days - 14.minutes - 25.seconds # => 3 days

time_ago_in_words(Time.now) # => less than a minute
time_ago_in_words(Time.now - 15.hours) # => 15 hours
time_ago_in_words(3.minutes.from_now) # => 3 minutes

==== Examples

Like distance_of_time_in_words, but where to_time is fixed to Time.now.
#
def time_ago_in_words(from_time, include_seconds = false)
  distance_of_time_in_words(from_time, Time.now, include_seconds)
end

def truncate(text, *args)


truncate("Once upon a time in a world far far away", :length => 8) => "Once upon..."

==== Examples

The last characters will be replaced with the :omission (defaults to "…") for a total length not exceeding :length.
Truncates a given text after a given :length if text is longer than :length (defaults to 30).
#
def truncate(text, *args)
  options = args.extract_options!
  options.reverse_merge!(:length => 30, :omission => "...")
  if text
    len = options[:length] - options[:omission].length
    chars = text
    (chars.length > options[:length] ? chars[0...len] + options[:omission] : text).to_s
  end
end

def word_wrap(text, *args)


word_wrap('Once upon a time', :line_width => 8) => "Once upon\na time"

==== Examples

This method breaks on the first whitespace character that does not exceed line_width (which is 80 by default).
Wraps the text into lines no longer than line_width width.
#
def word_wrap(text, *args)
  options = args.extract_options!
  unless args.blank?
    options[:line_width] = args[0] || 80
  end
  options.reverse_merge!(:line_width => 80)
  text.split("\n").collect do |line|
    line.length > options[:line_width] ? line.gsub(/(.{1,#{options[:line_width]}})(\s+|$)/, "\\1\n").strip : line
  end * "\n"
end