timerizer 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e03bc2d5660e629ad3545c610bf09efa55fbe07cec5c364970eabb8001add9fd
4
- data.tar.gz: 050b2b058e5c63eda87f973e5adde7c84e34c9c230833c47f84eb7189ef0d774
3
+ metadata.gz: 02461e09b8beea13b38f2e36aab85ab643fe7975b2f96132aa7bdbe8930ed370
4
+ data.tar.gz: 9fe1a1573e379256bedf1628ea469ec65c0e68f3a8da842ed77d995b0b70f753
5
5
  SHA512:
6
- metadata.gz: bcc860c64450e0e1f099dca114205f727410a216846c25a61ce75b5052783e95a7b748df72227b9b1b108d44ca0eb11f4dbb81ac7ddcf715629f3a4d9e3135a1
7
- data.tar.gz: a9836b0cb9c429a8ed66fad757cea99f022934af83e7b5757f8bd84fdf805fe102624d6e14b41d6e9711cbb10dbb53fbd315798b86633de18edfb1e560d2b6ed
6
+ metadata.gz: 1135496242298cd85e09d05d945b156cd592f76f9645a4b4bd3693e8cda1f3b190e8a27130a64337077ae62ab4b47f3205e8fbdeb6178034e358bb7f682dcbc6
7
+ data.tar.gz: baa46d6fe2ad8cec7bd48199081624dd31f2499235c04f319c0bd27b58417dfbc649f1e41cf207b2156985f56ca6a76148926cbc09ea083e2023dd3963bc2354
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+ require 'forwardable'
3
+
4
+ module Timerizer
5
+ class Duration
6
+ # Wraps rounding a {Timerizer::Duration} to the nearest value by the number
7
+ # of "places", which are customary time units (seconds, minutes, hours,
8
+ # days, months, years, etc; decades and weeks are not included).
9
+ #
10
+ # @private
11
+ class RoundedTime
12
+ extend Forwardable
13
+
14
+ # @!method remainder_times
15
+ # @return (see TermTimes#remainder_times)
16
+ # @!method target_unit
17
+ # @return (see TermTimes#target_unit)
18
+ # @!method times
19
+ # @return (see TermTimes#times)
20
+ def_delegators :@tt, :remainder_times, :target_unit, :times
21
+
22
+ # Default "places" (units, e.g., hours/minutes) to use for rounding.
23
+ DEFAULT_PLACES = 2
24
+ # Default {Timerizer::Duration::UNITS} *not* to include in rounded value.
25
+ OMITTED_KEYS = [:decades, :weeks]
26
+
27
+ # Given an original {Timerizer::Duration} instance, return a new instance
28
+ # that "rounds" the duration to the closest value expressed in a certain
29
+ # number of units (default 2).
30
+ #
31
+ # @param [{Timerizer::Duration}] duration Object encapsulating a duration
32
+ # (in hours, minutes, etc) to "round" to a number of
33
+ # units specified by `places`.
34
+ # @param [Integer] places Number of units to include in rounded value.
35
+ # Default is 2.
36
+ # @param [Array<Symbol>] omitted_keys Units to omit from calculation or
37
+ # return value. Default is `[:decades, :weeks]`
38
+ # @return {Timerizer::Duration}
39
+ # @example
40
+ # t = (12.hours 16.minutes 47.seconds).ago
41
+ # d = Time.since(t)
42
+ # d2 = RoundedTime.call(d)
43
+ # d.to_s # => "12 hours, 16 minutes, 47 seconds"
44
+ # d2.to_s # => "12 hours, 17 minutes"
45
+ #
46
+ def self.call(duration, places = DEFAULT_PLACES,
47
+ omitted_keys = OMITTED_KEYS)
48
+ new(duration, places, omitted_keys).call
49
+ end
50
+
51
+ # High-level method to do calculations on component durations.
52
+ #
53
+ # @return {Timerizer::Duration}
54
+ #
55
+ def call
56
+ remainder = sum_of(remainder_times)
57
+ sum_of(times) + offset_from(remainder)
58
+ end
59
+
60
+ private
61
+
62
+ # Initial value for adding a collection of Duration instances.
63
+ # (see #sum_of)
64
+ ZERO_TIME = Timerizer::Duration.new(seconds: 0)
65
+ private_constant :ZERO_TIME
66
+
67
+ # Private initialiser to prevent direct instantiation by client code.
68
+ #
69
+ # @param [{Timerizer::Duration}] duration Object encapsulating a duration
70
+ # (in hours, minutes, etc) to "round" to a number of
71
+ # units specified by `places`.
72
+ # @param [Integer] places Number of units to include in rounded value.
73
+ # Default is 2.
74
+ # @param [Array<Symbol>] omitted_keys Units to omit from calculation or
75
+ # return value. Default is `[:decades, :weeks]`
76
+ #
77
+ def initialize(duration, places = DEFAULT_PLACES,
78
+ omitted_keys = OMITTED_KEYS)
79
+ @tt = TermTimes.new(duration, omitted_keys).call(places).freeze
80
+ end
81
+
82
+ # Determine whether returned {Timerizer::Duration} value should be rounded
83
+ # up or down based on a remainder value.
84
+ #
85
+ # If the remainder value is more than half of the {#target_unit}, then
86
+ # this will return a duration of 1 times the target unit, else a duration
87
+ # of {ZERO_TIME}.
88
+ #
89
+ # @return [{Timerizer::Duration}] Either zero or 1 times the `target_unit`
90
+ # @param [{Timerizer::Duration}] remainder Value of input duration less
91
+ # than one `target_unit`
92
+ def offset_from(remainder)
93
+ Timerizer::Duration.new((remainder * 2).to_units(target_unit))
94
+ end
95
+
96
+ # Add all time (Duration) values in an Array (or other Enumerable).
97
+ #
98
+ # @return [{Timerizer::Duration}] Sum total of input values.
99
+ # @param [Array<{Timerizer::Duration}>] Unit values to add together
100
+ #
101
+ def sum_of(time_values)
102
+ time_values.inject(ZERO_TIME, :+)
103
+ end
104
+
105
+ # Convert a single {Timerizer::Duration} instance into an enumeration of
106
+ # per-unit Duration instances (hours, minutes, etc).
107
+ #
108
+ # @private
109
+ class TermTimes
110
+ # Least-significant time unit (e.g., ``:days`) used for rounding.
111
+ # @return [Symbol] Least-significant time unit in the resulting value.
112
+ attr_reader :target_unit
113
+ # Time units to be included in "rounded" result, before rounding.
114
+ # @return [Array<{Timerizer::Duration}>] Base result time-unit values.
115
+ attr_reader :times
116
+ # Time units to be "rounded" to adjust resulting Duration value.
117
+ # @return [Array<{Timerizer::Duration}>] Remaining time-unit values.
118
+ attr_reader :remainder_times
119
+
120
+ # Build array of time-part values based on input {Timerizer::Duration}.
121
+ #
122
+ # @param [{Timerizer::Duration}] duration Time differential used as
123
+ # input.
124
+ # @param [Array<Symbol>] omitted_keys {Timerizer::Duration::UNITS}
125
+ # values to exclude from resulting value.
126
+ #
127
+ def initialize(duration, omitted_keys)
128
+ @part_values = filter_units(duration, omitted_keys)
129
+ end
130
+
131
+ # Compute per-unit {Timerizer::Duration} values, split based on unit
132
+ # count
133
+ #
134
+ # @param [Integer] places Number of time units to include in main Array.
135
+ def call(places)
136
+ # Note that `places` may exceed the number of actual units in the
137
+ # value. For example, with a duration of `(10.days)` and a `places`
138
+ # value of 2. Adjust as needed.
139
+ places = @part_values.count - 1 if @part_values.count < places
140
+ # If a zero-time `duration` is passed in, then @part_values will be
141
+ # empty, and the key arithmetic will return `nil`. Adjust as needed.
142
+ @target_unit = @part_values.keys[places - 1] || :seconds
143
+ term_times = unit_times
144
+ @times = term_times[0..places - 1]
145
+ @remainder_times = term_times[@times.count..-1]
146
+ self
147
+ end
148
+
149
+ private
150
+
151
+ def filter_units(duration, omitted_keys)
152
+ unit_keys = Timerizer::Duration::UNITS.keys - omitted_keys
153
+ duration.to_units(*unit_keys).reject { |_, v| v.zero? }
154
+ end
155
+
156
+ def unit_times
157
+ @part_values.map { |unit, val| Timerizer::Duration.new(unit => val) }
158
+ end
159
+ end # class RoundedTime::TermTimes
160
+ private_constant :TermTimes
161
+ end # class RoundedTime
162
+ end
163
+ end
@@ -1,3 +1,3 @@
1
1
  module Timerizer
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timerizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyle Lacy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-27 00:00:00.000000000 Z
11
+ date: 2018-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -76,6 +76,7 @@ files:
76
76
  - lib/timerizer.rb
77
77
  - lib/timerizer/core.rb
78
78
  - lib/timerizer/duration.rb
79
+ - lib/timerizer/duration/rounded_time.rb
79
80
  - lib/timerizer/version.rb
80
81
  - lib/timerizer/wall_clock.rb
81
82
  homepage: http://github.com/kylewlacy/timerizer