Class: Ruck::Clock
- Inherits:
-
Object
- Object
- Ruck::Clock
- Defined in:
- lib/ruck/clock.rb
Overview
Clock keeps track of occurrences on a virtual timeline. Clocks can be configured to run fast or slow relative to another clock by changing their relative_rate and providing them a parent via add_child_clock.
Clocks and their sub-clocks always tell the same time. When fast_forward is called, they advance in lock-step. You should only call fast_forward on the root of any tree of Clocks.
A warning about fast_forward and time travel
When using a Clock with no children, there’s little reason to ever call fast_forward because in that case Clock is little more than a priority queue. When using a Clock with children, before ever changing a Clock’s relative_rate, you should fast_forward to the VIRTUAL instant that change is meant to take place. This ensures that the change happens at that time and future occurrences are scheduled correctly.
(For an example of why this is important, consider two connected clocks, where the child’s relative_rate is 1.0. If 5 time units in, the relative_rate is changed to 5,000 and fast_forward(5) isn’t called, the first 5 time units of the child’s clock are also affected by the change, and some occurrences could afterward take place at t < 5.)
Instance Attribute Summary collapse
-
#now ⇒ Object
readonly
current time in this clock’s units.
-
#relative_rate ⇒ Object
rate relative to parent clock.
Instance Method Summary collapse
-
#add_child_clock(clock) ⇒ Object
adds the given clock as a child of this one.
-
#fast_forward(dt) ⇒ Object
fast-forward this clock and all children clocks by the given time delta.
-
#initialize(relative_rate = 1.0) ⇒ Clock
constructor
A new instance of Clock.
-
#next ⇒ Object
returns [obj, relative_time], where relative_time is the offset from now in parent’s time units.
-
#schedule(obj, time = nil) ⇒ Object
schedules an occurrence at the given time with the given object, defaulting to the current time.
-
#unschedule(obj) ⇒ Object
dequeues the earliest occurrence from this clock or any child clocks.
-
#unschedule_next ⇒ Object
unschedules and returns the next object as [obj, relative_time], where relative_time is the offset from now in parent’s time units.
Constructor Details
#initialize(relative_rate = 1.0) ⇒ Clock
Returns a new instance of Clock.
37 38 39 40 41 42 |
# File 'lib/ruck/clock.rb', line 37 def initialize(relative_rate = 1.0) @relative_rate = relative_rate @now = 0 @children = [] @occurrences = PriorityQueue.new end |
Instance Attribute Details
#now ⇒ Object (readonly)
current time in this clock’s units
34 35 36 |
# File 'lib/ruck/clock.rb', line 34 def now @now end |
#relative_rate ⇒ Object
rate relative to parent clock
35 36 37 |
# File 'lib/ruck/clock.rb', line 35 def relative_rate @relative_rate end |
Instance Method Details
#add_child_clock(clock) ⇒ Object
adds the given clock as a child of this one. a clock should only be the child of one other clock, please.
53 54 55 56 |
# File 'lib/ruck/clock.rb', line 53 def add_child_clock(clock) @children << clock clock end |
#fast_forward(dt) ⇒ Object
fast-forward this clock and all children clocks by the given time delta
45 46 47 48 49 |
# File 'lib/ruck/clock.rb', line 45 def fast_forward(dt) adjusted_dt = dt * @relative_rate @now += adjusted_dt @children.each { |sub_clock| sub_clock.fast_forward(adjusted_dt) } end |
#next ⇒ Object
returns [obj, relative_time], where relative_time is the offset from now in parent’s time units
78 79 80 81 |
# File 'lib/ruck/clock.rb', line 78 def next clock, (obj, relative_time) = next_with_clock [obj, relative_time] if obj end |
#schedule(obj, time = nil) ⇒ Object
schedules an occurrence at the given time with the given object, defaulting to the current time
60 61 62 |
# File 'lib/ruck/clock.rb', line 60 def schedule(obj, time = nil) @occurrences[obj] = time || now end |
#unschedule(obj) ⇒ Object
dequeues the earliest occurrence from this clock or any child clocks. returns nil if it wasn’t there, or its relative_time otherwise
66 67 68 69 70 71 72 73 74 |
# File 'lib/ruck/clock.rb', line 66 def unschedule(obj) if @occurrences[obj] obj, time = @occurrences.delete obj unscale_time(time) else relative_time = @children.first_non_nil { |clock| clock.unschedule(obj) } unscale_relative_time(relative_time) if relative_time end end |
#unschedule_next ⇒ Object
unschedules and returns the next object as [obj, relative_time], where relative_time is the offset from now in parent’s time units
85 86 87 88 89 90 91 |
# File 'lib/ruck/clock.rb', line 85 def unschedule_next clock, (obj, relative_time) = next_with_clock if obj clock.unschedule(obj) [obj, relative_time] end end |