class EventMachine::Completion
def callback(*a, &b)
def callback(*a, &b) stateback(:succeeded, *a, &b) end
def cancel_callback(*a, &b)
Remove a callback. N.B. Some callbacks cannot be deleted. Usage is NOT
def cancel_callback(*a, &b) @callbacks[:succeeded].delete(EM::Callback(*a, &b)) end
def cancel_errback(*a, &b)
Remove an errback. N.B. Some errbacks cannot be deleted. Usage is NOT
def cancel_errback(*a, &b) @callbacks[:failed].delete(EM::Callback(*a, &b)) end
def cancel_timeout
def cancel_timeout if @timeout_timer @timeout_timer.cancel @timeout_timer = nil end end
def change_state(state, *args)
Enter a new state, setting the result value if given. If the state is one
def change_state(state, *args) @value = args @state = state EM.schedule { execute_callbacks } end
def clear_dead_callbacks
callback chains are completed. This means that operation specific
If we enter a completion state, clear other completion states after all
def clear_dead_callbacks completion_states.each do |state| @callbacks[state].clear end end
def completed?
this is :succeeded or :failed. Due to these semantics, the :completed
Indicates that we've reached some kind of completion state, by default
def completed? completion_states.any? { |s| state == s } end
def completion(*a, &b)
:succeeded state. They are stored as a special (reserved) state called
Completions are called when you enter (or are in) either a :failed or a
def completion(*a, &b) stateback(:completed, *a, &b) end
def completion_states
Completion states simply returns a list of completion states, by default
def completion_states [:succeeded, :failed] end
def errback(*a, &b)
def errback(*a, &b) stateback(:failed, *a, &b) end
def execute_callbacks
Execute all callbacks for the current state. If in a completed state, then
def execute_callbacks execute_state_callbacks(state) if completed? execute_state_callbacks(:completed) clear_dead_callbacks cancel_timeout end end
def execute_state_callbacks(state)
def execute_state_callbacks(state) while callback = @callbacks[state].shift callback.call(*value) end end
def fail(*args)
def fail(*args) change_state(:failed, *args) end
def initialize
def initialize @state = :unknown @callbacks = Hash.new { |h,k| h[k] = [] } @value = [] @timeout_timer = nil end
def stateback(state, *a, &b)
def stateback(state, *a, &b) # The following is quite unfortunate special casing for :completed # statebacks, but it's a necessary evil for latent completion # definitions. if :completed == state || !completed? || @state == state @callbacks[state] << EM::Callback(*a, &b) end execute_callbacks self end
def succeed(*args)
def succeed(*args) change_state(:succeeded, *args) end
def timeout(time, *args)
Schedule a time which if passes before we enter a completion state, this
def timeout(time, *args) cancel_timeout @timeout_timer = EM::Timer.new(time) do fail(*args) unless completed? end end