faker_maker 5.0.3 → 5.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 513de304bb5e07889bc3ebcfa0f79264aedca13b7d01ab29fc1fb5559d3d5266
4
- data.tar.gz: 9e5475d85f6a5eb58934450f4d7d4075e8c3778d678dffa9e9ace40b074e23d8
3
+ metadata.gz: 1b44668161c6ce88829e45936506db190418e6091de053e989242501f393171e
4
+ data.tar.gz: 1b51f3d30bd45ef34ec7384c7dcbe7fd8ea18196130e10551d044cd40aca55ae
5
5
  SHA512:
6
- metadata.gz: a190cd322a17ccf3ad4376e80ba27584bfd8f821432539dc738e39c9ec9bfae7dada1de12db82fa866d799daaa4c13746218142e20f534da5c5f3abfa5b4e44a
7
- data.tar.gz: fada3749b0b6a767a7134375e7732ab8a14b545d7b118f6ef07365c397274ae3d3ef927791fb6be7a146cb1e358965f275d420edba60df6ba1406c05ddd6cc5b
6
+ metadata.gz: beabf0e7079472e45322bfe0d46b04879d16e8740ba62599d85607c1c72ed76a0f32bc1430c1eca0ad205eb8631ca3510c8e9482064d7bf2fd8e3c8b0b97ec62
7
+ data.tar.gz: ad699c63f26f18b05cbf6936c69d7943e6ffa5686ebdc726aa0449f7139518cb4797a4d10da17c2c562bd95e7b4f226f2c5f8d243201906f214e1338b7d2bbcd
@@ -254,12 +254,18 @@ module FakerMaker
254
254
  end
255
255
 
256
256
  def value_for_attribute( instance, attr, attr_override_values, chaos: false )
257
- # Note: This is a behaviour change on the 5.x branch
258
- # If the attribute is overriden, that value will be supplied UNLESS
257
+ # NOTE: This is a behaviour change as of 5.x
258
+ # If the attribute is overridden, that value will be supplied UNLESS
259
259
  # - the value is a Hash, in which case FM will attempt to set nested parameters
260
- # EXCEPT if the hash is empty, in which case the assumptions is that the user intends to always
261
- # return an empty hash value
262
- if overridden_value?( attr, attr_override_values ) && !non_empty_hash?(attr_override_values[attr.name])
260
+ # EXCEPT if the Hash is empty, in which case the assumption is that the user intends to always
261
+ # return an empty Hash value
262
+ # - the attribute is an array of embedded factories and the value is an Array, in which case FM
263
+ # manufactures one object for each item, using the item as the override for that object
264
+ # EXCEPT if the Array is empty, in which case nothing is manufactured
265
+ # An item follows the same rules as a single embedded override, so an empty Hash item is supplied as is
266
+ if array_embedded_factory_override?( attr, attr_override_values )
267
+ manufacture_array_from_overrides( instance, attr, attr_override_values[attr.name], chaos: )
268
+ elsif overridden_value?( attr, attr_override_values ) && !non_empty_hash?(attr_override_values[attr.name])
263
269
  attr_override_values[attr.name]
264
270
  elsif attr.array?
265
271
  [].tap do |a|
@@ -276,13 +282,35 @@ module FakerMaker
276
282
  end
277
283
  end
278
284
 
285
+ # True when an Array override has been supplied for an embedded-factory array attribute.
286
+ # These overrides are handled item by item rather than as a single value.
287
+ def array_embedded_factory_override?( attr, attr_override_values )
288
+ overridden_value?( attr, attr_override_values ) &&
289
+ attr.array? &&
290
+ attr.embedded_factories? &&
291
+ attr_override_values[attr.name].is_a?( Array )
292
+ end
293
+
294
+ # Manufactures one object from the embedded factory for each item in the Array of overrides.
295
+ # Items follow the same rules as a single embedded override: a non-empty Hash is used as the
296
+ # overrides for the object, and anything else (such as nil or an empty Hash) is supplied
297
+ # as is, without running the attribute block. An empty Array yields no objects.
298
+ def manufacture_array_from_overrides( instance, attr, item_overrides, chaos: false )
299
+ item_overrides.map do |overrides|
300
+ next overrides unless non_empty_hash?( overrides )
301
+
302
+ manufacture = manufacture_from_embedded_factory( attr, overrides, chaos: )
303
+ attr.block ? instance.instance_exec( manufacture, &attr.block ) : manufacture
304
+ end
305
+ end
306
+
279
307
  def manufacture_from_embedded_factory( attr, attributes = {}, chaos: false )
280
308
  attributes ||= {}
281
309
  # The name of the embedded factory randomly selected from the list of embedded factories.
282
310
  embedded_factory = select_embedded_factory_or_sample(attr, attributes)
283
311
 
284
312
  if !embedded_factory && !attr.embedded_factories.empty?
285
- raise NoSuchFactoryError, "Unable to match given attributes to an embedded factory. Atributes: #{attributes.keys}"
313
+ raise NoSuchFactoryError, "Unable to match given attributes to an embedded factory. Attributes: #{attributes.keys}"
286
314
  end
