1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
require 'set'
require 'forwardable'
require 'hitimes'
require 'timers/timer'
require 'timers/events'
module Timers
class Group
include Enumerable
extend Forwardable
def_delegators :@timers, :each, :empty?
def initialize
@events = Events.new
@timers = Set.new
@paused_timers = Set.new
@interval = Hitimes::Interval.new
@interval.start
end
# Scheduled events:
attr :events
# Active timers:
attr :timers
# Paused timers:
attr :paused_timers
# Call the given block after the given interval. The first argument will be
# the time at which the group was asked to fire timers for.
def after(interval, &block)
Timer.new(self, interval, false, &block)
end
# Call the given block immediately, and then after the given interval. The first
# argument will be the time at which the group was asked to fire timers for.
def now_and_after(interval, &block)
block.call
after(interval, &block)
end
# Call the given block periodically at the given interval. The first
# argument will be the time at which the group was asked to fire timers for.
def every(interval, recur = true, &block)
Timer.new(self, interval, recur, &block)
end
# Call the given block immediately, and then periodically at the given interval. The first
# argument will be the time at which the group was asked to fire timers for.
def now_and_every(interval, recur = true, &block)
block.call
every(interval, recur, &block)
end
# Wait for the next timer and fire it. Can take a block, which should behave
# like sleep(n), except that n may be nil (sleep forever) or a negative
# number (fire immediately after return).
def wait(&block)
if block_given?
yield wait_interval
while interval = wait_interval and interval > 0
yield interval
end
else
while interval = wait_interval and interval > 0
# We cannot assume that sleep will wait for the specified time, it might be +/- a bit.
sleep interval
end
end
return fire
end
# Interval to wait until when the next timer will fire.
# - nil: no timers
# - -ve: timers expired already
# - 0: timers ready to fire
# - +ve: timers waiting to fire
def wait_interval(offset = self.current_offset)
if handle = @events.first
return handle.time - Float(offset)
end
end
# Fire all timers that are ready.
def fire(offset = self.current_offset)
@events.fire(offset)
end
# Pause all timers.
def pause
@timers.dup.each do |timer|
timer.pause
end
end
# Resume all timers.
def resume
@paused_timers.dup.each do |timer|
timer.resume
end
end
alias_method :continue, :resume
# Delay all timers.
def delay(seconds)
@timers.each do |timer|
timer.delay(seconds)
end
end
# Cancel all timers.
def cancel
@timers.dup.each do |timer|
timer.cancel
end
end
# The group's current time.
def current_offset
@interval.to_f
end
end
end
|