rf-web/vendor/bundle/gems/eventmachine-1.2.7/lib/em/tick_loop.rb
2019-10-21 10:18:17 +02:00

85 lines
2.1 KiB
Ruby

module EventMachine
# Creates and immediately starts an EventMachine::TickLoop
def self.tick_loop(*a, &b)
TickLoop.new(*a, &b).start
end
# A TickLoop is useful when one needs to distribute amounts of work
# throughout ticks in order to maintain response times. It is also useful for
# simple repeated checks and metrics.
# @example
# # Here we run through an array one item per tick until it is empty,
# # printing each element.
# # When the array is empty, we return :stop from the callback, and the
# # loop will terminate.
# # When the loop terminates, the on_stop callbacks will be called.
# EM.run do
# array = (1..100).to_a
#
# tickloop = EM.tick_loop do
# if array.empty?
# :stop
# else
# puts array.shift
# end
# end
#
# tickloop.on_stop { EM.stop }
# end
#
class TickLoop
# Arguments: A callback (EM::Callback) to call each tick. If the call
# returns +:stop+ then the loop will be stopped. Any other value is
# ignored.
def initialize(*a, &b)
@work = EM::Callback(*a, &b)
@stops = []
@stopped = true
end
# Arguments: A callback (EM::Callback) to call once on the next stop (or
# immediately if already stopped).
def on_stop(*a, &b)
if @stopped
EM::Callback(*a, &b).call
else
@stops << EM::Callback(*a, &b)
end
end
# Stop the tick loop immediately, and call it's on_stop callbacks.
def stop
@stopped = true
until @stops.empty?
@stops.shift.call
end
end
# Query if the loop is stopped.
def stopped?
@stopped
end
# Start the tick loop, will raise argument error if the loop is already
# running.
def start
raise ArgumentError, "double start" unless @stopped
@stopped = false
schedule
end
private
def schedule
EM.next_tick do
next if @stopped
if @work.call == :stop
stop
else
schedule
end
end
self
end
end
end