287
315
 
288
316
  # The object that is being manufactured by the factory.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FakerMaker
4
- VERSION = '5.0.3'
4
+ VERSION = '5.1.0'
5
5
  end
@@ -40,7 +40,7 @@ end
40
40
 
41
41
  then the value of `result.name` is 'Electric Sheep'.
42
42
 
43
- Beware when overriding values in this way: there is no type checking. You will get an exception if you try to set a value to an attribute that doesn't exist but you won't get one if you assign, say, an array of values where you would otherwise have a string and vice versa.
43
+ Beware when overriding values in this way: there is no type checking. You will get an exception if you try to set a value to an attribute that doesn't exist but you won't get one if you assign, say, an array of values where you would otherwise have a string and vice versa. The exception is an array of embedded factories, where an Array of Hashes is built into objects (see [Embedding Factories](docs/usage/embedding-factories/)).
44
44
 
45
45
  Calling `result.to_json` will give a stringified JSON representation. Because ActiveSupport is used under the covers, `as_json` will give you a `Hash` rather than the stringified version.
46
46
 
@@ -48,3 +48,5 @@ result.name
48
48
  ```
49
49
 
50
50
  Even though `name` is optional and Chaos might otherwise remove it, explicitly overriding it guarantees it will be present with the value you specified.
51
+
52
+ This also applies to arrays of embedded factories: an Array override is kept as given, and Chaos is still applied to the objects built from its items.
@@ -89,6 +89,50 @@ end
89
89
 
90
90
  **Since v5.0.3** when passing override values to `#build` and where the factory has a choice of embedded factory, as in the example above where an inventory may contain either an item or a coupon, Faker Maker will attempt to locate the embedded factory which most matches the values give in the override. For example, if the attributes given to build the `item` field most match `coupon` fields, that embedded factory will be chosen. If there are still several choices which match the given attributes, a random selection will be made.
91
91
 
92
+ ## Overriding arrays of embedded factories
93
+
94
+ When an embedded factory attribute is an Array:
95
+
96
+ ```ruby
97
+ FakerMaker.factory :item do
98
+ name { Faker::Commerce.product_name }
99
+ price { Faker::Commerce.price }
100
+ end
101
+
102
+ FakerMaker.factory :basket do
103
+ items( has: 3, factory: :item )
104
+ end
105
+ ```
106
+
107
+ A Hash override is applied to every object that is built:
108
+
109
+ ```ruby
110
+ FM[:basket].build( attributes: { items: { name: 'Electric Blanket' } } ).as_json
111
+ => {:items=>[{:name=>"Electric Blanket", :price=>94.33}, {:name=>"Electric Blanket", :price=>40.86}, {:name=>"Electric Blanket", :price=>93.73}]}
112
+ ```
113
+
114
+ **Since v5.1.0** an Array can be passed instead. Faker Maker builds one object for each item in the Array, using the item as the overrides for that object. The number of objects comes from the Array, not from `has:`:
115
+
116
+ ```ruby
117
+ FM[:basket].build( attributes: { items: [{ name: 'Electric Blanket' }, { name: 'Electric Sheep', price: 5.99 }] } ).as_json
118
+ => {:items=>[{:name=>"Electric Blanket", :price=>34.28}, {:name=>"Electric Sheep", :price=>5.99}]}
119
+ ```
120
+
121
+ Each object is built by its embedded factory, so it uses that factory's JSON field names, `omit` options and (when enabled) Chaos, and anything the item does not set is generated as usual. When the factory has a choice of embedded factory, each item is matched separately.
122
+
123
+ An item follows the same rules as a single embedded override:
124
+
125
+ * A non-empty Hash is used as the overrides for the object that is built. An attribute which does not exist raises `NoSuchFactoryError`.
126
+ * An empty Hash, `nil` or any other value is supplied as it is, and the attribute's block is not run for it. This supports testing invalid message formats, as with a single empty Hash override.
127
+ * An empty Array builds no objects.
128
+
129
+ ```ruby
130
+ FM[:basket].build( attributes: { items: [{ name: 'Electric Blanket' }, {}, nil] } ).as_json
131
+ => {:items=>[{:name=>"Electric Blanket", :price=>47.86}, {}, nil]}
132
+ ```
133
+
134
+ An Array of values is still passed through untouched when the attribute has no embedded factory.
135
+
92
136
  ## Alternative method
93
137
 
94
138
  There is an alternative style which might be of use, **but** you have less control using build-time overrides for values (you can't set nested values). *This is no longer a recommended pattern*.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faker_maker
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.3
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nigel Brookes-Thomas
@@ -274,7 +274,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
274
274
  - !ruby/object:Gem::Version
275
275
  version: '0'
276
276
  requirements: []
277
- rubygems_version: 4.0.10
277
+ rubygems_version: 4.0.20
278
278
  specification_version: 4
279
279
  summary: FakerMaker bakes fakes.
280
280
  test_files: []