Class: Spanner
- Inherits:
-
Object
- Object
- Spanner
- Defined in:
- lib/spanner.rb
Constant Summary collapse
- ParseError =
Class.new(RuntimeError)
Instance Attribute Summary collapse
-
#from ⇒ Object
readonly
Returns the value of attribute from.
-
#raise_on_error ⇒ Object
readonly
Returns the value of attribute raise_on_error.
-
#value ⇒ Object
readonly
Returns the value of attribute value.
Class Method Summary collapse
- .days_in_month(year, month) ⇒ Object
- .format(distance, opts = nil) ⇒ Object
- .parse(str, opts = nil) ⇒ Object
Instance Method Summary collapse
- #error(err) ⇒ Object
- #format(distance) ⇒ Object
-
#initialize(opts) ⇒ Spanner
constructor
A new instance of Spanner.
- #length_of_month ⇒ Object
- #parse(value) ⇒ Object
Constructor Details
#initialize(opts) ⇒ Spanner
Returns a new instance of Spanner.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/spanner.rb', line 18 def initialize(opts) @value = value @on_error = opts && opts.key?(:on_error) ? opts[:on_error] : :raise @length_of_month = opts && opts[:length_of_month] @biggest_unit = ((opts && opts[:biggest_unit]) || "years").to_s.downcase.to_sym @from = if opts && opts.key?(:from) case opts[:from] when :now Time.new.to_i else opts[:from].to_i end else 0 end end |
Instance Attribute Details
#from ⇒ Object (readonly)
Returns the value of attribute from.
16 17 18 |
# File 'lib/spanner.rb', line 16 def from @from end |
#raise_on_error ⇒ Object (readonly)
Returns the value of attribute raise_on_error.
16 17 18 |
# File 'lib/spanner.rb', line 16 def raise_on_error @raise_on_error end |
#value ⇒ Object (readonly)
Returns the value of attribute value.
16 17 18 |
# File 'lib/spanner.rb', line 16 def value @value end |
Class Method Details
.days_in_month(year, month) ⇒ Object
36 37 38 |
# File 'lib/spanner.rb', line 36 def self.days_in_month(year, month) (Date.new(year, 12, 31) << (12-month)).day end |
Instance Method Details
#error(err) ⇒ Object
44 45 46 47 48 |
# File 'lib/spanner.rb', line 44 def error(err) if on_error == :raise raise ParseError.new(err) end end |
#format(distance) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/spanner.rb', line 99 def format(distance) distance = distance.to_i units = [:years, :months, :weeks, :days, :hours, :minutes] biggest_unit = units.index(@biggest_unit) || 0 parts = {} parts[:years], distance = distance.divmod(31_556_926) unless biggest_unit > units.index(:years) parts[:months], distance = distance.divmod(length_of_month) unless biggest_unit > units.index(:months) parts[:weeks], distance = distance.divmod(604_800) unless biggest_unit > units.index(:weeks) parts[:days], distance = distance.divmod(86_400) unless biggest_unit > units.index(:days) parts[:hours], distance = distance.divmod(3600) unless biggest_unit > units.index(:hours) parts[:minutes], parts[:seconds] = distance.divmod(60) unless biggest_unit > units.index(:minutes) output = [] parts.each do |name, value| next if value == 0 name = name.to_s.singularize if value.between?(-1, 1) output << "%d %s" % [value, name] end output.join(" ") end |
#length_of_month ⇒ Object
40 41 42 |
# File 'lib/spanner.rb', line 40 def length_of_month @length_of_month ||= Spanner.parse("#{Spanner.days_in_month(Time.new.year, Time.new.month)} days") end |
#parse(value) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/spanner.rb', line 50 def parse(value) parts = [] part_contextualized = nil value.to_s.scan(/[\+\-]?(?:\d*\.\d+|\d+)|[a-z]+/i).each do |part| part_as_float = Float(part) rescue nil if part_as_float parts << part_as_float part_contextualized = nil else if part_contextualized error "Part has already been contextualized with #{part_contextualized}" return nil end if parts.empty? parts << 1 end # part is context multiplier = case part when 's', 'sec', 'second', 'seconds' then 1 when 'h', 'hour', 'hours', 'hrs' then 3600 when 'm', 'min', 'minute', 'minutes' then 60 when 'd', 'day', 'days' then 86_400 when 'w', 'wks', 'week', 'weeks' then 604_800 when 'months', 'month', 'M' then length_of_month when 'years', 'year', 'y' then 31_556_926 when /\As/ then 1 when /\Am/ then 60 when /\Ah/ then 3600 when /\Ad/ then 86_400 when /\Aw/ then 604_800 when /\AM/ then length_of_month when /\Ay/ then 31_556_926 end part_contextualized = part parts << (parts.pop * multiplier) if multiplier end end if parts.empty? nil else value = parts.inject(from) {|s, p| s += p} value.ceil == value ? value.ceil : value end end |