time_math2 0.0.8 → 0.1.0

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
  SHA1:
3
- metadata.gz: 35d2a3523dac20994a38d19862500ce1eae98854
4
- data.tar.gz: 82b7664f95fb1879a4911886cd257c41282f9327
3
+ metadata.gz: f2e42b79bda1365a78f8c74b1b2d41af59f4c5c0
4
+ data.tar.gz: b2dcd6572c88be32bfbff1f9a3f15cda929551b9
5
5
  SHA512:
6
- metadata.gz: 99dc9701481d961e93e9d803e4b943ce390bd03e55e8b23a779456094051d1fce129c5bb2a3900cf7f1d8c64f20be684839e2f1f80234c6a6c79912e78eb7954
7
- data.tar.gz: 22dcc1315f78bd1d323ae9faed9b5e8ef6b39267ddd65b7c3be40cfe33b4f4ec217c79eecfc89c49c14b37ce60c92497ac49d5b5fa7b5d69a6afbd947687da8b
6
+ metadata.gz: 987ddc51e856db1f2f9baa77d68beb189b7a2f6193a82d5839cf11b3e4b9f989d8fe676d4539087a60bbda75e4779f90a7c8d0b706a5d2cef1c85123c8fd9f6b
7
+ data.tar.gz: 0d5a36c6e120c1244ae40a768b13f499455e855890a46013674464e9d6939b7797ef14aed268a05491e29e98be4249467bb112d5b29381611606be7346f4632e
@@ -1,5 +1,10 @@
1
1
  # TimeMath Changelog
2
2
 
3
+ # 0.1.0 (2017-07-30)
4
+
5
+ * Update sequences logic to be, well... More logical (Thanks @kenn again for meaningful discussion!);
6
+ * Various code cleanups.
7
+
3
8
  # 0.0.8 (2017-06-02)
4
9
 
