wizardwerdna-pluggable 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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