summaryrefslogtreecommitdiffstats
path: root/test/lib/spec/callback
diff options
context:
space:
mode:
Diffstat (limited to 'test/lib/spec/callback')
-rw-r--r--test/lib/spec/callback/callback_container.rb60
-rw-r--r--test/lib/spec/callback/extensions/module.rb24
-rw-r--r--test/lib/spec/callback/extensions/object.rb37
3 files changed, 121 insertions, 0 deletions
diff --git a/test/lib/spec/callback/callback_container.rb b/test/lib/spec/callback/callback_container.rb
new file mode 100644
index 000000000..24d4c0ced
--- /dev/null
+++ b/test/lib/spec/callback/callback_container.rb
@@ -0,0 +1,60 @@
+module Callback
+ class CallbackContainer
+ def initialize
+ @callback_registry = Hash.new do |hash, key|
+ hash[key] = Array.new
+ end
+ end
+
+ # Defines the callback with the key in this container.
+ def define(key, callback_proc=nil, &callback_block)
+ callback = extract_callback(callback_block, callback_proc) do
+ raise "You must define the callback that accepts the call method."
+ end
+ @callback_registry[key] << callback
+ callback
+ end
+
+ # Undefines the callback with the key in this container.
+ def undefine(key, callback_proc)
+ callback = extract_callback(callback_proc) do
+ raise "You may only undefine callbacks that use the call method."
+ end
+ @callback_registry[key].delete callback
+ callback
+ end
+
+ # Notifies the callbacks for the key. Arguments may be passed.
+ # An error handler may be passed in as a block. If there is an error, the block is called with
+ # error object as an argument.
+ # An array of the return values of the callbacks is returned.
+ def notify(key, *args, &error_handler)
+ @callback_registry[key].collect do |callback|
+ begin
+ callback.call(*args)
+ rescue Exception => e
+ yield(e) if error_handler
+ end
+ end
+ end
+
+ # Clears all of the callbacks in this container.
+ def clear
+ @callback_registry.clear
+ end
+
+ protected
+ def extract_callback(first_choice_callback, second_choice_callback = nil)
+ callback = nil
+ if first_choice_callback
+ callback = first_choice_callback
+ elsif second_choice_callback
+ callback = second_choice_callback
+ end
+ unless callback.respond_to? :call
+ yield
+ end
+ return callback
+ end
+ end
+end
diff --git a/test/lib/spec/callback/extensions/module.rb b/test/lib/spec/callback/extensions/module.rb
new file mode 100644
index 000000000..429268ed1
--- /dev/null
+++ b/test/lib/spec/callback/extensions/module.rb
@@ -0,0 +1,24 @@
+module Callback
+ module ModuleMethods
+ # For each event_name submitted, defines a callback event with this name.
+ # Client code can then register as a callback listener using object.event_name.
+ def callback_events(*event_names)
+ event_names.each do |event_name|
+ define_callback_event(event_name)
+ end
+ end
+
+ private
+ def define_callback_event(event_name)
+ module_eval <<-EOS
+ def #{event_name}(&block)
+ register_callback(:#{event_name}, &block)
+ end
+ EOS
+ end
+ end
+end
+
+class Module
+ include Callback::ModuleMethods
+end
diff --git a/test/lib/spec/callback/extensions/object.rb b/test/lib/spec/callback/extensions/object.rb
new file mode 100644
index 000000000..c6ac6fd14
--- /dev/null
+++ b/test/lib/spec/callback/extensions/object.rb
@@ -0,0 +1,37 @@
+module Callback
+ module InstanceMethods
+ # Registers a callback for the event on the object. The callback can either be a block or a proc.
+ # When the callbacks are notified, the return value of the proc is passed to the caller.
+ def register_callback(event, callback_proc=nil, &callback_block)
+ callbacks.define(event, callback_proc, &callback_block)
+ end
+
+ # Removes the callback from the event. The callback proc must be the same
+ # object as the one that was passed to register_callback.
+ def unregister_callback(event, callback_proc)
+ callbacks.undefine(event, callback_proc)
+ end
+
+ protected
+ # Notifies the callbacks registered with the event on the object. Arguments can be passed to the callbacks.
+ # An error handler may be passed in as a block. If there is an error, the block is called with
+ # error object as an argument.
+ # An array of the return values of the callbacks is returned.
+ def notify_callbacks(event, *args, &error_handler)
+ callbacks.notify(event, *args, &error_handler)
+ end
+
+ def notify_class_callbacks(event, *args, &error_handler)
+ self.class.send(:notify_callbacks, event, *args, &error_handler)
+ end
+
+ # The CallbackContainer for this object.
+ def callbacks
+ @callbacks ||= CallbackContainer.new
+ end
+ end
+end
+
+class Object
+ include Callback::InstanceMethods
+end \ No newline at end of file