From: Nick Lewis <[email protected]> Callbacks are intended to be used by Dashboard's modular plug-ins to modify core functionality. Core functionality will call Registry.each_callback to invoke callbacks, and plug-ins will call Registry.add_callback to make their presence known to the core.
Reviewed-by: Paul Berry <[email protected]> and Max Martin <[email protected]> Signed-off-by: Paul Berry <[email protected]> --- Local-branch: maint/next/add-registry config/environment.rb | 2 + lib/registry.rb | 44 +++++++++++++++++++++ spec/lib/registry_spec.rb | 92 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 0 deletions(-) create mode 100644 lib/registry.rb create mode 100644 spec/lib/registry_spec.rb diff --git a/config/environment.rb b/config/environment.rb index 6eaf249..e0084a5 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -7,6 +7,8 @@ RAILS_GEM_VERSION = '2.3.4' unless defined? RAILS_GEM_VERSION require File.join(File.dirname(__FILE__), 'boot') require 'active_support' +require 'registry' + Rails::Initializer.run do |config| config.gem 'rack' config.gem 'haml' diff --git a/lib/registry.rb b/lib/registry.rb new file mode 100644 index 0000000..a1f60f3 --- /dev/null +++ b/lib/registry.rb @@ -0,0 +1,44 @@ +class Registry + class << self + delegate :add_callback, :each_callback, :find_first_callback, :to => :instance + end + + def self.instance + @instance ||= new + end + + def add_callback( feature_name, hook_name, callback_name, value = nil, &block ) + if block and value + raise "Cannot pass both a value and a block to add_callback" + elsif @registry[feature_name][hook_name][callback_name] + raise "Cannot redefine callback [#{feature_name.inspect},#{hook_name.inspect},#{callback_name}]" + end + + @registry[feature_name][hook_name][callback_name] = value || block + end + + def each_callback( feature_name, hook_name ) + hook = @registry[feature_name][hook_name] + hook.sort.each do |callback_name,callback| + yield( callback ) + end + nil + end + + def find_first_callback(feature_name, hook_name) + self.each_callback(feature_name, hook_name) do |thing| + if result = yield(thing) + return result + end + end + nil + end + + def initialize + @registry = Hash.new do |registry, feature_name| + registry[feature_name] = Hash.new do |hooks, hook_name| + hooks[hook_name] = Hash.new + end + end + end +end diff --git a/spec/lib/registry_spec.rb b/spec/lib/registry_spec.rb new file mode 100644 index 0000000..ecb3020 --- /dev/null +++ b/spec/lib/registry_spec.rb @@ -0,0 +1,92 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe @registry do + before :each do + @registry = Registry.new + end + + describe "#add_callback" do + it "does not allow multiple callbacks with the same name" do + @registry.add_callback(:test, :hook, "test_callback", "value1") + lambda { @registry.add_callback(:test, :hook, "test_callback", "value2") }.should raise_error(/Cannot redefine callback/) + + callbacks = [] + @registry.each_callback(:test, :hook) do |callback| + callbacks << callback + end + callbacks.should == ["value1"] + end + + it "does not allow both a value and a block to be specified" do + lambda { @registry.add_callback(:test, :hook, "test_callback", "inline_value") { "block_value" } }.should raise_error(/Cannot pass both a value and a block/) + callbacks = [] + @registry.each_callback(:test, :hook) do |callback| + callbacks << callback + end + callbacks.should be_empty + end + + it "adds the given callback to the registry" do + @registry.add_callback(:test, :hook, "0_block_callback") { "my block" } + @registry.add_callback(:test, :hook, "1_value_callback", "foo bar baz") + + callbacks = [] + @registry.each_callback(:test, :hook) do |callback| + callbacks << callback + end + callbacks.first.should be_a(Proc) + callbacks.first.call.should == "my block" + callbacks.last.should == "foo bar baz" + end + end + + describe "#each_callback" do + it "does nothing if the hook has no callbacks" do + callbacks = [] + @registry.each_callback(:test, :nonexistent) do |callback| + callbacks << callback + end + callbacks.should be_empty + end + + it "yields each callback in order" do + @registry.add_callback(:test, :hook, "2_callback", "second") + @registry.add_callback(:test, :hook, "3_callback", "third") + @registry.add_callback(:test, :hook, "1_callback", "first") + + values = [] + + @registry.each_callback(:test, :hook) do |value| + values << value + end + + values.should == ["first", "second", "third"] + end + + it "yields procs intact, not their values" do + @registry.add_callback(:test, :hook, "my_callback") { "my_callback_value" } + @registry.add_callback(:test, :hook, "my_other_callback") { "my_other_callback_value" } + + blocks = [] + @registry.each_callback(:test, :hook) do |block| + blocks << block + end + + blocks.map(&:class).should == [Proc, Proc] + blocks.map(&:call).should == ["my_callback_value", "my_other_callback_value"] + end + end + + describe "#find_first_callback" do + it "returns the value returned by the first callback which returns a value" do + @registry.add_callback(:test, :hook, "0_callback") { 0 } + @registry.add_callback(:test, :hook, "1_callback") { 1 } + @registry.add_callback(:test, :hook, "2_callback") { 2 } + + @registry.find_first_callback(:test, :hook) do |callback| + val = callback.call + val.odd? ? val.ordinalize : nil + end.should == "1st" + end + end +end -- 1.7.2 -- You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en.
