ago.rb 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. module Ago
  2. module VERSION
  3. MAJOR = 0
  4. MINOR = 1
  5. TINY = 5
  6. class << self
  7. def pretty
  8. "#{MAJOR}.#{MINOR}.#{TINY}"
  9. end
  10. alias_method :print, :pretty
  11. end
  12. end
  13. Ago::Order = [:year, :month, :week, :day, :hour, :minute, :second]
  14. Ago::Units = {
  15. :year => {
  16. :basic => 60 * 60 * 24 * 365,
  17. :gregorian => 86400 * 365.2425,
  18. },
  19. :month => {
  20. :basic => 60 * 60 * 24 * 30,
  21. :gregorian => 86400 * 30.436875,
  22. },
  23. :week => {
  24. :basic => 60 * 60 * 24 * 7,
  25. :gregorian => 86400 * 7.02389423076923,
  26. },
  27. :day => {
  28. :basic => 60 * 60 * 24
  29. },
  30. :hour => {
  31. :basic => 60 * 60
  32. },
  33. :minute => {
  34. :basic => 60
  35. },
  36. :second => {
  37. :basic => 1
  38. }
  39. }
  40. def Ago.calendar_check(calendar)
  41. error = ":calendar => value must be either :basic or :gregorian."
  42. unless calendar == :basic || calendar == :gregorian
  43. raise ArgumentError, error
  44. end
  45. end
  46. module Ago::TimeAgo
  47. # Generate List of valid unit :symbols
  48. valids = ""
  49. Ago::Order.each do |u|
  50. unless u == :second
  51. valids += ":#{u.to_s}, "
  52. else
  53. valids += "and :#{u.to_s}."
  54. end
  55. end
  56. Valids = valids
  57. def ago_in_words(opts={})
  58. # Process options {hash}
  59. focus = opts[:focus] ? opts[:focus] : 0
  60. start_at = opts[:start_at] ? opts[:start_at] : :year
  61. now = opts[:now] ? opts[:now] : Time.now
  62. in_time = opts[:in_time] ? opts[:in_time] : :past
  63. calendar = opts[:calendar] ? opts[:calendar] : :basic
  64. # Filter out invalid arguments for :in_time
  65. in_time_error = ":in_time => value must be either :past or :future, " \
  66. + "depending on whether the Time object is before or after Time.now."
  67. unless in_time == :past || in_time == :future
  68. raise ArgumentError, in_time_error
  69. end
  70. # Filter out invalid arguments for :calendar
  71. Ago.calendar_check(calendar)
  72. # Filter out invalid arguments for :start_at and :focus
  73. base_error = " => value must either be a number " +
  74. "between 0 and 6 (inclusive),\nor one of the following " +
  75. "symbols: " + Valids
  76. {:focus => focus, :start_at => start_at}.each do |key, opt|
  77. opt_error = ":" + key.to_s + base_error
  78. if opt.class == Integer
  79. raise ArgumentError, opt_error unless opt >= 0 && opt <= 6
  80. elsif opt.class == Symbol
  81. raise ArgumentError, opt_error unless Ago::Units[opt]
  82. else
  83. raise ArgumentError, opt_error
  84. end
  85. end
  86. # Create Variables necessary for processing.
  87. frags = []
  88. output = ""
  89. count = 0
  90. now = calendar == :basic ? now.to_i : now.to_f
  91. my_time = calendar == :basic ? self.to_i : self.to_f
  92. if now > my_time
  93. diff = now - my_time
  94. tail = " ago"
  95. elsif my_time > now
  96. diff = my_time - now
  97. tail = " from now"
  98. else
  99. diff = 0
  100. tail = "just now"
  101. end
  102. # Begin Ago.ago processing
  103. Ago::Order.each do |u|
  104. if calendar == :gregorian && Ago::Units[u][:gregorian]
  105. value = Ago::Units[u][:gregorian]
  106. else
  107. value = Ago::Units[u][:basic]
  108. end
  109. count += 1
  110. # Move further ahead in the Ago::Units array if start_at is farther back than
  111. # the current point in the array.
  112. if start_at.class == Integer
  113. next if count <= start_at
  114. elsif start_at.class == Symbol
  115. next if Ago::Order.index(u) < Ago::Order.index(start_at)
  116. end
  117. n = (diff/value).floor
  118. if n > 0
  119. plural = n > 1 ? "s" : ""
  120. frags << "#{n} #{u.to_s + plural}"
  121. # If the argument passed into ago() is a symbol, focus the ago statement
  122. # down to the level specified in the symbol
  123. if focus.class == Symbol
  124. break if u == focus || u == :second
  125. elsif focus.class == Integer
  126. if focus == 0 || u == :second
  127. break
  128. else
  129. focus -= 1
  130. end
  131. end
  132. diff -= n * value
  133. end
  134. end
  135. # Der Kommissar
  136. frags.size.times do |n|
  137. output += frags[n]
  138. output += ", " unless n == frags.size - 1
  139. end
  140. return output + "#{tail}"
  141. end
  142. def from_now_in_words(opts={})
  143. ago_in_words(opts)
  144. end
  145. end
  146. end
  147. class Time
  148. include Ago::TimeAgo
  149. end