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 +44 -6
- data/VERSION +1 -1
- data/lib/pluggable.rb +3 -0
- data/pluggable.gemspec +1 -1
- data/spec/pluggable_spec.rb +38 -5
- metadata +1 -1
data/README.rdoc
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
= pluggable
|
2
2
|
|
3
|
-
Pluggable is a mixin for classes requiring plugins.
|
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
|
49
|
-
Test.new.plugins.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
|
+
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
data/spec/pluggable_spec.rb
CHANGED
@@ -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
|