pluggability 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/.gemtest +0 -0
- data/ChangeLog +690 -0
- data/History.rdoc +4 -0
- data/Manifest.txt +8 -0
- data/README.rdoc +237 -0
- data/Rakefile +31 -0
- data/lib/pluggability.rb +343 -0
- data/spec/lib/helpers.rb +31 -0
- data/spec/pluggability_spec.rb +198 -0
- metadata +212 -0
- metadata.gz.sig +1 -0
data/spec/lib/helpers.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent
|
7
|
+
|
8
|
+
libdir = basedir + "lib"
|
9
|
+
|
10
|
+
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
11
|
+
}
|
12
|
+
|
13
|
+
require 'rspec'
|
14
|
+
require 'loggability/spechelpers'
|
15
|
+
require 'pluggability'
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
### Mock with Rspec
|
20
|
+
RSpec.configure do |config|
|
21
|
+
ruby_version_vec = RUBY_VERSION.split('.').map {|c| c.to_i }.pack( "N*" )
|
22
|
+
|
23
|
+
config.include( Loggability::SpecHelpers )
|
24
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
25
|
+
|
26
|
+
config.mock_with :rspec
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
# vim: set nosta noet ts=4 sw=4:
|
31
|
+
|
@@ -0,0 +1,198 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
BEGIN {
|
4
|
+
require 'pathname'
|
5
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent
|
6
|
+
|
7
|
+
libdir = basedir + "lib"
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
|
10
|
+
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
11
|
+
}
|
12
|
+
|
13
|
+
require 'rspec'
|
14
|
+
require 'logger'
|
15
|
+
require 'pluggability'
|
16
|
+
|
17
|
+
require 'spec/lib/helpers'
|
18
|
+
|
19
|
+
class Plugin
|
20
|
+
extend Pluggability
|
21
|
+
plugin_prefixes 'plugins', 'plugins/private'
|
22
|
+
end
|
23
|
+
|
24
|
+
class SubPlugin < Plugin; end
|
25
|
+
class TestingPlugin < Plugin; end
|
26
|
+
class BlackSheep < Plugin; end
|
27
|
+
module Test
|
28
|
+
class LoadablePlugin < Plugin; end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
describe Pluggability do
|
33
|
+
|
34
|
+
before( :each ) do
|
35
|
+
setup_logging( :fatal )
|
36
|
+
end
|
37
|
+
|
38
|
+
after( :each ) do
|
39
|
+
reset_logging()
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
it "allows extended objects to declare one or more prefixes to use when requiring derviatives" do
|
44
|
+
Plugin.plugin_prefixes.should == ['plugins', 'plugins/private']
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
context "-extended class" do
|
50
|
+
|
51
|
+
it "knows about all of its derivatives" do
|
52
|
+
Plugin.derivatives.keys.should include( 'sub' )
|
53
|
+
Plugin.derivatives.keys.should include( 'subplugin' )
|
54
|
+
Plugin.derivatives.keys.should include( 'SubPlugin' )
|
55
|
+
Plugin.derivatives.keys.should include( SubPlugin )
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns derivatives directly if they're already loaded" do
|
59
|
+
class AlreadyLoadedPlugin < Plugin; end
|
60
|
+
Kernel.should_not_receive( :require )
|
61
|
+
Plugin.create( 'alreadyloaded' ).should be_an_instance_of( AlreadyLoadedPlugin )
|
62
|
+
Plugin.create( 'AlreadyLoaded' ).should be_an_instance_of( AlreadyLoadedPlugin )
|
63
|
+
Plugin.create( 'AlreadyLoadedPlugin' ).should be_an_instance_of( AlreadyLoadedPlugin )
|
64
|
+
Plugin.create( AlreadyLoadedPlugin ).should be_an_instance_of( AlreadyLoadedPlugin )
|
65
|
+
end
|
66
|
+
|
67
|
+
it "filters errors that happen when creating an instance of derivatives so they " +
|
68
|
+
"point to the right place" do
|
69
|
+
class PugilistPlugin < Plugin
|
70
|
+
def initialize
|
71
|
+
raise "Oh noes -- an error!"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
exception = nil
|
76
|
+
begin
|
77
|
+
Plugin.create('pugilist')
|
78
|
+
rescue ::RuntimeError => err
|
79
|
+
exception = err
|
80
|
+
else
|
81
|
+
fail "Expected an exception to be raised."
|
82
|
+
end
|
83
|
+
|
84
|
+
exception.backtrace.first.should =~ /#{__FILE__}/
|
85
|
+
end
|
86
|
+
|
87
|
+
it "will refuse to create an object other than one of its derivatives" do
|
88
|
+
class Doppelgaenger; end
|
89
|
+
expect {
|
90
|
+
Plugin.create(Doppelgaenger)
|
91
|
+
}.to raise_error( ArgumentError, /is not a descendent of/ )
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
it "will load new plugins from the require path if they're not loaded yet" do
|
96
|
+
loaded_class = nil
|
97
|
+
|
98
|
+
Plugin.should_receive( :require ).with( 'plugins/dazzle_plugin' ).and_return do |*args|
|
99
|
+
loaded_class = Class.new( Plugin )
|
100
|
+
# Simulate a named class, since we're not really requiring
|
101
|
+
Plugin.derivatives['dazzle'] = loaded_class
|
102
|
+
true
|
103
|
+
end
|
104
|
+
|
105
|
+
Plugin.create( 'dazzle' ).should be_an_instance_of( loaded_class )
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
it "will output a sensible description of what it tried to load if requiring a " +
|
110
|
+
"derivative fails" do
|
111
|
+
|
112
|
+
# at least 6 -> 3 variants * 2 paths
|
113
|
+
Plugin.should_receive( :require ).
|
114
|
+
at_least(6).times.
|
115
|
+
and_return {|path| raise LoadError, "path" }
|
116
|
+
|
117
|
+
expect {
|
118
|
+
Plugin.create('scintillating')
|
119
|
+
}.to raise_error( Pluggability::FactoryError, /couldn't find a \S+ named \S+.*tried \[/i )
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
it "will output a sensible description when a require succeeds, but it loads something unintended" do
|
124
|
+
# at least 6 -> 3 variants * 2 paths
|
125
|
+
Plugin.should_receive( :require ).and_return( true )
|
126
|
+
|
127
|
+
expect {
|
128
|
+
Plugin.create('corruscating')
|
129
|
+
}.to raise_error( Pluggability::FactoryError, /Require of '\S+' succeeded, but didn't load a Plugin/i )
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
it "will re-raise the first exception raised when attempting to load a " +
|
134
|
+
"derivative if none of the paths work" do
|
135
|
+
|
136
|
+
# at least 6 -> 3 variants * 2 paths
|
137
|
+
Plugin.should_receive( :require ).at_least(6).times.and_return {|path|
|
138
|
+
raise ScriptError, "error while parsing #{path}"
|
139
|
+
}
|
140
|
+
|
141
|
+
expect {
|
142
|
+
Plugin.create('portable')
|
143
|
+
}.to raise_error( ScriptError, /error while parsing/ )
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
it "can preload all of its derivatives" do
|
148
|
+
Gem.should_receive( :find_files ).with( 'plugins/*.rb' ).
|
149
|
+
and_return([ 'plugins/first.rb' ])
|
150
|
+
Gem.should_receive( :find_files ).with( 'plugins/private/*.rb' ).
|
151
|
+
and_return([ 'plugins/private/second.rb', 'plugins/private/third.rb' ])
|
152
|
+
|
153
|
+
Plugin.should_receive( :require ).with( 'plugins/first.rb' ).
|
154
|
+
and_return( true )
|
155
|
+
Plugin.should_receive( :require ).with( 'plugins/private/second.rb' ).
|
156
|
+
and_return( true )
|
157
|
+
Plugin.should_receive( :require ).with( 'plugins/private/third.rb' ).
|
158
|
+
and_return( true )
|
159
|
+
|
160
|
+
Plugin.load_all
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
context "derivative of an extended class" do
|
166
|
+
|
167
|
+
it "knows what type of factory loads it" do
|
168
|
+
TestingPlugin.factory_type.should == 'Plugin'
|
169
|
+
end
|
170
|
+
|
171
|
+
it "raises a FactoryError if it can't figure out what type of factory loads it" do
|
172
|
+
TestingPlugin.stub!( :ancestors ).and_return( [] )
|
173
|
+
expect {
|
174
|
+
TestingPlugin.factory_type
|
175
|
+
}.to raise_error( Pluggability::FactoryError, /couldn't find factory base/i )
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
context "derivative of an extended class that isn't named <Something>Plugin" do
|
181
|
+
|
182
|
+
it "is still creatable via its full name" do
|
183
|
+
Plugin.create( 'blacksheep' ).should be_an_instance_of( BlackSheep )
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
context "derivative of an extended class in another namespace" do
|
190
|
+
|
191
|
+
it "is still creatable via its derivative name" do
|
192
|
+
Plugin.create( 'loadable' ).should be_an_instance_of( Test::LoadablePlugin )
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
metadata
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pluggability
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Martin Chase
|
9
|
+
- Michael Granger
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain:
|
13
|
+
- !binary |-
|
14
|
+
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURMRENDQWhTZ0F3SUJB
|
15
|
+
Z0lCQURBTkJna3Foa2lHOXcwQkFRVUZBREE4TVF3d0NnWURWUVFEREFOblpX
|
16
|
+
UXgKRnpBVkJnb0praWFKay9Jc1pBRVpGZ2RmWVdWeWFXVmZNUk13RVFZS0Na
|
17
|
+
SW1pWlB5TEdRQkdSWURiM0puTUI0WApEVEV3TURreE5qRTBORGcxTVZvWERU
|
18
|
+
RXhNRGt4TmpFME5EZzFNVm93UERFTU1Bb0dBMVVFQXd3RFoyVmtNUmN3CkZR
|
19
|
+
WUtDWkltaVpQeUxHUUJHUllIWDJGbGNtbGxYekVUTUJFR0NnbVNKb21UOGl4
|
20
|
+
a0FSa1dBMjl5WnpDQ0FTSXcKRFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURD
|
21
|
+
Q0FRb0NnZ0VCQUx5Ly9CRnhDMWYvY1BTbnd0SkJXb0ZpRnJpcgpoN1JpY0kr
|
22
|
+
am9xL29jVlhRcUk0VERXUHlGLzh0cWt2dCtyRDk5WDlxczJZZVI4Q1UvWWlJ
|
23
|
+
cExXclFPWVNUNzBKCnZEbjdVdmhiMm11RlZxcTYrdm9iZVRrSUxCRU82cGlv
|
24
|
+
bldERzhqU2JvM3FLbTFSaktKRHdnOXA0d05LaFB1dTgKS0d1ZS9CRmI2N0tm
|
25
|
+
bHF5QXBQbVBlYjNWZGQ5Y2xzcHpxZUZxcDdjVUJNRXBGUzZMV3h5NEdrK3F2
|
26
|
+
RkZKQkpMQgpCVUhFL0xaVkpNVnpmcEM1VXErUW1ZN0IrRkgvUXFObmRuM3RP
|
27
|
+
SGdzUGFkTFROaW11QjFzQ3VMMWE0ejNQZXBkClRlTEJFRm1FYW81RGszSy9R
|
28
|
+
OG84dmxiSUIvakJEVFV4NkRqYmd4dzc3OTA5eDZnSTlkb1U0TEQ1WE1jQ0F3
|
29
|
+
RUEKQWFNNU1EY3dDUVlEVlIwVEJBSXdBREFMQmdOVkhROEVCQU1DQkxBd0hR
|
30
|
+
WURWUjBPQkJZRUZKZW9Ha09yOWw0Qgorc2FNa1cvWlhUNFVlU3ZWTUEwR0NT
|
31
|
+
cUdTSWIzRFFFQkJRVUFBNElCQVFCRzJLT2J2WUkyZUh5eUJVSlNKM2pOCnZF
|
32
|
+
blUzZDYwem5BWGJyU2QycWIzcjFsWTFFUEREM2JjeTBNZ2dDZkdkZzNYdTU0
|
33
|
+
ejIxb3F5SWRrOHVHdFdCUEwKSElhOUVnZkZHU1VFZ3ZjSXZhWXFpTjRqVFV0
|
34
|
+
aWRmRUZ3K0x0anM4QVA5Z1dnU0lZUzZHcjM4VjBXR0ZGTnpJSAphT0Qyd211
|
35
|
+
OW9vL1JmZlc0aFMvOEd1dmZNemN3N0NRMzU1d0ZSNEtCL255emUrRXNaMVk1
|
36
|
+
RGVyQ0FhZ01WdURRClUwQkxtV0RGelBHR1dsUGVRQ3JZSENyK0FjSnorTlJu
|
37
|
+
YUhDS0xaZFNLai9SSHVUT3QrZ2JsUmV4OEZBaDhOZUEKY21saFhlNDZwWk5K
|
38
|
+
Z1dLYnhaYWg4NWpJang5NWhSOHZPSStOQU01aUg5a09xSzEzRHJ4YWNUS1Bo
|
39
|
+
cWo1UGp3RgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
40
|
+
date: 2012-08-03 00:00:00.000000000 Z
|
41
|
+
dependencies:
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: loggability
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ~>
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0.5'
|
50
|
+
type: :runtime
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ~>
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0.5'
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: hoe-mercurial
|
60
|
+
requirement: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 1.4.0
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ~>
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 1.4.0
|
74
|
+
- !ruby/object:Gem::Dependency
|
75
|
+
name: hoe-highline
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ~>
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 0.1.0
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.1.0
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: rdoc
|
92
|
+
requirement: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ~>
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '3.10'
|
98
|
+
type: :development
|
99
|
+
prerelease: false
|
100
|
+
version_requirements: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ~>
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '3.10'
|
106
|
+
- !ruby/object:Gem::Dependency
|
107
|
+
name: hoe-deveiate
|
108
|
+
requirement: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ~>
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0.1'
|
114
|
+
type: :development
|
115
|
+
prerelease: false
|
116
|
+
version_requirements: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ~>
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0.1'
|
122
|
+
- !ruby/object:Gem::Dependency
|
123
|
+
name: hoe
|
124
|
+
requirement: !ruby/object:Gem::Requirement
|
125
|
+
none: false
|
126
|
+
requirements:
|
127
|
+
- - ~>
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '3.0'
|
130
|
+
type: :development
|
131
|
+
prerelease: false
|
132
|
+
version_requirements: !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ~>
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '3.0'
|
138
|
+
description: ! 'Pluggability is a mixin module that turns an including class into
|
139
|
+
a factory for
|
140
|
+
|
141
|
+
its derivatives, capable of searching for and loading them by name. This is
|
142
|
+
|
143
|
+
useful when you have an abstract base class which defines an interface and basic
|
144
|
+
|
145
|
+
functionality for a part of a larger system, and a collection of subclasses
|
146
|
+
|
147
|
+
which implement the interface for different underlying functionality.
|
148
|
+
|
149
|
+
|
150
|
+
An example of where this might be useful is in a program which talks to a
|
151
|
+
|
152
|
+
database. To avoid coupling it to a specific database, you use a Driver class
|
153
|
+
|
154
|
+
which encapsulates your program''s interaction with the database behind a useful
|
155
|
+
|
156
|
+
interface. Now you can create a concrete implementation of the Driver class for
|
157
|
+
|
158
|
+
each kind of database you wish to talk to. If you make the base Driver class a
|
159
|
+
|
160
|
+
Pluggability, too, you can add new drivers simply by dropping them in a
|
161
|
+
|
162
|
+
directory and using the Driver''s `create` method to instantiate them:'
|
163
|
+
email:
|
164
|
+
- stillflame@FaerieMUD.org
|
165
|
+
- ged@FaerieMUD.org
|
166
|
+
executables: []
|
167
|
+
extensions: []
|
168
|
+
extra_rdoc_files:
|
169
|
+
- History.rdoc
|
170
|
+
- Manifest.txt
|
171
|
+
- README.rdoc
|
172
|
+
files:
|
173
|
+
- ChangeLog
|
174
|
+
- History.rdoc
|
175
|
+
- Manifest.txt
|
176
|
+
- README.rdoc
|
177
|
+
- Rakefile
|
178
|
+
- lib/pluggability.rb
|
179
|
+
- spec/lib/helpers.rb
|
180
|
+
- spec/pluggability_spec.rb
|
181
|
+
- .gemtest
|
182
|
+
homepage: http://deveiate.org/projects/Pluggability
|
183
|
+
licenses:
|
184
|
+
- BSD
|
185
|
+
post_install_message:
|
186
|
+
rdoc_options:
|
187
|
+
- -f
|
188
|
+
- fivefish
|
189
|
+
- -t
|
190
|
+
- Pluggability Toolkit
|
191
|
+
require_paths:
|
192
|
+
- lib
|
193
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
194
|
+
none: false
|
195
|
+
requirements:
|
196
|
+
- - ! '>='
|
197
|
+
- !ruby/object:Gem::Version
|
198
|
+
version: '0'
|
199
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
200
|
+
none: false
|
201
|
+
requirements:
|
202
|
+
- - ! '>='
|
203
|
+
- !ruby/object:Gem::Version
|
204
|
+
version: '0'
|
205
|
+
requirements: []
|
206
|
+
rubyforge_project: pluggability
|
207
|
+
rubygems_version: 1.8.24
|
208
|
+
signing_key:
|
209
|
+
specification_version: 3
|
210
|
+
summary: Pluggability is a mixin module that turns an including class into a factory
|
211
|
+
for its derivatives, capable of searching for and loading them by name
|
212
|
+
test_files: []
|
metadata.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
�.�(,�����}����D�����Y�9�1�ڑ�ղ^��T1n˿���v�7�L�`!v~�<p�#�"�)Ir=�J��/����^�L]ʴW��cWO(v�<�<l8O��oո��P�����B��қ����^0C3�i�X4N��I�E���kS�������qhW���M��S���f��F?���l���,i �0�4����*������wF8Z��dI�K�.�C�Z/�Ï.1O�c�k
|