fabrique 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -0
  3. data/Gemfile +5 -0
  4. data/Guardfile +9 -0
  5. data/README.md +152 -3
  6. data/Rakefile +11 -3
  7. data/config/cucumber.yml +2 -0
  8. data/constructors +70 -0
  9. data/docs/autowiring.yml +23 -0
  10. data/docs/multiple_providers.rb +104 -0
  11. data/fabrique.gemspec +3 -0
  12. data/features/bean_factory.feature +295 -0
  13. data/features/plugin_registry.feature +79 -0
  14. data/features/step_definitions/bean_factory_steps.rb +73 -0
  15. data/features/step_definitions/plugin_registry_steps.rb +207 -0
  16. data/features/support/byebug.rb +4 -0
  17. data/lib/fabrique/argument_adaptor/keyword.rb +19 -0
  18. data/lib/fabrique/argument_adaptor/positional.rb +76 -0
  19. data/lib/fabrique/bean_definition.rb +46 -0
  20. data/lib/fabrique/bean_definition_registry.rb +43 -0
  21. data/lib/fabrique/bean_factory.rb +78 -0
  22. data/lib/fabrique/bean_reference.rb +13 -0
  23. data/lib/fabrique/construction/as_is.rb +16 -0
  24. data/lib/fabrique/construction/builder_method.rb +21 -0
  25. data/lib/fabrique/construction/default.rb +17 -0
  26. data/lib/fabrique/construction/keyword_argument.rb +16 -0
  27. data/lib/fabrique/construction/positional_argument.rb +40 -0
  28. data/lib/fabrique/construction/properties_hash.rb +19 -0
  29. data/lib/fabrique/constructor/identity.rb +10 -0
  30. data/lib/fabrique/cyclic_bean_dependency_error.rb +6 -0
  31. data/lib/fabrique/plugin_registry.rb +56 -0
  32. data/lib/fabrique/test/fixtures/constructors.rb +81 -0
  33. data/lib/fabrique/test/fixtures/modules.rb +35 -0
  34. data/lib/fabrique/test/fixtures/opengl.rb +37 -0
  35. data/lib/fabrique/test/fixtures/repository.rb +139 -0
  36. data/lib/fabrique/test.rb +8 -0
  37. data/lib/fabrique/version.rb +1 -1
  38. data/lib/fabrique/yaml_bean_factory.rb +42 -0
  39. data/lib/fabrique.rb +4 -2
  40. data/spec/fabrique/argument_adaptor/keyword_spec.rb +50 -0
  41. data/spec/fabrique/argument_adaptor/positional_spec.rb +166 -0
  42. data/spec/fabrique/construction/as_is_spec.rb +23 -0
  43. data/spec/fabrique/construction/builder_method_spec.rb +29 -0
  44. data/spec/fabrique/construction/default_spec.rb +19 -0
  45. data/spec/fabrique/construction/positional_argument_spec.rb +61 -0
  46. data/spec/fabrique/construction/properties_hash_spec.rb +36 -0
  47. data/spec/fabrique/constructor/identity_spec.rb +4 -0
  48. data/spec/fabrique/plugin_registry_spec.rb +78 -0
  49. data/spec/fabrique_spec.rb +0 -4
  50. 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
+
@@ -0,0 +1,4 @@
1
+ begin
2
+ require "byebug"
3
+ rescue LoadError
4
+ end
@@ -0,0 +1,19 @@
1
+ module Fabrique
2
+
3
+ module ArgumentAdaptor
4
+
5
+ class Keyword
6
+
7
+ def adapt(properties = nil)
8
+ if properties.nil?
9
+ []
10
+ else
11
+ [properties]
12
+ end
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end