pluggability 0.0.1

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