fabrique 0.0.0 → 0.0.1
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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/Gemfile +5 -0
- data/Guardfile +9 -0
- data/README.md +152 -3
- data/Rakefile +11 -3
- data/config/cucumber.yml +2 -0
- data/constructors +70 -0
- data/docs/autowiring.yml +23 -0
- data/docs/multiple_providers.rb +104 -0
- data/fabrique.gemspec +3 -0
- data/features/bean_factory.feature +295 -0
- data/features/plugin_registry.feature +79 -0
- data/features/step_definitions/bean_factory_steps.rb +73 -0
- data/features/step_definitions/plugin_registry_steps.rb +207 -0
- data/features/support/byebug.rb +4 -0
- data/lib/fabrique/argument_adaptor/keyword.rb +19 -0
- data/lib/fabrique/argument_adaptor/positional.rb +76 -0
- data/lib/fabrique/bean_definition.rb +46 -0
- data/lib/fabrique/bean_definition_registry.rb +43 -0
- data/lib/fabrique/bean_factory.rb +78 -0
- data/lib/fabrique/bean_reference.rb +13 -0
- data/lib/fabrique/construction/as_is.rb +16 -0
- data/lib/fabrique/construction/builder_method.rb +21 -0
- data/lib/fabrique/construction/default.rb +17 -0
- data/lib/fabrique/construction/keyword_argument.rb +16 -0
- data/lib/fabrique/construction/positional_argument.rb +40 -0
- data/lib/fabrique/construction/properties_hash.rb +19 -0
- data/lib/fabrique/constructor/identity.rb +10 -0
- data/lib/fabrique/cyclic_bean_dependency_error.rb +6 -0
- data/lib/fabrique/plugin_registry.rb +56 -0
- data/lib/fabrique/test/fixtures/constructors.rb +81 -0
- data/lib/fabrique/test/fixtures/modules.rb +35 -0
- data/lib/fabrique/test/fixtures/opengl.rb +37 -0
- data/lib/fabrique/test/fixtures/repository.rb +139 -0
- data/lib/fabrique/test.rb +8 -0
- data/lib/fabrique/version.rb +1 -1
- data/lib/fabrique/yaml_bean_factory.rb +42 -0
- data/lib/fabrique.rb +4 -2
- data/spec/fabrique/argument_adaptor/keyword_spec.rb +50 -0
- data/spec/fabrique/argument_adaptor/positional_spec.rb +166 -0
- data/spec/fabrique/construction/as_is_spec.rb +23 -0
- data/spec/fabrique/construction/builder_method_spec.rb +29 -0
- data/spec/fabrique/construction/default_spec.rb +19 -0
- data/spec/fabrique/construction/positional_argument_spec.rb +61 -0
- data/spec/fabrique/construction/properties_hash_spec.rb +36 -0
- data/spec/fabrique/constructor/identity_spec.rb +4 -0
- data/spec/fabrique/plugin_registry_spec.rb +78 -0
- data/spec/fabrique_spec.rb +0 -4
- metadata +72 -4
@@ -0,0 +1,295 @@
|
|
1
|
+
@bean_factory
|
2
|
+
Feature: Bean Factory
|
3
|
+
|
4
|
+
As a developer
|
5
|
+
I want injectable dependencies to be a configuration concern
|
6
|
+
So that I can configure different dependencies in different environments.
|
7
|
+
|
8
|
+
Scenario: Simple object with default constructor
|
9
|
+
|
10
|
+
Given I have a YAML application context definition:
|
11
|
+
"""
|
12
|
+
---
|
13
|
+
beans: !beans
|
14
|
+
- !bean
|
15
|
+
id: simple_object
|
16
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithDefaultConstructor
|
17
|
+
"""
|
18
|
+
When I request a bean factory for the application context
|
19
|
+
And I request the "simple_object" bean from the bean factory
|
20
|
+
Then the bean has "size" set to "default size"
|
21
|
+
And the bean has "color" set to "default color"
|
22
|
+
And the bean has "shape" set to "default shape"
|
23
|
+
|
24
|
+
Scenario: Simple object with positional argument constructor
|
25
|
+
|
26
|
+
Given I have a YAML application context definition:
|
27
|
+
"""
|
28
|
+
---
|
29
|
+
beans:
|
30
|
+
- id: simple_object
|
31
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithPositionalArgumentConstructor
|
32
|
+
constructor_args:
|
33
|
+
- small
|
34
|
+
- red
|
35
|
+
- dot
|
36
|
+
"""
|
37
|
+
When I request a bean factory for the application context
|
38
|
+
And I request the "simple_object" bean from the bean factory
|
39
|
+
Then the bean has "size" set to "small"
|
40
|
+
And the bean has "color" set to "red"
|
41
|
+
And the bean has "shape" set to "dot"
|
42
|
+
|
43
|
+
Scenario: Simple object with keyword argument constructor
|
44
|
+
|
45
|
+
Given I have a YAML application context definition:
|
46
|
+
"""
|
47
|
+
---
|
48
|
+
beans:
|
49
|
+
- id: simple_object
|
50
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithKeywordArgumentConstructor
|
51
|
+
constructor_args:
|
52
|
+
size: large
|
53
|
+
color: black
|
54
|
+
shape: hole
|
55
|
+
"""
|
56
|
+
When I request a bean factory for the application context
|
57
|
+
And I request the "simple_object" bean from the bean factory
|
58
|
+
Then the bean has "size" set to "large"
|
59
|
+
And the bean has "color" set to "black"
|
60
|
+
And the bean has "shape" set to "hole"
|
61
|
+
|
62
|
+
|
63
|
+
Scenario: Simple object with hash properties constructor
|
64
|
+
|
65
|
+
Given I have a YAML application context definition:
|
66
|
+
"""
|
67
|
+
---
|
68
|
+
beans:
|
69
|
+
- id: simple_object
|
70
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithPropertiesHashConstructor
|
71
|
+
constructor_args:
|
72
|
+
size: tiny
|
73
|
+
color: purple
|
74
|
+
shape: elephant
|
75
|
+
"""
|
76
|
+
When I request a bean factory for the application context
|
77
|
+
And I request the "simple_object" bean from the bean factory
|
78
|
+
Then the bean has "size" set to "tiny"
|
79
|
+
And the bean has "color" set to "purple"
|
80
|
+
And the bean has "shape" set to "elephant"
|
81
|
+
|
82
|
+
Scenario: Module by identity
|
83
|
+
|
84
|
+
Given I have a YAML application context definition:
|
85
|
+
"""
|
86
|
+
---
|
87
|
+
beans:
|
88
|
+
- id: my_module
|
89
|
+
class: Fabrique::Test::Fixtures::Modules::ModuleWithStaticMethods
|
90
|
+
factory_method: itself
|
91
|
+
"""
|
92
|
+
When I request a bean factory for the application context
|
93
|
+
And I request the "my_module" bean from the bean factory
|
94
|
+
Then the bean has "size" set to "module size"
|
95
|
+
And the bean has "color" set to "module color"
|
96
|
+
And the bean has "shape" set to "module shape"
|
97
|
+
|
98
|
+
Scenario: Bean reference
|
99
|
+
|
100
|
+
Given I have a YAML application context definition:
|
101
|
+
"""
|
102
|
+
---
|
103
|
+
beans:
|
104
|
+
- id: customer_repository
|
105
|
+
class: Fabrique::Test::Fixtures::Repository::CustomerRepository
|
106
|
+
constructor_args:
|
107
|
+
- !bean/ref store
|
108
|
+
- !bean/ref customer_data_mapper
|
109
|
+
- id: product_repository
|
110
|
+
class: Fabrique::Test::Fixtures::Repository::ProductRepository
|
111
|
+
constructor_args:
|
112
|
+
store: !bean/ref store
|
113
|
+
data_mapper: !bean/ref product_data_mapper
|
114
|
+
- id: store
|
115
|
+
class: Fabrique::Test::Fixtures::Repository::MysqlStore
|
116
|
+
constructor_args:
|
117
|
+
host: localhost
|
118
|
+
port: 3306
|
119
|
+
- id: customer_data_mapper
|
120
|
+
class: Fabrique::Test::Fixtures::Repository::CustomerDataMapper
|
121
|
+
scope: prototype
|
122
|
+
- id: product_data_mapper
|
123
|
+
class: Fabrique::Test::Fixtures::Repository::ProductDataMapper
|
124
|
+
scope: prototype
|
125
|
+
"""
|
126
|
+
When I request a bean factory for the application context
|
127
|
+
Then the "customer_repository" and "product_repository" beans share the same "store"
|
128
|
+
And the "customer_repository" and "product_repository" beans each have their own "data_mapper"
|
129
|
+
|
130
|
+
Scenario: Cyclic bean property reference
|
131
|
+
|
132
|
+
Given I have a YAML application context definition:
|
133
|
+
"""
|
134
|
+
---
|
135
|
+
beans:
|
136
|
+
- id: left
|
137
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithProperties
|
138
|
+
properties:
|
139
|
+
shape: !bean/ref right
|
140
|
+
- id: right
|
141
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithProperties
|
142
|
+
properties:
|
143
|
+
shape: !bean/ref left
|
144
|
+
"""
|
145
|
+
Then I get a cyclic bean dependency error when I request a bean factory for the application context
|
146
|
+
|
147
|
+
Scenario: Cyclic bean constructor arg reference
|
148
|
+
|
149
|
+
Given I have a YAML application context definition:
|
150
|
+
"""
|
151
|
+
---
|
152
|
+
beans:
|
153
|
+
- id: left
|
154
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithPositionalArgumentConstructor
|
155
|
+
constructor_args:
|
156
|
+
- !bean/ref right
|
157
|
+
- red
|
158
|
+
- dot
|
159
|
+
- id: right
|
160
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithPositionalArgumentConstructor
|
161
|
+
constructor_args:
|
162
|
+
- !bean/ref left
|
163
|
+
- purple
|
164
|
+
- elephant
|
165
|
+
"""
|
166
|
+
Then I get a cyclic bean dependency error when I request a bean factory for the application context
|
167
|
+
|
168
|
+
Scenario: Cyclic bean property reference with non-cyclic constructor arg reference
|
169
|
+
|
170
|
+
Given I have a YAML application context definition:
|
171
|
+
"""
|
172
|
+
---
|
173
|
+
beans:
|
174
|
+
- id: left
|
175
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithKeywordArgumentConstructor
|
176
|
+
constructor_args:
|
177
|
+
shape: !bean/ref middle
|
178
|
+
- id: middle
|
179
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithKeywordArgumentConstructor
|
180
|
+
constructor_args:
|
181
|
+
shape: !bean/ref right
|
182
|
+
- id: right
|
183
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithProperties
|
184
|
+
properties:
|
185
|
+
shape: !bean/ref left
|
186
|
+
"""
|
187
|
+
Then I get a cyclic bean dependency error when I request a bean factory for the application context
|
188
|
+
|
189
|
+
Scenario: Nested bean references
|
190
|
+
|
191
|
+
Given I have a YAML application context definition:
|
192
|
+
"""
|
193
|
+
---
|
194
|
+
beans:
|
195
|
+
- id: disco_cube
|
196
|
+
class: Fabrique::Test::Fixtures::OpenGL::Object
|
197
|
+
constructor_args:
|
198
|
+
- glittering
|
199
|
+
- :mesh: !bean/ref cube_mesh
|
200
|
+
:scale: 10
|
201
|
+
- id: cube_mesh
|
202
|
+
class: Fabrique::Test::Fixtures::OpenGL::Mesh
|
203
|
+
constructor_args:
|
204
|
+
- [[0, 0, 0],[1, 0, 0],[1, 0, 1],[0, 0, 1],[0, 1, 0],[1, 1, 0],[1, 1, 1],[0, 1, 1]]
|
205
|
+
"""
|
206
|
+
When I request a bean factory for the application context
|
207
|
+
And I request the "disco_cube" bean from the bean factory
|
208
|
+
Then the "disco_cube" bean has "mesh" set to the "cube_mesh" bean
|
209
|
+
And the "disco_cube" bean has "scale" that is the Integer 10
|
210
|
+
|
211
|
+
Scenario: Singleton bean (default)
|
212
|
+
|
213
|
+
Given I have a YAML application context definition:
|
214
|
+
"""
|
215
|
+
---
|
216
|
+
beans:
|
217
|
+
- id: simple_object
|
218
|
+
scope: singleton
|
219
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithDefaultConstructor
|
220
|
+
"""
|
221
|
+
When I request a bean factory for the application context
|
222
|
+
And I request the "simple_object" bean from the bean factory
|
223
|
+
Then I get the same object when I request the "simple_object" bean again
|
224
|
+
|
225
|
+
Scenario: Prototype bean
|
226
|
+
|
227
|
+
Given I have a YAML application context definition:
|
228
|
+
"""
|
229
|
+
---
|
230
|
+
beans:
|
231
|
+
- id: simple_object
|
232
|
+
scope: prototype
|
233
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithDefaultConstructor
|
234
|
+
"""
|
235
|
+
When I request a bean factory for the application context
|
236
|
+
And I request the "simple_object" bean from the bean factory
|
237
|
+
Then I get a different object when I request the "simple_object" bean again
|
238
|
+
|
239
|
+
Scenario: Setter injection
|
240
|
+
|
241
|
+
Given I have a YAML application context definition:
|
242
|
+
"""
|
243
|
+
---
|
244
|
+
beans:
|
245
|
+
- id: simple_object
|
246
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithProperties
|
247
|
+
properties:
|
248
|
+
size: large
|
249
|
+
color: blue
|
250
|
+
shape: square
|
251
|
+
"""
|
252
|
+
When I request a bean factory for the application context
|
253
|
+
And I request the "simple_object" bean from the bean factory
|
254
|
+
Then the bean has "size" set to "large"
|
255
|
+
And the bean has "color" set to "blue"
|
256
|
+
And the bean has "shape" set to "square"
|
257
|
+
|
258
|
+
Scenario: Constructor argument type
|
259
|
+
|
260
|
+
Given I have a YAML application context definition:
|
261
|
+
"""
|
262
|
+
---
|
263
|
+
beans:
|
264
|
+
- id: simple_object
|
265
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithPositionalArgumentConstructor
|
266
|
+
constructor_args:
|
267
|
+
- infinite
|
268
|
+
- invisible
|
269
|
+
- 42
|
270
|
+
"""
|
271
|
+
When I request a bean factory for the application context
|
272
|
+
And I request the "simple_object" bean from the bean factory
|
273
|
+
Then the bean has "size" set to "infinite"
|
274
|
+
And the bean has "color" set to "invisible"
|
275
|
+
And the bean has "shape" that is the Integer "42"
|
276
|
+
|
277
|
+
Scenario: Property argument type
|
278
|
+
|
279
|
+
Given I have a YAML application context definition:
|
280
|
+
"""
|
281
|
+
---
|
282
|
+
beans:
|
283
|
+
- id: simple_object
|
284
|
+
class: Fabrique::Test::Fixtures::Constructors::ClassWithProperties
|
285
|
+
properties:
|
286
|
+
size: infinite
|
287
|
+
color: invisible
|
288
|
+
shape: 42
|
289
|
+
"""
|
290
|
+
When I request a bean factory for the application context
|
291
|
+
And I request the "simple_object" bean from the bean factory
|
292
|
+
Then the bean has "size" set to "infinite"
|
293
|
+
And the bean has "color" set to "invisible"
|
294
|
+
And the bean has "shape" that is the Integer "42"
|
295
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
@plugin_registry
|
2
|
+
Feature: Plugin registry
|
3
|
+
|
4
|
+
As a developer
|
5
|
+
I want to register the identity and construction method of different plugins
|
6
|
+
So that I can decouple their dependants from their means of creation
|
7
|
+
|
8
|
+
Plugins are classes, modules, objects or lambdas that may come from other developers, and so
|
9
|
+
may have disparate construction methods. A plugin registry allows these differences to be
|
10
|
+
abstracted, and for them to be created by a known and invariant identity. The identities of
|
11
|
+
plugins must be defined by the developer of the dependant.
|
12
|
+
|
13
|
+
This does not address the concern of ensuring that multiple plugins offer the same interface.
|
14
|
+
That concern is dealt with by a contract conformance strategy (e.g. interface through
|
15
|
+
delegation).
|
16
|
+
|
17
|
+
Most developers will not use a plugin registry directly. Instead, they will use a factory
|
18
|
+
that implements a conformance strategy. This has the additional benefit of allowing the
|
19
|
+
developers of plugins to define and register the identities of their plugins.
|
20
|
+
|
21
|
+
Scenario: Multiple plugins
|
22
|
+
|
23
|
+
Given I have a plugin registry
|
24
|
+
And I have two classes with default constructors
|
25
|
+
When I register each class into the registry with a unique identity and a default construction method
|
26
|
+
Then I can acquire instances of each class from the registry by its unique identity
|
27
|
+
|
28
|
+
Scenario Outline: As-is plugin
|
29
|
+
|
30
|
+
Given I have a plugin registry
|
31
|
+
And I have <article> <entity>, i.e. <code>
|
32
|
+
When I register the <entity> into the registry with a unique identity and an as-is construction method
|
33
|
+
Then I get the same <entity> every time I acquire the same identity
|
34
|
+
|
35
|
+
Examples:
|
36
|
+
| article | entity | code |
|
37
|
+
| an | object | Object.new |
|
38
|
+
| a | class | Class |
|
39
|
+
| a | module | Module |
|
40
|
+
| a | lambda | -> {} |
|
41
|
+
|
42
|
+
Scenario: Classical plugin with default constructor
|
43
|
+
|
44
|
+
Given I have a plugin registry
|
45
|
+
And I have a class with a default constructor
|
46
|
+
When I register the class into the registry with a unique identity and a default construction method
|
47
|
+
Then I can acquire instances of the class from the registry by its unique identity
|
48
|
+
|
49
|
+
Scenario: Classical plugin with properties hash constructor
|
50
|
+
|
51
|
+
Given I have a plugin registry
|
52
|
+
And I have a class with a properties hash constructor
|
53
|
+
When I register the class into the registry with a unique identity and a properties hash construction method
|
54
|
+
Then I can acquire an instance of the class from the registry by its unique identity, specifying properties with a hash argument
|
55
|
+
|
56
|
+
Scenario: Classical plugin with positional argument constructor
|
57
|
+
|
58
|
+
Given I have a plugin registry
|
59
|
+
And I have a class with a positional argument constructor
|
60
|
+
When I register the class into the registry with a unique identity and a positional argument construction method
|
61
|
+
Then I can acquire an instance of the class from the registry by its unique identity, specifying properties with a hash argument
|
62
|
+
And the instance has the specified properties
|
63
|
+
|
64
|
+
Scenario: Classical plugin with keyword argument constructor
|
65
|
+
|
66
|
+
Given I have a plugin registry
|
67
|
+
And I have a class with a keyword argument constructor
|
68
|
+
When I register the class into the registry with a unique identity and a keyword argument construction method
|
69
|
+
Then I can acquire an instance of the class from the registry by its unique identity, specifying properties with a hash argument
|
70
|
+
And the instance has the specified properties
|
71
|
+
|
72
|
+
Scenario: Builder pattern plugin
|
73
|
+
|
74
|
+
Given I have a plugin registry
|
75
|
+
And I have a class with a builder method
|
76
|
+
When I register the class into the registry with a unique identity and builder construction method
|
77
|
+
Then I can acquire an instance of the class from the registry by its unique identity, specifying properties with a hash argument
|
78
|
+
And the instance has the specified properties
|
79
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
After do
|
4
|
+
if defined?(@tmpfile) and File.exists?(@tmpfile)
|
5
|
+
File.unlink(@tmpfile)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
Given(/^I have a YAML application context definition:$/) do |string|
|
10
|
+
Tempfile.open('fabrique') do |f|
|
11
|
+
@tmpfile = f.path
|
12
|
+
f.write(string)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
When(/^I request a bean factory for the application context$/) do
|
17
|
+
@bean_factory = Fabrique::YamlBeanFactory.new(@tmpfile)
|
18
|
+
end
|
19
|
+
|
20
|
+
When(/^I request the "(.*?)" bean from the bean factory$/) do |bean_name|
|
21
|
+
@bean = @bean_factory.get_bean(bean_name)
|
22
|
+
end
|
23
|
+
|
24
|
+
Then(/^the bean has "(.*?)" set to "(.*?)"$/) do |attr, value|
|
25
|
+
expect(@bean.send(attr)).to eql value
|
26
|
+
end
|
27
|
+
|
28
|
+
Then(/^the bean has "(.*?)" that is the Integer "(.*?)"$/) do |attr, int_value|
|
29
|
+
expect(@bean.send(attr)).to eql int_value.to_i
|
30
|
+
end
|
31
|
+
|
32
|
+
Then(/^the "(.*?)" bean has "(.*?)" that is the Integer (\d+)$/) do |bean_name, attr, int_value|
|
33
|
+
bean = @bean_factory.get_bean(bean_name)
|
34
|
+
expect(bean.send(attr)).to eql int_value.to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
Then(/^the "(.*?)" bean has "(.*?)" set to the "(.*?)" bean$/) do |parent, attr, child|
|
38
|
+
parent = @bean_factory.get_bean(parent)
|
39
|
+
child = @bean_factory.get_bean(child)
|
40
|
+
expect(parent.send(attr)).to eql child
|
41
|
+
end
|
42
|
+
|
43
|
+
Then(/^the "(.*?)" bean has "(.*?)" set to "(.*?)"$/) do |bean_name, attr, value|
|
44
|
+
bean = @bean_factory.get_bean(bean_name)
|
45
|
+
expect(bean.send(attr)).to eql(value)
|
46
|
+
end
|
47
|
+
|
48
|
+
Then(/^I get the same object when I request the "(.*?)" bean again$/) do |bean_name|
|
49
|
+
new_reference = @bean_factory.get_bean(bean_name)
|
50
|
+
expect(new_reference.object_id).to eql @bean.object_id
|
51
|
+
end
|
52
|
+
|
53
|
+
Then(/^I get a different object when I request the "(.*?)" bean again$/) do |bean_name|
|
54
|
+
new_reference = @bean_factory.get_bean(bean_name)
|
55
|
+
expect(new_reference.object_id).to_not eql @bean.object_id
|
56
|
+
end
|
57
|
+
|
58
|
+
Then(/^I get a cyclic bean dependency error when I request a bean factory for the application context$/) do
|
59
|
+
expect { Fabrique::YamlBeanFactory.new(@tmpfile) }.to raise_error(Fabrique::CyclicBeanDependencyError, /cyclic bean dependency error/)
|
60
|
+
end
|
61
|
+
|
62
|
+
Then(/^the "(.*?)" and "(.*?)" beans share the same "(.*?)"$/) do |bean1_name, bean2_name, shared_property|
|
63
|
+
bean1 = @bean_factory.get_bean(bean1_name)
|
64
|
+
bean2 = @bean_factory.get_bean(bean2_name)
|
65
|
+
expect(bean1.send(shared_property).object_id).to eql bean2.send(shared_property).object_id
|
66
|
+
end
|
67
|
+
|
68
|
+
Then(/^the "(.*?)" and "(.*?)" beans each have their own "(.*?)"$/) do |bean1_name, bean2_name, own_property|
|
69
|
+
bean1 = @bean_factory.get_bean(bean1_name)
|
70
|
+
bean2 = @bean_factory.get_bean(bean2_name)
|
71
|
+
expect(bean1.send(own_property).object_id).to_not eql bean2.send(own_property).object_id
|
72
|
+
end
|
73
|
+
|
@@ -0,0 +1,207 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "fabrique/test"
|
3
|
+
|
4
|
+
class PluginRegistryTestRunner
|
5
|
+
include RSpec::Matchers
|
6
|
+
include Fabrique::Test::Fixtures::Constructors
|
7
|
+
|
8
|
+
def initialize(subject_constructor)
|
9
|
+
@subject_constructor = subject_constructor
|
10
|
+
end
|
11
|
+
|
12
|
+
def have_plugin_registry
|
13
|
+
@registry = @subject_constructor.call
|
14
|
+
end
|
15
|
+
|
16
|
+
def have_class_with_default_constructor
|
17
|
+
@class = ClassWithDefaultConstructor
|
18
|
+
end
|
19
|
+
|
20
|
+
def have_two_classes_with_default_constructors
|
21
|
+
@class1 = ClassWithDefaultConstructor
|
22
|
+
@class2 = OtherClassWithDefaultConstructor
|
23
|
+
end
|
24
|
+
|
25
|
+
def have_object(object)
|
26
|
+
@object = object
|
27
|
+
end
|
28
|
+
|
29
|
+
def have_class_with_positional_argument_constructor
|
30
|
+
@class = ClassWithPositionalArgumentConstructor
|
31
|
+
end
|
32
|
+
|
33
|
+
def have_class_with_properties_hash_constructor
|
34
|
+
@class = ClassWithPropertiesHashConstructor
|
35
|
+
end
|
36
|
+
|
37
|
+
def have_class_with_keyword_argument_constructor
|
38
|
+
@class = ClassWithKeywordArgumentConstructor
|
39
|
+
end
|
40
|
+
|
41
|
+
def have_class_with_builder_method
|
42
|
+
@class = ClassWithBuilderMethod
|
43
|
+
end
|
44
|
+
|
45
|
+
def register_class_with_as_is_constructor
|
46
|
+
@identity = :my_plugin
|
47
|
+
@registry.register(@identity, @class, Fabrique::Construction::Default.new)
|
48
|
+
end
|
49
|
+
|
50
|
+
def register_classes_with_default_constructors
|
51
|
+
@identity1 = :plugin1
|
52
|
+
@identity2 = :plugin2
|
53
|
+
@registry.register(@identity1, @class1, Fabrique::Construction::Default.new)
|
54
|
+
@registry.register(@identity2, @class2, Fabrique::Construction::Default.new)
|
55
|
+
end
|
56
|
+
|
57
|
+
def register_object_with_as_is_constructor
|
58
|
+
@identity = :my_plugin
|
59
|
+
@registry.register(@identity, @object, Fabrique::Construction::AsIs.new)
|
60
|
+
end
|
61
|
+
|
62
|
+
def register_class_with_properties_hash_constructor
|
63
|
+
@identity = :my_plugin
|
64
|
+
@registry.register(@identity, @class, Fabrique::Construction::PropertiesHash.new)
|
65
|
+
end
|
66
|
+
|
67
|
+
def register_class_with_positional_argument_constructor
|
68
|
+
@identity = :my_plugin
|
69
|
+
@registry.register(@identity, @class, Fabrique::Construction::PositionalArgument.new(:size, :color, :shape))
|
70
|
+
end
|
71
|
+
|
72
|
+
def register_class_with_keyword_argument_constructor
|
73
|
+
@identity = :my_plugin
|
74
|
+
@registry.register(@identity, @class, Fabrique::Construction::KeywordArgument.new)
|
75
|
+
end
|
76
|
+
|
77
|
+
def register_class_with_builder_method
|
78
|
+
@identity = :my_plugin
|
79
|
+
@registry.register(@identity, @class, Fabrique::Construction::BuilderMethod.new(:build) { |builder, properties|
|
80
|
+
builder.size = properties[:size]
|
81
|
+
builder.color = properties[:color]
|
82
|
+
builder.shape = properties[:shape]
|
83
|
+
})
|
84
|
+
end
|
85
|
+
|
86
|
+
def can_acquire_instances_of_class
|
87
|
+
instance1 = @registry.acquire(@identity)
|
88
|
+
instance2 = @registry.acquire(@identity)
|
89
|
+
expect(instance1.class).to eql @class
|
90
|
+
expect(instance2.class).to eql @class
|
91
|
+
expect(instance1.object_id).to_not eql instance2.object_id
|
92
|
+
end
|
93
|
+
|
94
|
+
def can_acquire_instances_of_classes
|
95
|
+
instance1 = @registry.acquire(@identity1)
|
96
|
+
instance2 = @registry.acquire(@identity2)
|
97
|
+
expect(instance1.class).to eql @class1
|
98
|
+
expect(instance2.class).to eql @class2
|
99
|
+
end
|
100
|
+
|
101
|
+
def can_acquire_same_object_id_every_time
|
102
|
+
instance1 = @registry.acquire(@identity)
|
103
|
+
instance2 = @registry.acquire(@identity)
|
104
|
+
expect(instance1.object_id).to eql @object.object_id
|
105
|
+
expect(instance2.object_id).to eql @object.object_id
|
106
|
+
end
|
107
|
+
|
108
|
+
def can_acquire_instance_of_class_with_properties
|
109
|
+
@instance = @registry.acquire(@identity, size: "large", color: "pink", shape: "cube")
|
110
|
+
end
|
111
|
+
|
112
|
+
def can_verify_instance_properties
|
113
|
+
expect(@instance.color).to eql "pink"
|
114
|
+
expect(@instance.shape).to eql "cube"
|
115
|
+
expect(@instance.size).to eql "large"
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
require "fabrique"
|
121
|
+
|
122
|
+
Before do |scenario|
|
123
|
+
if scenario.source_tags.any? { |tag| tag.name == "@plugin_registry" }
|
124
|
+
@test = PluginRegistryTestRunner.new( -> {Fabrique::PluginRegistry.new("Test plugin registry")})
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
Given(/^I have a plugin registry$/) do
|
129
|
+
@test.have_plugin_registry
|
130
|
+
end
|
131
|
+
|
132
|
+
Given(/^I have a class with a default constructor$/) do
|
133
|
+
@test.have_class_with_default_constructor
|
134
|
+
end
|
135
|
+
|
136
|
+
Given(/^I have two classes with default constructors$/) do
|
137
|
+
@test.have_two_classes_with_default_constructors
|
138
|
+
end
|
139
|
+
|
140
|
+
Given(/^I have an? \w+, i\.e\. (.+)$/) do |code|
|
141
|
+
@test.have_object(eval code)
|
142
|
+
end
|
143
|
+
|
144
|
+
Given(/^I have a class with a positional argument constructor$/) do
|
145
|
+
@test.have_class_with_positional_argument_constructor
|
146
|
+
end
|
147
|
+
|
148
|
+
Given(/^I have a class with a properties hash constructor$/) do
|
149
|
+
@test.have_class_with_properties_hash_constructor
|
150
|
+
end
|
151
|
+
|
152
|
+
Given(/^I have a class with a keyword argument constructor$/) do
|
153
|
+
@test.have_class_with_keyword_argument_constructor
|
154
|
+
end
|
155
|
+
|
156
|
+
Given(/^I have a class with a builder method$/) do
|
157
|
+
@test.have_class_with_builder_method
|
158
|
+
end
|
159
|
+
|
160
|
+
When(/^I register the class into the registry with a unique identity and a default construction method$/) do
|
161
|
+
@test.register_class_with_as_is_constructor
|
162
|
+
end
|
163
|
+
|
164
|
+
When(/^I register each class into the registry with a unique identity and a default construction method$/) do
|
165
|
+
@test.register_classes_with_default_constructors
|
166
|
+
end
|
167
|
+
|
168
|
+
When(/^I register the \w+ into the registry with a unique identity and an as\-is construction method$/) do
|
169
|
+
@test.register_object_with_as_is_constructor
|
170
|
+
end
|
171
|
+
|
172
|
+
When(/^I register the class into the registry with a unique identity and a properties hash construction method$/) do
|
173
|
+
@test.register_class_with_properties_hash_constructor
|
174
|
+
end
|
175
|
+
|
176
|
+
When(/^I register the class into the registry with a unique identity and a positional argument construction method$/) do
|
177
|
+
@test.register_class_with_positional_argument_constructor
|
178
|
+
end
|
179
|
+
|
180
|
+
When(/^I register the class into the registry with a unique identity and a keyword argument construction method$/) do
|
181
|
+
@test.register_class_with_keyword_argument_constructor
|
182
|
+
end
|
183
|
+
|
184
|
+
When(/^I register the class into the registry with a unique identity and builder construction method$/) do
|
185
|
+
@test.register_class_with_builder_method
|
186
|
+
end
|
187
|
+
|
188
|
+
Then(/^I can acquire instances of the class from the registry by its unique identity$/) do
|
189
|
+
@test.can_acquire_instances_of_class
|
190
|
+
end
|
191
|
+
|
192
|
+
Then(/^I can acquire instances of each class from the registry by its unique identity$/) do
|
193
|
+
@test.can_acquire_instances_of_classes
|
194
|
+
end
|
195
|
+
|
196
|
+
Then(/^I get the same \w+ every time I acquire the same identity$/) do
|
197
|
+
@test.can_acquire_same_object_id_every_time
|
198
|
+
end
|
199
|
+
|
200
|
+
Then(/^I can acquire an instance of the class from the registry by its unique identity, specifying properties with a hash argument$/) do
|
201
|
+
@test.can_acquire_instance_of_class_with_properties
|
202
|
+
end
|
203
|
+
|
204
|
+
Then(/^the instance has the specified properties$/) do
|
205
|
+
@test.can_verify_instance_properties
|
206
|
+
end
|
207
|
+
|