Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion lib/faker_maker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ class NoSuchFactoryError < StandardError; end
class NoSuchAttributeError < StandardError; end
class ChaosConflictingAttributeError < StandardError; end
class NoSuchAttributeNamingStrategy < StandardError; end
# Your code goes here...

# Token value for marking attributes as omittable from generated JSON.
# Usage in factory definitions: `omit: FakerMaker::OMIT`
OMIT = '__OMIT__'.freeze

module_function

Expand Down
7 changes: 7 additions & 0 deletions lib/faker_maker/factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,13 @@ def populate_instance( instance, attr_override_values, chaos: false )
FakerMaker[parent].populate_instance(instance, attr_override_values, chaos:) if parent?

attributes = chaos ? chaos_select(chaos) : @attributes
# When chaos is enabled, protect explicitly overridden attributes from being affected by chaos;
# what you pass in is what you get.
if chaos
override_attrs = @attributes.select { |attr| attr_override_values.key?( attr.name ) }
attributes = (attributes + override_attrs).uniq
attributes = @attributes.select { |attr| attributes.include?( attr ) }
end

attributes.each do |attribute|
value = value_for_attribute( instance, attribute, attr_override_values, chaos: )
Expand Down
2 changes: 1 addition & 1 deletion lib/faker_maker/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module FakerMaker
VERSION = '4.0.0'
VERSION = '5.0.0'
end
16 changes: 14 additions & 2 deletions spec/faker_maker/attribute_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,22 @@
expect( attr.omit?('anything') ).to be true
end

it 'can omit nils and empty' do
attr = FakerMaker::Attribute.new( :my_name, nil, omit: %i[nil empty] )
it 'can omit using the OMIT token' do
attr = FakerMaker::Attribute.new( :my_name, nil, omit: FakerMaker::OMIT )
expect( attr.omit?(FakerMaker::OMIT) ).to be true
end

it 'does not omit nil or empty when using the OMIT token' do
attr = FakerMaker::Attribute.new( :my_name, nil, omit: FakerMaker::OMIT )
expect( attr.omit?(nil) ).to be false
expect( attr.omit?('') ).to be false
end

it 'can omit nils, empty and the OMIT token' do
attr = FakerMaker::Attribute.new( :my_name, nil, omit: [:nil, :empty, FakerMaker::OMIT] )
expect( attr.omit?('') ).to be true
expect( attr.omit?(nil) ).to be true
expect( attr.omit?(FakerMaker::OMIT) ).to be true
expect( attr.omit?('anything') ).to be false
end

Expand Down
18 changes: 18 additions & 0 deletions spec/faker_maker/factory_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,24 @@
factory.build( chaos: %i[required_attribute] )
end.to raise_error(FakerMaker::ChaosConflictingAttributeError)
end

it 'preserves explicitly overridden attributes when chaos is enabled' do
factory = FakerMaker::Factory.new( :example_factory )
required_attribute = FakerMaker::Attribute.new( :required_attribute, proc { 'required' }, required: true )
optional_attribute = FakerMaker::Attribute.new( :optional_attribute, proc { 'optional' } )
factory.attach_attribute( required_attribute )
factory.attach_attribute( optional_attribute )
FakerMaker.register_factory( factory )

fakes = []
10.times do
fakes << factory.build( attributes: { optional_attribute: 'overridden' }, chaos: true )
end

fakes.each do |fake|
expect( fake.optional_attribute ).to eq 'overridden'
end
end
end

describe '#instance' do
Expand Down
12 changes: 12 additions & 0 deletions usefakermaker.com.site/site/src/docs/usage/chaos/index.page.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,15 @@ You can also specify which attributes Chaos can use when instantiating your obje
```ruby
result = FakerMaker[:item].build( chaos: %i[name manufacturer] )
```

## Overrides are preserved

When you pass override attributes at build time, Chaos will not touch them. What you pass in is what you get.

```ruby
result = FakerMaker[:item].build( attributes: { name: 'Specific Name' }, chaos: true )
result.name
=> "Specific Name"
```

Even though `name` is optional and Chaos might otherwise remove it, explicitly overriding it guarantees it will be present with the value you specified.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ FakerMaker.factory :user do
end

FM[:user].as_json
=> {:name=>"Patsy Stone"}
=> {:name=>"Patsy Stone"}
```

On the other hand, sometimes you really, really want to destroy a factory and start again (especially if you are experimenting in a REPL for example). FakerMaker allows you to shut a factory which will de-register it from the list of available factories and attempt to unload the class it has built from the Ruby interpreter.
Expand All @@ -43,7 +43,7 @@ FakerMaker.factory :user do
end

FM[:user].as_json
=> {:name=>"Patsy Stone", :email=>"patsy@fabulous.co.uk"}
```
=> {:name=>"Patsy Stone", :email=>"patsy@fabulous.co.uk"}
```

It also provides the `shut_all!` method to remove all factories.
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@ FakerMaker.factory :request do
end

FakerMaker[:request].build.body
# => nil
=> nil
```
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ v.engine_capacity = 125

v.to_json

=> "{\"wheels\":4,\"colour\":\"blue\",\"engineCapacity\":125}"
=> "{\"wheels\":4,\"colour\":\"blue\",\"engineCapacity\":125}"
```

## Per-attribute naming
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ end
FM[:user].build.as_json
=> {:name=>"Patsy Stone", :email=>"patsy@fabulous.co.uk", :admin=>false}

FM[:user].build(email: nil).as_json
FM[:user].build( attributes: { email: nil } ).as_json
=> {:name=>"Patsy Stone", :admin=>false}
```

The `omit` modifier can take a single value or an array. If it is passed a value and the attribute equals this value, it will not be included in the output from `as_json` (which returns a Ruby Hash) or in `to_json` methods.

There are three special modifiers:
There are four special modifiers:

* `:nil` (symbol) to omit output when the attribute is set to nil
* `:empty` to omit output when the value is an empty string, an empty array or an empty hash
* `:nil` (symbol) to omit output when the attribute is set to nil.
* `:empty` to omit output when the value is an empty string, an empty array or an empty hash.
* `:always` to never output this attribute.
* `FakerMaker::OMIT` to omit output only when the attribute is set to this token value.

These can be mixed with real values, e.g.

Expand All @@ -33,3 +34,26 @@ FakerMaker.factory :user do
admin {false}
end
```

## Using the omit token

You may want to exclude a field but still allow it to be set to `nil`, an empty string/array/hash, or any other value.

`FakerMaker::OMIT` is a token value that can provide this flexibility, e.g.

```ruby
FakerMaker.factory :user do
name(omit: FakerMaker::OMIT) {'Patsy Stone'}
email(omit: :nil) {'patsy@fabulous.co.uk'}
admin(omit: :empty) {false}
end

FM[:user].build( attributes: { name: FakerMaker::OMIT } ).as_json
=> {:email=>"patsy@fabulous.co.uk", :admin=>false}

FM[:user].build( attributes: { name: nil, email: nil } ).as_json
=> {:name=>nil, :admin=>false}

FM[:user].build( attributes: { name: '', admin: '' } ).as_json
=> {:name=>"", :email=>"patsy@fabulous.co.uk"}
```
Loading