module Eventable
Incredibly simple framework for adding events
Constants
- VERSION
Attributes
callbacks[R]
Allows for dynamic discovery of hooked callbacks
Public Class Methods
included(base)
click to toggle source
Add the event method to the extending class not instances of that class
# File lib/eventable/eventable.rb, line 29 def self.included(base) base.extend(EventableEventMethods) end
new(*args)
click to toggle source
Calls superclass method
# File lib/eventable/eventable.rb, line 33 def initialize(*args) super @eventable_mutex = Mutex.new end
Public Instance Methods
events()
click to toggle source
# File lib/eventable/eventable.rb, line 21 def events self.class.events end
fire_event(event, *return_value, &block)
click to toggle source
When the event happens the class where it happens runs this
# File lib/eventable/eventable.rb, line 39 def fire_event(event, *return_value, &block) check_mutex @eventable_mutex.synchronize { return false unless @callbacks && @callbacks[event] && !@callbacks[event].empty? @callbacks[event].each do |listener_id, callbacks| begin listener = ObjectSpace._id2ref(listener_id) callbacks.each do |callback| Thread.new {listener.send callback, *return_value, &block} end rescue RangeError => re # Don't bubble up a missing recycled object, I don't care if it's not there, I just won't call it raise re unless re.message.match(/is recycled object/) end end } true end
register_for_event(args)
click to toggle source
Allows an object to listen for an event and have a callback run when the event happens
# File lib/eventable/eventable.rb, line 61 def register_for_event(args) [:event, :listener, :callback].each do |parameter| raise ArgumentError, "Missing parameter :#{parameter}" unless args[parameter] end # Make access to the callback array threadsafe check_mutex @eventable_mutex.synchronize { event = args[:event] raise Errors::UnknownEvent unless events.include? event @callbacks ||= {} @callbacks[event] ||= {} listener = args[:listener] listener_id = listener.object_id callback = args[:callback] # save the callback info without creating a reference to the object @callbacks[event][listener_id] ||= [] @callbacks[event][listener_id] << callback # will remove the object from the callback list if it is destroyed ObjectSpace.define_finalizer( listener, unregister_finalizer(event, listener_id, callback) ) } end
unregister_for_event(args)
click to toggle source
Allows objects to stop listening to events
# File lib/eventable/eventable.rb, line 92 def unregister_for_event(args) check_mutex @eventable_mutex.synchronize { event = args[:event] return unless @callbacks && @callbacks[event] listener_id = args[:listener_id] || args[:listener].object_id callback = args[:callback] @callbacks[event].delete_if do |listener, callbacks| callbacks.delete(callback) if listener == listener_id callbacks.empty? end } end
Private Instance Methods
check_mutex()
click to toggle source
# File lib/eventable/eventable.rb, line 109 def check_mutex raise Errors::SuperNotCalledInInitialize, "You must include super in your class's initialize method" unless @eventable_mutex end
unregister_finalizer(event, listener_id, callback)
click to toggle source
Wrapper for the finalize proc. You have to call a method from define_finalizer; you can’t just put this proc in there.
# File lib/eventable/eventable.rb, line 115 def unregister_finalizer(event, listener_id, callback) proc {unregister_for_event(event: event, listener_id: listener_id, callback: callback)} end