5
10
  * Fix `Units::Base#measure` to correctly measure negative distances (e.g. from > to, thanks @kenn for
@@ -2,14 +2,13 @@ module TimeMath
2
2
  # @private
3
3
  class Resampler
4
4
  class << self
5
- def call(name, array_or_hash, symbol = nil, &block)
6
- if array_or_hash.is_a?(Array) && array_or_hash.all?(&Util.method(:timey?))
7
- ArrayResampler.new(name, array_or_hash).call
8
- elsif array_or_hash.is_a?(Hash) && array_or_hash.keys.all?(&Util.method(:timey?))
9
- HashResampler.new(name, array_or_hash).call(symbol, &block)
10
- else
11
- raise ArgumentError, "Array of timestamps or hash with timestamp keys, #{array_or_hash} got"
12
- end
5
+ def call(unit, array_or_hash, symbol = nil, &block)
6
+ resampler =
7
+ ArrayResampler.try(unit, array_or_hash) ||
8
+ HashResampler.try(unit, array_or_hash) or
9
+ raise ArgumentError, "Expected array of timestamps or hash with timestamp keys, #{array_or_hash} got"
10
+
11
+ resampler.call(symbol, &block)
13
12
  end
14
13
  end
15
14
 
@@ -17,29 +16,30 @@ module TimeMath
17
16
  @unit = Units.get(unit)
18
17
  end
19
18
 
20
- private
21
-
22
- def sequence
23
- @sequence ||= @unit.sequence(from...to, expand: true)
19
+ def call
20
+ raise NotImplementedError
24
21
  end
25
22
 
26
- def from
27
- timestamps.min
28
- end
23
+ private
29
24
 
30
- def to
31
- @unit.next(timestamps.max)
25
+ def sequence
26
+ @sequence ||= @unit.sequence(timestamps.min..timestamps.max)
32
27
  end
33
28
  end
34
29
 
35
30
  # @private
36
31
  class ArrayResampler < Resampler
32
+ def self.try(unit, array)
33
+ return nil unless array.is_a?(Array) && array.all?(&Util.method(:timey?))
34
+ new(unit, array)
35
+ end
36
+
37
37
  def initialize(unit, array)
38
38
  super(unit)
39
39
  @array = array
40
40
  end
41
41
 
42
- def call
42
+ def call(*)
43
43
  sequence.to_a
44
44
  end
45
45
 
@@ -52,6 +52,11 @@ module TimeMath
52
52
 
53
53
  # @private
54
54
  class HashResampler < Resampler
55
+ def self.try(unit, hash)
56
+ return nil unless hash.is_a?(Hash) && hash.keys.all?(&Util.method(:timey?))
57
+ new(unit, hash)
58
+ end
59
+
55
60
  def initialize(unit, hash)
56
61
  super(unit)
57
62
  @hash = hash
@@ -9,63 +9,49 @@ module TimeMath
9
9
  # from = Time.parse('2016-05-01 13:30')
10
10
  # to = Time.parse('2016-05-04 18:20')
11
11
  # seq = TimeMath.day.sequence(from...to)
12
- # # => #<TimeMath::Sequence(2016-05-01 13:30:00 +0300...2016-05-04 18:20:00 +0300)>
12
+ # # => #<TimeMath::Sequence day (2016-05-01 00:00:00 +0300-2016 - 2016-05-04 00:00:00 +0300)>
13
13
  # ```
14
14
  #
15
15
  # Now, you can use it:
16
16
  #
17
17
  # ```ruby
18
18
  # seq.to_a
19
- # # => [2016-05-01 13:30:00 +0300, 2016-05-02 13:30:00 +0300, 2016-05-03 13:30:00 +0300, 2016-05-04 13:30:00 +0300]
19
+ # # => [2016-05-01 00:00:00 +0300, 2016-05-02 00:00:00 +0300, 2016-05-03 00:00:00 +0300]
20
20
  # ```
21
- # -- it's an "each day start between from and to". As you can see,
22
- # the period start is the same as in `from`.
21
+ # -- it's an "each day start between from and to".
23
22
  #
24
- # You can expand from and to to nearest round unit by {#expand} method
25
- # or `:expand` option:
23
+ # Depending of including/excluding of range, you will, or will not receive period that includes `to`:
26
24
  #
27
25
  # ```ruby
28
- # seq.expand.to_a
26
+ # TimeMath.day.sequence(from..to).to_a
29
27
  # # => [2016-05-01 00:00:00 +0300, 2016-05-02 00:00:00 +0300, 2016-05-03 00:00:00 +0300, 2016-05-04 00:00:00 +0300]
30
- # # or:
31
- # seq = TimeMath.day.sequence(from...to, expand: true)
32
- # # => #<TimeMath::Sequence(2016-05-01 00:00:00 +0300...2016-05-05 00:00:00 +0300)>
33
- # seq.to_a
34
- # # => [2016-05-01 00:00:00 +0300, 2016-05-02 00:00:00 +0300, 2016-05-03 00:00:00 +0300, 2016-05-04 00:00:00 +0300]
35
- # # ^ note that `to` is excluded.
36
- # # You can include it by creating sequence from including-end range:
37
- # seq = TimeMath.day.sequence(from..to, expand: true)
38
- # # => #<TimeMath::Sequence(:day, 2016-05-01 00:00:00 +0300..2016-05-05 00:00:00 +0300)>
39
- # seq.to_a
40
- # # => [2016-05-01 00:00:00 +0300, 2016-05-02 00:00:00 +0300, 2016-05-03 00:00:00 +0300, 2016-05-04 00:00:00 +0300, 2016-05-05 00:00:00 +0300]
41
28
  # ```
42
29
  #
43
30
  # Besides each period beginning, you can also request pairs of begin/end
44
31
  # of a period, either as an array of arrays, or array of ranges:
45
32
  #
46
33
  # ```ruby
47
- # seq = TimeMath.day.sequence(from...to)
48
34
  # seq.pairs
49
- # # => [[2016-05-01 13:30:00 +0300, 2016-05-02 13:30:00 +0300], [2016-05-02 13:30:00 +0300, 2016-05-03 13:30:00 +0300], [2016-05-03 13:30:00 +0300, 2016-05-04 13:30:00 +0300], [2016-05-04 13:30:00 +0300, 2016-05-04 18:20:00 +0300]]
35
+ # # => [[2016-05-01 00:00:00 +0300, 2016-05-02 00:00:00 +0300], [2016-05-02 00:00:00 +0300, 2016-05-03 00:00:00 +0300], [2016-05-03 00:00:00 +0300, 2016-05-04 00:00:00 +0300]]
50
36
  # seq.ranges
51
- # # => [2016-05-01 13:30:00 +0300...2016-05-02 13:30:00 +0300, 2016-05-02 13:30:00 +0300...2016-05-03 13:30:00 +0300, 2016-05-03 13:30:00 +0300...2016-05-04 13:30:00 +0300, 2016-05-04 13:30:00 +0300...2016-05-04 18:20:00 +0300]
37
+ # # => [2016-05-01 00:00:00 +0300...2016-05-02 00:00:00 +0300, 2016-05-02 00:00:00 +0300...2016-05-03 00:00:00 +0300, 2016-05-03 00:00:00 +0300...2016-05-04 00:00:00 +0300]
52
38
  # ```
53
39
  #
54
- # It is pretty convenient for filtering data from databases or APIs,
55
- # TimeMath creates list of filtering ranges in a blink.
40
+ # It is pretty convenient for filtering data from databases or APIs: TimeMath creates list of
41
+ # filtering ranges in a blink.
56
42
  #
57
43
  # Sequence also supports any item-updating operations in the same fashion
58
44
  # {Op} does:
59
45
  #
60
46
  # ```ruby
61
- # seq = TimeMath.day.sequence(from...to, expand: true).advance(:hour, 5).decrease(:min, 20)
62
- # # => #<TimeMath::Sequence(:day, 2016-05-01 00:00:00 +0300...2016-05-05 00:00:00 +0300).advance(:hour, 5).decrease(:min, 20)>
47
+ # seq = TimeMath.day.sequence(from...to).advance(:hour, 5).decrease(:min, 20)
48
+ # # => #<TimeMath::Sequence day (2016-05-01 00:00:00 +0300 - 2016-05-03 00:00:00 +0300).advance(:hour, 5).decrease(:min, 20)>
63
49
  # seq.to_a
64
- # # => [2016-05-01 04:40:00 +0300, 2016-05-02 04:40:00 +0300, 2016-05-03 04:40:00 +0300, 2016-05-04 04:40:00 +0300]
50
+ # # => [2016-05-01 04:40:00 +0300, 2016-05-02 04:40:00 +0300, 2016-05-03 04:40:00 +0300]
65
51
  # ```
66
52
  #
67
53
  class Sequence
68
- # Creates a sequence. Typically, it is easier to to it with {Units::Base#sequence},
54
+ # Creates a sequence. Typically, it is easier to do it with {Units::Base#sequence},
69
55
  # like this:
70
56
  #
71
57
  # ```ruby
@@ -76,23 +62,17 @@ module TimeMath
76
62
  # @param range [Range] range of time-y values (Time, Date, DateTime);
77
63
  # note that range with inclusive and exclusive and will produce
78
64
  # different sequences.
79
- # @param options [Hash]
80
- # @option options [Boolean] :expand round sequence ends on creation
81
- # (`from` is floored and `to` is ceiled);
82
65
  #
83
- def initialize(unit, range, options = {})
66
+ def initialize(unit, range)
84
67
  @unit = Units.get(unit)
85
- @from, @to, @exclude_end = process_range(range)
86
- @options = options.dup
87
-
88
- expand! if options[:expand]
68
+ @from, @to = process_range(range)
89
69
  @op = Op.new
90
70
  end
91
71
 
92
72
  # @private
93
73
  def initialize_copy(other)
94
74
  @unit = other.unit
95
- @from, @to, @exclude_end = other.from, other.to, other.exclude_end?
75
+ @from, @to = other.from, other.to
96
76
  @op = other.op.dup
97
77
  end
98
78
 
@@ -106,33 +86,9 @@ module TimeMath
106
86
  def ==(other) # rubocop:disable Metrics/AbcSize
107
87
  self.class == other.class && unit == other.unit &&
108
88
  from == other.from && to == other.to &&
109
- exclude_end? == other.exclude_end? &&
110
89
  op == other.op
111
90
  end
112
91
 
113
- # Whether sequence was created from exclude-end range (and, therefore,
114
- # will exclude `to` when converted to array).
115
- def exclude_end?
116
- @exclude_end
117
- end
118
-
119
- # Expand sequence ends to nearest round unit.
120
- #
121
- # @return [self]
122
- def expand!
123
- @from = unit.floor(from)
124
- @to = unit.ceil(to)
125
-
126
- self
127
- end
128
-
129
- # Creates new sequence with ends rounded to nearest unit.
130
- #
131
- # @return [Sequence]
132
- def expand
133
- dup.expand!
134
- end
135
-
136
92
  # @method floor!(unit, span = 1)
137
93
  # Adds {Units::Base#floor} to list of operations to apply to sequence items.
138
94
  #
@@ -239,12 +195,11 @@ module TimeMath
239
195
  return to_enum(:each) unless block_given?
240
196
 
241
197
  iter = from
242
- while iter < to
198
+ while iter <= to
243
199
  yield(op.call(iter))
244
200
 
245
201
  iter = unit.advance(iter)
246
202
  end
247
- yield(op.call(to)) unless exclude_end?
248
203
  end
249
204
 
250
205
  include Enumerable
@@ -255,7 +210,7 @@ module TimeMath
255
210
  # @return [Array<Array>]
256
211
  def pairs
257
212
  seq = to_a
258
- seq.zip(seq[1..-1] + [to])
213
+ seq.zip([*seq[1..-1], unit.advance(to)])
259
214
  end
260
215
 
261
216
  # Creates an array of Ranges (time unit start...time unit end) between
@@ -269,16 +224,21 @@ module TimeMath
269
224
  def inspect
270
225
  ops = op.inspect_operations
271
226
  ops = '.' + ops unless ops.empty?
272
- "#<#{self.class}(#{unit.name.inspect}, #{from}#{exclude_end? ? '...' : '..'}#{to})#{ops}>"
227
+ "#<#{self.class} #{unit.name} (#{from} - #{to})#{ops}>"
273
228
  end
274
229
 
275
230
  private
276
231
 
232
+ def valid_time_range?(range)
233
+ range.is_a?(Range) && Util.timey?(range.begin) && Util.timey?(range.end)
234
+ end
235
+
277
236
  def process_range(range)
278
- range.is_a?(Range) && Util.timey?(range.begin) && Util.timey?(range.end) or
237
+ valid_time_range?(range) or
279
238
  raise ArgumentError, "Range of time-y values expected, #{range} got"
280
239
 
281
- [range.begin, range.end, range.exclude_end?]
240
+ range_end = unit.floor(range.end)
241
+ [unit.floor(range.begin), range.exclude_end? ? unit.decrease(range_end) : range_end]
282
242
  end
283
243
  end
284
244
  end
@@ -223,20 +223,13 @@ module TimeMath
223
223
  end
224
224
 
225
225
  # Creates {Sequence} instance for producing all time units between
226
- # from and too. See {Sequence} class documentation for available
227
- # options and functionality.
226
+ # from and too. See {Sequence} class documentation for detailed functionality description.
228
227
  #
229
- # @param from [Time,Date,DateTime] start of sequence;
230
- # @param to [Time,Date,DateTime] upper limit of sequence;
231
- # @param options [Hash]
232
- # @option options [Boolean] :expand round sequence ends on creation
233
- # (from is floored and to is ceiled);
234
- # @option options [Boolean] :floor sequence will be rounding'ing all
235
- # the intermediate values.
228
+ # @param range [Range<Time,Date,DateTime>] start and end of sequence.
236
229
  #
237
230
  # @return [Sequence]
238
- def sequence(range, options = {})
239
- TimeMath::Sequence.new(name, range, options)
231
+ def sequence(range)
232
+ TimeMath::Sequence.new(name, range)
240
233
  end
241
234
 
242
235
  # Converts input timestamps list to regular list of timestamps
@@ -1,4 +1,4 @@
1
1
  module TimeMath
2
2
  # @private
3
- VERSION = '0.0.8'.freeze
3
+ VERSION = '0.1.0'.freeze
4
4
  end
@@ -16,6 +16,8 @@ Gem::Specification.new do |s|
16
16
  EOF
17
17
  s.licenses = ['MIT']
18
18
 
19
+ s.required_ruby_version = '>= 2.1.0'
20
+
19
21
  s.files = `git ls-files`.split($RS).reject do |file|
20
22
  file =~ /^(?:
21
23
  spec\/.*
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: time_math2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Shepelev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-02 00:00:00.000000000 Z
11
+ date: 2017-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -165,7 +165,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
165
165
  requirements:
166
166
  - - ">="
167
167
  - !ruby/object:Gem::Version
168
- version: '0'
168
+ version: 2.1.0
169
169
  required_rubygems_version: !ruby/object:Gem::Requirement
170
170
  requirements:
171
171
  - - ">="