Class: Ruck::Clock

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

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

#nowObject (readonly)

current time in this clock’s units



34
35
36
# File 'lib/ruck/clock.rb', line 34

def now
  @now
end

#relative_rateObject

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

#nextObject

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_nextObject

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