Class: TimeMath::Sequence

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/time_math/sequence.rb

Overview

Sequence represents a sequential units of time between two points. It has several options and convenience methods for creating arrays of data.

Basic usage example:

from = Time.parse('2016-05-01 13:30')
to = Time.parse('2016-05-04 18:20')
seq = TimeMath.day.sequence(from...to)
# => #<TimeMath::Sequence(2016-05-01 13:30:00 +0300...2016-05-04 18:20:00 +0300)>

Now, you can use it:

seq.to_a
# => [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]

-- it's an "each day start between from and to". As you can see, the period start is the same as in from.

You can expand from and to to nearest round unit by #expand method or :expand option:

seq.expand.to_a
# => [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]
# or:
seq = TimeMath.day.sequence(from...to, expand: true)
# => #<TimeMath::Sequence(2016-05-01 00:00:00 +0300...2016-05-05 00:00:00 +0300)>
seq.to_a
# => [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]
# ^ note that `to` is excluded.
# You can include it by creating sequence from including-end range:
seq = TimeMath.day.sequence(from..to, expand: true)
# => #<TimeMath::Sequence(:day, 2016-05-01 00:00:00 +0300..2016-05-05 00:00:00 +0300)>
seq.to_a
# => [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]

Besides each period beginning, you can also request pairs of begin/end of a period, either as an array of arrays, or array of ranges:

seq = TimeMath.day.sequence(from...to)
seq.pairs
# => [[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]]
seq.ranges
# => [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]

It is pretty convenient for filtering data from databases or APIs, TimeMath creates list of filtering ranges in a blink.

Sequence also supports any item-updating operations in the same fashion Op does:

seq = TimeMath.day.sequence(from...to, expand: true).advance(:hour, 5).decrease(:min, 20)
# => #<TimeMath::Sequence(:day, 2016-05-01 00:00:00 +0300...2016-05-05 00:00:00 +0300).advance(:hour, 5).decrease(:min, 20)>
seq.to_a
# => [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]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(unit, range, options = {}) ⇒ Sequence

Creates a sequence. Typically, it is easier to to it with Units::Base#sequence, like this:

TimeMath.day.sequence(from...to)

Parameters:

  • unit (Symbol)
  • range (Range)

    range of time-y values (Time, Date, DateTime); note that range with inclusive and exclusive and will produce different sequences.

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :expand (Boolean)

    round sequence ends on creation (from is floored and to is ceiled);



83
84
85
86
87
88
89
90
# File 'lib/time_math/sequence.rb', line 83

def initialize(unit, range, options = {})
  @unit = Units.get(unit)
  @from, @to, @exclude_end = process_range(range)
  @options = options.dup

  expand! if options[:expand]
  @op = Op.new
end

Instance Attribute Details

#fromObject (readonly)

Returns the value of attribute from.



99
100
101
# File 'lib/time_math/sequence.rb', line 99

def from
  @from
end

#opObject (readonly)

Returns the value of attribute op.



99
100
101
# File 'lib/time_math/sequence.rb', line 99

def op
  @op
end

#toObject (readonly)

Returns the value of attribute to.



99
100
101
# File 'lib/time_math/sequence.rb', line 99

def to
  @to
end

#unitObject (readonly)

Returns the value of attribute unit.



99
100
101
# File 'lib/time_math/sequence.rb', line 99

def unit
  @unit
end

Instance Method Details

#==(other) ⇒ Boolean

Compares two sequences, considering their start, end, unit and operations.

Parameters:

Returns:

  • (Boolean)


106
107
108
109
110
111
# File 'lib/time_math/sequence.rb', line 106

def ==(other) # rubocop:disable Metrics/AbcSize
  self.class == other.class && unit == other.unit &&
    from == other.from && to == other.to &&
    exclude_end? == other.exclude_end? &&
    op == other.op
end

#advance(unit, amount = 1) ⇒ Sequence

Non-destructive version of #advance!.

Parameters:

  • unit (Symbol)
  • amount (Numeric) (defaults to: 1)

    how many units to advance.

Returns:



222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#advance!(unit, amount = 1) ⇒ self

Adds Units::Base#advance to list of operations to apply to sequence items.

Parameters:

  • unit (Symbol)
  • amount (Numeric) (defaults to: 1)

    how many units to advance.

Returns:

  • (self)


222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#ceil(unit, span = 1) ⇒ Sequence

Non-destructive version of #ceil!.

Parameters:

  • unit (Symbol)
  • span (Numeric) (defaults to: 1)

    how many units to ceil to.

Returns:



222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#ceil!(unit, span = 1) ⇒ self

Adds Units::Base#ceil to list of operations to apply to sequence items.

Parameters:

  • unit (Symbol)
  • span (Numeric) (defaults to: 1)

    how many units to ceil to.

Returns:

  • (self)


222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#decrease(unit, amount = 1) ⇒ Sequence

Non-destructive version of #decrease!.

