wizardwerdna-pluggable 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.rdoc CHANGED
@@ -1,6 +1,11 @@
1
1
  = pluggable
2
2
 
3
- Pluggable is a mixin for classes requiring plugins. A pluggable class, +Klass+, has a public function, +plugins+, returning an array-like object that holds all subclasses of <tt>Klass::Plugin</tt>.
3
+ Pluggable is a mixin for classes requiring plugins. Including *Pluggable* adds several methods:
4
+
5
+ [*install_plugins*] Should generally be called when initializing an instance of the Pluggable class.
6
+ [*plugins*] After initialization, returns a list of plugin instances
7
+
8
+ For example:
4
9
 
5
10
  require 'rubygems'
6
11
  require 'pluggable'
@@ -20,8 +25,7 @@ Pluggable is a mixin for classes requiring plugins. A pluggable class, +Klass+,
20
25
 
21
26
  Test.new.process # => ["foo", "bar"]
22
27
 
23
- It may be convenient to have public methods of plugins delegated to from the +plugins+ object, which may in turn be delgated to by the +Pluggable+ class in various ways. For example:
24
-
28
+ It may be convenient to have public methods of plugins delegated to from the +plugins+ object, which may in turn be delgated to by the +Pluggable+ class in various ways. This is accomplished with the class method *delegate_plugin_public_methods_except*, which should be called after loading all of the plugins. For example:
25
29
 
26
30
  require 'rubygems'
27
31
  require 'pluggable'
@@ -42,11 +46,45 @@ It may be convenient to have public methods of plugins delegated to from the +pl
42
46
  end
43
47
 
44
48
  Test.delegate_plugin_public_methods_except :process
45
-
46
49
 
47
50
  Test.new.process # => ["foo", "bar"]
48
- Test.new.plugins.foo = "foo"
49
- Test.new.plugins.bar = "bar"
51
+ Test.new.plugins.foo # => "foo"
52
+ Test.new.plugins.bar # => "bar"
53
+
54
+ Finally, it may be useful to establish an API for plugins in the form of a traditional Ruby module. The module may be included into the plugins using the class method *plugin_install_methods, which may be called in the Pluggable class definition. For example:
55
+
56
+ require 'rubygems'
57
+ require 'pluggable'
58
+ module PluginAPI
59
+ def first; "first"; end
60
+ def second; private_second; end
61
+ module ClassMethods
62
+ def class_first; "class_first"; end
63
+ end
64
+ private
65
+ def private_second; "second"; end
66
+ def self.included(klass)
67
+ klass.extend ClassMethods
68
+ end
69
+ end
70
+
71
+ class Test
72
+ include Pluggable
73
+ def initialize; install_plugins; end
74
+ def process; plugins.map {|plugin| plugin.process}; end
75
+ private
76
+ def method_missing symbol, *args
77
+ plugins.send(symbol, *args)
78
+ end
79
+ end
80
+
81
+ require 'plugin_definitions'
82
+
83
+ Test.new.plugins.first.first # => "first"
84
+ Test.new.plugins.first.second # => "second"
85
+ Test.new.plugins.first.class.class_first # => "class_first"
86
+
87
+ And of course, the plugins may override the API definitions.
50
88
 
51
89
  == Note on Patches/Pull Requests
52
90
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
data/lib/pluggable.rb CHANGED
@@ -65,5 +65,8 @@ module Pluggable
65
65
  def delegate_plugin_public_methods_except *excluded_methods
66
66
  PluginFactory.instance.delegate_plugin_public_methods_to_plugins_class_except *excluded_methods
67
67
  end
68
+ def plugin_include_module mod
69
+ Plugin.class_eval "include #{mod.to_s}"
70
+ end
68
71
  end
69
72
  end
data/pluggable.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{pluggable}
8
- s.version = "0.1.1"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Andrew C. Greenberg"]
@@ -1,8 +1,22 @@
1
1
  require 'forwardable'
2
2
  require File.dirname(__FILE__) + '/spec_helper.rb'
3
3
 
4
+ module PluginAPI
5
+ def first; "first"; end
6
+ def second; private_second; end
7
+ module ClassMethods
8
+ def class_first; "class_first"; end
9
+ end
10
+ private
11
+ def private_second; "second"; end
12
+ def self.included(klass)
13
+ klass.extend ClassMethods
14
+ end
15
+ end
16
+
4
17
  class Test
5
18
  include Pluggable
19
+ plugin_include_module PluginAPI
6
20
  def process
7
21
  plugins.map{|each| each.process}
8
22
  end
@@ -49,7 +63,15 @@ describe Pluggable, "when included in a class" do
49
63
  Test.plugin_factory.should have(3).items
50
64
  Test.plugin_factory.should include(Plugin1, Plugin2, Plugin3)
51
65
  end
66
+
67
+ it "should install a class method #delegate_plugin_public_methods_except" do
68
+ Test.should respond_to(:delegate_plugin_public_methods_except)
69
+ end
52
70
 
71
+ it "should install a class method #plugin_include_module" do
72
+ Test.should respond_to(:plugin_include_module)
73
+ end
74
+
53
75
  it "should add a method #plugins that should be nil upon creation" do
54
76
  @test_instance.should respond_to(:plugins)
55
77
  @test_instance.plugins.should be_nil
@@ -58,10 +80,6 @@ describe Pluggable, "when included in a class" do
58
80
  it "should add a method #install_plugins" do
59
81
  Test.new.should respond_to(:install_plugins)
60
82
  end
61
-
62
- it "should install a class method #delegate_plugin_public_methods_except" do
63
- Test.should respond_to(:delegate_plugin_public_methods_except)
64
- end
65
83
  end
66
84
 
67
85
  describe Pluggable, "after installing plugins" do
@@ -113,6 +131,16 @@ describe Pluggable, "after Test has delegated all but excepted plugin public met
113
131
  end
114
132
  end
115
133
 
134
+ describe Test::Plugin, "after Test has included a module" do
135
+ it "should have the instance methods of the module" do
136
+ Test::Plugin.instance_methods.should include(*PluginAPI.instance_methods)
137
+ end
138
+
139
+ it "should have the class methods of the module" do
140
+ Test::Plugin.methods.should include(*PluginAPI::ClassMethods.instance_methods)
141
+ end
142
+ end
143
+
116
144
  describe Test::PluginFactory, "instances" do
117
145
  before(:each) do
118
146
  @instance = Test::PluginFactory.instance
@@ -132,7 +160,6 @@ describe Test::PluginFactory, "instances" do
132
160
  end
133
161
 
134
162
  describe Test, "when using message_missing to simulate delegation from the parent" do
135
-
136
163
  before(:each) do
137
164
  @test_instance = Test.new
138
165
  @test_instance.install_plugins
@@ -147,4 +174,10 @@ describe Test, "when using message_missing to simulate delegation from the paren
147
174
  @test_instance.bar.should == "bar"
148
175
  @test_instance.baz.should == "baz"
149
176
  end
177
+
178
+ it "should work with included module procedures" do
179
+ @test_instance.plugins.first.first.should == "first"
180
+ @test_instance.plugins.first.second.should == "second"
181
+ @test_instance.plugins.first.class.class_first.should == "class_first"
182
+ end
150
183
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wizardwerdna-pluggable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew C. Greenberg