module Ably::Modules::EventEmitter

EventEmitter provides methods to attach to public events and emit events on any class instance

EventEmitter are typically used for public interfaces, and as such, may be overriden in the classes to enforce ‘event` names match expected values.

@note This module requires that the method logger is defined.

@example

class Example
  include Modules::EventEmitter
end

event_emitter = Example.new
event_emitter.on(:signal) { |name| puts "Signal #{name} received" }
event_emitter.emit :signal, "Test"
#=> "Signal Test received"

Private Class Methods

included(klass) click to toggle source
# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 156
def self.included(klass)
  klass.extend ClassMethods
end

Public Instance Methods

emit(event_name, *args) click to toggle source

Emits an event, calling registered listeners with the given event name and any other given arguments. If an exception is raised in any of the listeners, the exception is caught by the EventEmitter and the exception is logged to the Ably logger.

@spec RTE6

# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 90
def emit(event_name, *args)
  [callbacks_any, callbacks[callbacks_event_coerced(event_name)]].each do |callback_arr|
    callback_arr.clone.
    select do |proc_hash|
      if proc_hash[:unsafe]
        proc_hash[:emit_proc].call(*args)
      else
        safe_yield proc_hash[:emit_proc], *args
      end
    end.each do |callback|
      callback_arr.delete callback
    end
  end
end
off(*event_names, &block) click to toggle source

Remove all callbacks for event_name.

If a block is provided, only callbacks matching that block signature will be removed. If block is not provided, all callbacks matching the event_name will be removed.

@spec RTE5

@param [Array<String>] event_names event name

@return [void]

# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 116
def off(*event_names, &block)
  off_internal(false, *event_names, &block)
end
on(*event_names, &block) click to toggle source

On receiving an event matching the event_name, call the provided block

@spec RTE4

@param [Array<String>] event_names event name

@return [void]

# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 55
def on(*event_names, &block)
  add_callback event_names, proc_for_block(block)
end
once(*event_names, &block) click to toggle source

On receiving an event maching the event_name, call the provided block only once and remove the registered callback

@spec RTE4

@param [Array<String>] event_names event name

@return [void]

# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 74
def once(*event_names, &block)
  add_callback event_names, proc_for_block(block, delete_once_run: true)
end
unsafe_off(*event_names, &block) click to toggle source

Equivalent of {#off} but only unsafe listeners are removed. This method is designed to be used internally by the client library. @api private

# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 123
def unsafe_off(*event_names, &block)
  off_internal(true, *event_names, &block)
end
unsafe_on(*event_names, &block) click to toggle source

Equivalent of {#on} but any exception raised in a block will bubble up and cause this client library to fail. This method is designed to be used internally by the client library. @api private

# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 62
def unsafe_on(*event_names, &block)
  add_callback event_names, proc_for_block(block, unsafe: true)
end
unsafe_once(*event_names, &block) click to toggle source

Equivalent of {#once} but any exception raised in a block will bubble up and cause this client library to fail. This method is designed to be used internally by the client library. @api private

# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 81
def unsafe_once(*event_names, &block)
  add_callback event_names, proc_for_block(block, delete_once_run: true, unsafe: true)
end

Private Instance Methods

add_callback(event_names, proc_block) click to toggle source
# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 160
def add_callback(event_names, proc_block)
  if event_names.empty?
    callbacks_any << proc_block
  else
    event_names.each do |event_name|
      callbacks[callbacks_event_coerced(event_name)] << proc_block
    end
  end
end
callbacks() click to toggle source
# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 183
def callbacks
  @callbacks ||= Hash.new { |hash, key| hash[key] = [] }
end
callbacks_any() click to toggle source
# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 187
def callbacks_any
  @callbacks_any ||= []
end
callbacks_event_coerced(event_name) click to toggle source
# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 191
def callbacks_event_coerced(event_name)
  if self.class.event_emitter_coerce_proc
    self.class.event_emitter_coerce_proc.call(event_name)
  else
    event_name
  end
end
off_internal(unsafe, *event_names, &block) click to toggle source
# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 128
def off_internal(unsafe, *event_names, &block)
  keys = if event_names.empty?
    callbacks.keys
  else
    event_names
  end

  if event_names.empty?
    callbacks_any.delete_if do |proc_hash|
      if block_given?
        (proc_hash[:unsafe] == unsafe) && (proc_hash[:block] == block)
      else
        proc_hash[:unsafe] == unsafe
      end
    end
  end

  keys.each do |event_name|
    callbacks[callbacks_event_coerced(event_name)].delete_if do |proc_hash|
      if block_given?
        (proc_hash[:unsafe] == unsafe) && (proc_hash[:block] == block)
      else
        proc_hash[:unsafe] == unsafe
      end
    end
  end
end
proc_for_block(block, options = {}) click to toggle source

Create a Hash with a proc that calls the provided block and returns true if option :delete_once_run is set to true. emit automatically deletes any blocks that return true thus allowing a block to be run once

# File lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb, line 172
def proc_for_block(block, options = {})
  {
    emit_proc: lambda do |*args|
      block.call(*args)
      true if options[:delete_once_run]
    end,
    block: block,
    unsafe: options[:unsafe] || false
  }
end