Parameters:

  • unit (Symbol)
  • amount (Numeric) (defaults to: 1)

    how many units to decrease.

Returns:



222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#decrease!(unit, amount = 1) ⇒ self

Adds Units::Base#decrease to list of operations to apply to sequence items.

Parameters:

  • unit (Symbol)
  • amount (Numeric) (defaults to: 1)

    how many units to decrease.

Returns:

  • (self)


222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#each {|op.call(to)| ... } ⇒ Enumerator<Time, or Date, or DateTime>

Enumerates time unit between from and to. They will have same granularity as from (e.g. if unit is day and from is 2016-05-01 13:30, each of return values will be next day at 13:30), unless sequence is not set to floor values.

Yields:

Returns:

  • (Enumerator<Time, or Date, or DateTime>)


238
239
240
241
242
243
244
245
246
247
248
# File 'lib/time_math/sequence.rb', line 238

def each
  return to_enum(:each) unless block_given?

  iter = from
  while iter < to
    yield(op.call(iter))

    iter = unit.advance(iter)
  end
  yield(op.call(to)) unless exclude_end?
end

#exclude_end?Boolean

Whether sequence was created from exclude-end range (and, therefore, will exclude to when converted to array).

Returns:

  • (Boolean)


115
116
117
# File 'lib/time_math/sequence.rb', line 115

def exclude_end?
  @exclude_end
end

#expandSequence

Creates new sequence with ends rounded to nearest unit.

Returns:



132
133
134
# File 'lib/time_math/sequence.rb', line 132

def expand
  dup.expand!
end

#expand!self

Expand sequence ends to nearest round unit.

Returns:

  • (self)


122
123
124
125
126
127
# File 'lib/time_math/sequence.rb', line 122

def expand!
  @from = unit.floor(from)
  @to = unit.ceil(to)

  self
end

#floor(unit, span = 1) ⇒ Sequence

Non-destructive version of #floor!.

Parameters:

  • unit (Symbol)
  • span (Numeric) (defaults to: 1)

    how many units to floor to.

Returns:



222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#floor!(unit, span = 1) ⇒ self

Adds Units::Base#floor to list of operations to apply to sequence items.

Parameters:

  • unit (Symbol)
  • span (Numeric) (defaults to: 1)

    how many units to floor to.

Returns:

  • (self)


222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#inspectObject



269
270
271
272
273
# File 'lib/time_math/sequence.rb', line 269

def inspect
  ops = op.inspect_operations
  ops = '.' + ops unless ops.empty?
  "#<#{self.class}(#{unit.name.inspect}, #{from}#{exclude_end? ? '...' : '..'}#{to})#{ops}>"
end

#next(unit, span = 1) ⇒ Sequence

Non-destructive version of #next!.

Parameters:

  • unit (Symbol)
  • span (Numeric) (defaults to: 1)

    how many units to ceil to.

Returns:



222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#next!(unit, span = 1) ⇒ self

Adds Units::Base#next to list of operations to apply to sequence items.

Parameters:

  • unit (Symbol)
  • span (Numeric) (defaults to: 1)

    how many units to ceil to.

Returns:

  • (self)


222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#pairsArray<Array>

Creates an array of pairs (time unit start, time unit end) between from and to.

Returns:

  • (Array<Array>)


256
257
258
259
# File 'lib/time_math/sequence.rb', line 256

def pairs
  seq = to_a
  seq.zip(seq[1..-1] + [to])
end

#prev(unit, span = 1) ⇒ Sequence

Non-destructive version of #prev!.

Parameters:

  • unit (Symbol)
  • span (Numeric) (defaults to: 1)

    how many units to floor to.

Returns:



222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#prev!(unit, span = 1) ⇒ self

Adds Units::Base#prev to list of operations to apply to sequence items.

Parameters:

  • unit (Symbol)
  • span (Numeric) (defaults to: 1)

    how many units to floor to.

Returns:

  • (self)


222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#rangesArray<Range>

Creates an array of Ranges (time unit start...time unit end) between from and to.

Returns:

  • (Array<Range>)


265
266
267
# File 'lib/time_math/sequence.rb', line 265

def ranges
  pairs.map { |b, e| (b...e) }
end

#round(unit, span = 1) ⇒ Sequence

Non-destructive version of #round!.

Parameters:

  • unit (Symbol)
  • span (Numeric) (defaults to: 1)

    how many units to round to.

Returns:



222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end

#round!(unit, span = 1) ⇒ self

Adds Units::Base#round to list of operations to apply to sequence items.

Parameters:

  • unit (Symbol)
  • span (Numeric) (defaults to: 1)

    how many units to round to.

Returns:

  • (self)


222
223
224
225
226
227
228
229
230
231
# File 'lib/time_math/sequence.rb', line 222

Op::OPERATIONS.each do |operation|
  define_method "#{operation}!" do |*arg|
    @op.send("#{operation}!", *arg)
    self
  end

  define_method operation do |*arg|
    dup.send("#{operation}!", *arg)
  end
end