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.
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