Class: Bonito::SerialTimeline

Inherits:
Timeline
  • Object
show all
Defined in:
lib/bonito/serial_timeline.rb

Overview

A SerialTimeline is a data structure with a duration (measured in seconds) that contains timelines. A timeline is any instance of a class that inherits from the Timeline base class.

A SerialTimeline serves to define an interval in which it may be simulated that one or more Moment objects are evaluated in series_.

A SerialTimeline exposes methods that can either be used to define these Moment objects directly or to create additional child data structures (i.e ParallelTimeline objects or further, child SerialTimeline objects) which can in turn be provide more fine grained control over precisely when any given Moment objects may be evaluated.

Example

Bonito.over(2.weeks) do
  please { puts Time.now }
end

The above defines a SerialTimeline (using the Bonito#over module method) that specifies a 2 week time period. A single Moment is included in this serial (via the #please factory method). When the top level SerialTimeline is evaluated (using a Runner object) the block

puts Time.now

is evaluated exactly once. Furthermore, the simulated time at which the block is evaluated will be contained at some point within the 2 week interval beginning on some start date provided when instantiating the Runner object.

As mentioned, it is also possible to include other data structures within SerialTimeline objects, including other SerialTimeline objects.

Example

We could use the #over method to add an empty SerialTimeline to the previous example in order to force the already included Moment to be evaluated during the last day of the 2 week period.

Bonito.over(2.weeks) do
  over(2.weeks - 1.day)  # This defines an empty serial
  please { puts Time.now }
end

The empty SerialTimeline returned by the #over factory method consumes 13 days of the parent SerialTimeline object’s total duration of 2 weeks. This means that when this parent SerialTimeline is evaluated, the Moment will be as if it occurred during the final day of the 2 week period.

Finally, we may also define ParallelTimeline objects within serials using the #simultaneously method. These allow for multiple SerialTimeline objects to be defined over the same time period and for any Moment objects contained within to be interleaved when the parent SerialTimeline is ultimately evaluated.

The #simultaneously method instantiates a ParallelTimeline object, whilst accepting a block. The block is evaluated within the context of the new ParallelTimeline. Timelines defined within this block will be evaluated in parallel.

Note that ParallelTimeline implements many of the same methods as SerialTimeline

Example

Bonito.over(2.weeks) do
  simultaneously do
    over 1.week do
      puts "SerialTimeline 1 #{Time.now}"
    end
    over 6.days, after: 1.day do
      puts "SerialTimeline 2 #{Time.now}"
    end
  end

  over 1.week {}  # This defines an empty serial
end

Now, when evaluating this SerialTimeline both the blocks

puts "SerialTimeline 1 #{Time.now}"

and

puts "SerialTimeline 2 #{Time.now}"

will be evaluated once during the first week. The precise instant is chosen randomly within this interval with the only constraint being that the second block cannot be evaluated during the first day (This offset is controlled by the after parameter of the #simultaneously method).

Note that the moment from the second SerialTimeline could still be evaluated at a simulated time before that at which the moment from the first SerialTimeline is evaluated.

Instance Attribute Summary

Attributes inherited from Timeline

#duration

Instance Method Summary collapse

Methods inherited from Timeline

#each, schedule_with, #scheduler, #size

Constructor Details

#initialize(duration, parent = nil, &block) ⇒ SerialTimeline

Instantiate a new SerialTimeline object

duration

The total time period (in seconds) that the SerialTimeline encompasses

parent

If the SerialTimeline is a child of another Timeline, parent is this Timeline

block

A block that will be evaluated within the context of the newly created SerialTimeline. Note that the following two statements are equivalent

a_serial = Bonito::SerialTimeline.new(1.week) do

please { p Time.now }

end

another_serial = Bonito::SerialTimeline.new 1.week serial.please { p Time.now }

The ability to include a block in this way is in order to allow the code used to define a given SerialTimeline will reflect its hierarchy.



143
144
145
146
147
148
# File 'lib/bonito/serial_timeline.rb', line 143

def initialize(duration, parent = nil, &block)
  @parent = parent
  @total_child_duration = 0
  super duration
  instance_eval(&block) if block_given?
end

Instance Method Details

#*(other) ⇒ Object

Repeatedly apply the #+ method of the current SerialTimeline to itself

other

Denotes the number of times the current serial should be added to itself.

Returns a new SerialTimeline object

Note that the following statements are equivalent for some serial serial:

serial * 3
serial + serial + serial


254
255
256
257
258
# File 'lib/bonito/serial_timeline.rb', line 254

def *(other)
  SerialTimeline.new(duration * other) do
    use(*Array.new(other) { entries }.reduce(:+))
  end
end

#**(other) ⇒ Object

Scale up a serial by parallelising it according to some factor

other

An Integer denoting the degree of parallelism with which to scale the serial.

Returns a new ParallelTimeline whose child timelines are precisely the current serial repeated other times.



268
269
270
271
272
273
# File 'lib/bonito/serial_timeline.rb', line 268

def **(other)
  this = self
  SerialTimeline.new(duration) do
    simultaneously { use(*Array.new(other) { this }) }
  end
end

#+(other) ⇒ Object

Combine two Windows into a single, larger SerialTimeline object.

other

Some other SerialTimeline object

Returns a SerialTimeline object consisting of the ordered child Timeline objects of the current SerialTimeline with the ordered child Timeline objects of other appended to the end.



234
235
236
237
238
# File 'lib/bonito/serial_timeline.rb', line 234

def +(other)
  SerialTimeline.new duration + other.duration do
    use(*(to_a + other.to_a))
  end
end

#over(duration, &block) ⇒ Object

Define a new SerialTimeline and add it as a child to the current SerialTimeline

duration

The duration (in seconds) of the newly created child SerialTimeline

block

A block passed to the #new method on the child SerialTimeline object

Returns the newly created SerialTimeline object



166
167
168
# File 'lib/bonito/serial_timeline.rb', line 166

def over(duration, &block)
  self.class.new(duration, self, &block).tap(&method(:use))
end

#please(&block) ⇒ Object

Define a new Moment and add it as a child to the current SerialTimeline

block

A block passed to the #new method on the child Moment object

Returns the newly created Moment object



176
177
178
# File 'lib/bonito/serial_timeline.rb', line 176

def please(&block)
  Moment.new(&block).tap(&method(:use))
end

#repeat(times:, over:, &block) ⇒ Object

Define a new serial and append it multiple times as a child of the current SerialTimeline object.

times

The number of times that the new SerialTimeline object to be appended to the current SerialTimeline

over

The total duration (in senconds) of the new repeated SerialTimeline objects.

block

A block passed to the #new method on the child SerialTimeline object

Returns the current SerialTimeline



196
197
198
199
# File 'lib/bonito/serial_timeline.rb', line 196

def repeat(times:, over:, &block)
  repeated_block = proc { times.times { instance_eval(&block) } }
  over(over, &repeated_block)
end

#simultaneously(&block) ⇒ Object

Define a new ParallelTimeline object append it as a child to the current SerialTimeline. Also permit the evaluation of methods within the context of the new ParallelTimeline.

block

A block to be passed to the #new method on the child ParallelTimeline method.

Returns the current SerialTimeline object



210
211
212
# File 'lib/bonito/serial_timeline.rb', line 210

def simultaneously(&block)
  use ParallelTimeline.new(&block)
end

#unused_durationObject

The the amount of #duration remaining taking into account the duration of any Timeline objects included as children of the SerialTimeline.



152
153
154
# File 'lib/bonito/serial_timeline.rb', line 152

def unused_duration
  duration - @total_child_duration
end

#use(*timelines) ⇒ Object

Append an existing Timeline as a child of the current SerialTimeline

timelines

An array of Timeline objects that will be appended, in order to the current SerialTimeline

Returns the current SerialTimeline object



221
222
223
224
# File 'lib/bonito/serial_timeline.rb', line 221

def use(*timelines)
  timelines.each { |timeline| send :<<, timeline }
  self
end