Class: TimeCalc::Value
- Inherits:
-
Object
- Object
- TimeCalc::Value
- Includes:
- Comparable
- Defined in:
- lib/time_calc/value.rb
Overview
Wrapper (one can say “monad”) around date/time value, allowing to perform several TimeCalc operations in a chain.
Constant Summary collapse
- TIMEY =
proc { |t| t.respond_to?(:to_time) }
- CLASS_NAME =
Because AS::TimeWithZone so frigging smart that it returns “Time” from redefined class name.
Class.instance_method(:name)
Instance Attribute Summary collapse
- #internal ⇒ Object readonly
Class Method Summary collapse
Instance Method Summary collapse
-
#+(span, unit) ⇒ Value
Add ‘<span units>` to wrapped value.
-
#-(span_or_other, unit = nil) ⇒ Object
Subtracts ‘span units` from wrapped value.
- #<=>(other) ⇒ 1, ...
-
#ceil(unit) ⇒ Value
Ceils (rounds up) underlying date/time to nearest ‘unit`.
- #convert(klass) ⇒ Object
- #dst? ⇒ Boolean
-
#for(span, unit) ⇒ Sequence
Produces Sequence from this value to ‘this + <span units>`.
-
#initialize(time_or_date) ⇒ Value
constructor
A new instance of Value.
- #inspect ⇒ Object
-
#iterate(span, unit) {|Time/Date/DateTime| ... } ⇒ Value
Like #+, but allows conditional skipping of some periods.
-
#merge(**attrs) ⇒ Value
Produces new value with some components of underlying time/date replaced.
-
#round(unit) ⇒ Object
Rounds up or down underlying date/time to nearest ‘unit`.
-
#step(span, unit = nil) ⇒ Sequence
Produces endless Sequence from this value, with step specified.
-
#to(date_or_time) ⇒ Sequence
Produces Sequence from this value to ‘date_or_time`.
-
#truncate(unit) ⇒ Object
(also: #floor)
Truncates all time components lower than ‘unit`.
-
#unwrap ⇒ Time, ...
The value of the original type that was wrapped and processed.
Constructor Details
#initialize(time_or_date) ⇒ Value
Prefer TimeCalc.wrap to create a Value.
Returns a new instance of Value.
50 51 52 |
# File 'lib/time_calc/value.rb', line 50 def initialize(time_or_date) @internal = time_or_date end |
Instance Attribute Details
#internal ⇒ Object (readonly)
45 46 47 |
# File 'lib/time_calc/value.rb', line 45 def internal @internal end |
Class Method Details
.wrap(value) ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/time_calc/value.rb', line 28 def self.wrap(value) case value when Time, Date, DateTime # NB: ActiveSupport::TimeWithZone will also pass to this branch if # active_support/core_ext/time is required. But it is doubtfully it is not -- TWZ will be # mostly unusable :) new(value) when Value value when TIMEY wrap(value.to_time) else fail ArgumentError, "Unsupported value: #{value}" end end |
Instance Method Details
#+(span, unit) ⇒ Value
Add ‘<span units>` to wrapped value.
147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/time_calc/value.rb', line 147 def +(span, unit) unit = Units.(unit) case unit when :sec, :min, :hour, :day plus_seconds(span, unit) when :week self.+(span * 7, :day) when :month plus_months(span) when :year merge(year: year + span) end end |
#-(span, unit) ⇒ Value #-(date_or_time) ⇒ Diff
Subtracts ‘span units` from wrapped value.
171 172 173 |
# File 'lib/time_calc/value.rb', line 171 def -(span_or_other, unit = nil) unit.nil? ? Diff.new(self, span_or_other) : self.+(-span_or_other, unit) end |
#<=>(other) ⇒ 1, ...
65 66 67 68 69 |
# File 'lib/time_calc/value.rb', line 65 def <=>(other) return unless other.is_a?(self.class) Types.compare(internal, other.internal) end |
#ceil(unit) ⇒ Value
Ceils (rounds up) underlying date/time to nearest ‘unit`.
124 125 126 |
# File 'lib/time_calc/value.rb', line 124 def ceil(unit) floor(unit).then { |res| res == self ? res : res.+(1, unit) } end |
#convert(klass) ⇒ Object
229 230 231 232 233 |
# File 'lib/time_calc/value.rb', line 229 def convert(klass) return dup if internal.class == klass Value.new(Types.convert(internal, klass)) end |
#dst? ⇒ Boolean
75 76 77 78 79 |
# File 'lib/time_calc/value.rb', line 75 def dst? return unless internal.respond_to?(:dst?) internal.dst? end |
#for(span, unit) ⇒ Sequence
Produces Sequence from this value to ‘this + <span units>`
224 225 226 |
# File 'lib/time_calc/value.rb', line 224 def for(span, unit) to(self.+(span, unit)) end |
#inspect ⇒ Object
60 61 62 |
# File 'lib/time_calc/value.rb', line 60 def inspect '#<%s(%s)>' % [self.class, internal] end |
#iterate(span, unit) {|Time/Date/DateTime| ... } ⇒ Value
Like #+, but allows conditional skipping of some periods. Increases value by ‘unit` at least `span` times, on each iteration checking with block provided if this point matches desired period; if it is not, it is skipped without increasing iterations counter. Useful for “business date/time” algorithms.
See TimeCalc#iterate for examples.
188 189 190 191 192 193 194 195 |
# File 'lib/time_calc/value.rb', line 188 def iterate(span, unit) block_given? or fail ArgumentError, 'No block given' Integer === span or fail ArgumentError, 'Only integer spans are supported' # rubocop:disable Style/CaseEquality Enumerator.produce(self) { |v| v.+((span <=> 0).nonzero? || 1, unit) } .lazy.select { |v| yield(v.internal) } .drop(span.abs).first end |
#merge(**attrs) ⇒ Value
Produces new value with some components of underlying time/date replaced.
89 90 91 92 |
# File 'lib/time_calc/value.rb', line 89 def merge(**attrs) class_name = CLASS_NAME.bind(internal.class).call.tr(':', '_') Value.new(Types.public_send("merge_#{class_name.downcase}", internal, **attrs)) end |
#round(unit) ⇒ Object
Rounds up or down underlying date/time to nearest ‘unit`.
136 137 138 139 140 |
# File 'lib/time_calc/value.rb', line 136 def round(unit) f, c = floor(unit), ceil(unit) (internal - f.internal).abs < (internal - c.internal).abs ? f : c end |
#step(unit) ⇒ Sequence #step(span, unit) ⇒ Sequence
Produces endless Sequence from this value, with step specified.
214 215 216 217 |
# File 'lib/time_calc/value.rb', line 214 def step(span, unit = nil) span, unit = 1, span if unit.nil? Sequence.new(from: self).step(span, unit) end |
#to(date_or_time) ⇒ Sequence
Produces Sequence from this value to ‘date_or_time`
201 202 203 |
# File 'lib/time_calc/value.rb', line 201 def to(date_or_time) Sequence.new(from: self).to(date_or_time) end |
#truncate(unit) ⇒ Object Also known as: floor
Truncates all time components lower than ‘unit`. In other words, “floors” (rounds down) underlying date/time to nearest `unit`.
103 104 105 106 107 108 109 110 111 112 |
# File 'lib/time_calc/value.rb', line 103 def truncate(unit) unit = Units.(unit) return floor_week if unit == :week Units::STRUCTURAL .drop_while { |u| u != unit } .drop(1) .then { |keys| Units::DEFAULTS.slice(*keys) } .then { |attrs| merge(**attrs) } # can't simplify to &method(:merge) due to 2.7 keyword param problem end |
#unwrap ⇒ Time, ...
Returns The value of the original type that was wrapped and processed.
55 56 57 |
# File 'lib/time_calc/value.rb', line 55 def unwrap @internal end |