Skip to content

Commit

Permalink
chaos docs
Browse files Browse the repository at this point in the history
  • Loading branch information
BillyRuffian committed Jan 16, 2025
1 parent c06b71f commit 18e251f
Show file tree
Hide file tree
Showing 7 changed files with 288 additions and 2 deletions.
16 changes: 14 additions & 2 deletions usefakermaker.com/_data/navigation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,23 @@ sidebar:
url: /docs/usage/getting-started/
- title: "Building instances"
url: /docs/usage/building-instances/
- title: "Arrays"
url: /docs/usage/arrays/
- title: "Omitting fields"
url: /docs/usage/omitting-fields/
- title: "JSON field names"
url: /docs/usage/json-field-names/
- title: "Inheritance"
url: /docs/usage/inheritance/
- title: "Arrays"
url: /docs/usage/arrays/
- title: "Embedding factories"
url: /docs/usage/embedding-factories/
- title: "Chaos"
url: /docs/usage/chaos/
- title: "Lifecycle hooks"
url: /docs/usage/lifecycle-hooks/
- title: "Destroying factories"
url: /docs/usage/destroying-factories/
- title: "Managing dependencies"
url: /docs/usage/managing-dependencies/
- title: "History logging"
url: /docs/usage/history-logging/
41 changes: 41 additions & 0 deletions usefakermaker.com/docs/usage/chaos/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
layout: single
title: Chaos
---

Chaos mode introduces extra spice to your generated factories.

Attributes can be marked as either `required` or `optional`, which Chaos will use to determine what attributes are included when instantiating your factory.

Required attributes will always be present, however, optional attributes are not guaranteed to be present when Chaos is enabled.

*All attributes are optional by default.*

To explicitly mark attributes as either required or optional:

```ruby
FM.factory :item, naming: :json do
name { 'Blanket' }
price(required: true) { 100 }
description(optional: true) { 'Keeps you warm and cozy' }
manufacturer(optional: 0.7) { 'A large fruit company' }
end
```

You can state an attribute is optional using the `optional` option set to either be a `Boolean`, `Integer` or a `Float`.

When optional is set to either an `Integer` or a `Float`, this overrides the weighting which Chaos uses to determine the likelihood that attribute will be removed.

Higher the value, the more likely that attribute will be present. By default there's a 50/50 chance an optional attribute will be present.

To unleash Chaos over a factory, you need to enable it when instantiating your object:

```ruby
result = FakerMaker[:item].build( chaos: true )
```

You can also specify which attributes Chaos can use when instantiating your object:

```ruby
result = FakerMaker[:item].build( chaos: %i[name manufacturer] )
```
52 changes: 52 additions & 0 deletions usefakermaker.com/docs/usage/destroying-factories/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
layout: single
title: Destroying Factories
---

## A Cautionary Tale

If you think you want to do this, you are probably wrong. This will not only de-register the factory from Faker Maker, but also delete the class definition from the interpreter. While it's cool that Ruby allows this, it's almost certainly going to hurt.

This functionality exists for experimenting with factories in REPLs.

Seriously, don't use this in anger.

# Destroying Factories

Faker Maker deliberately does not allow you to redefine a factory by redeclaring it. It will also be silent about your attempt to do so. This is to avoid throwing up runtime warning from the Ruby interpreter if you are embedding one factory definition in another.

For example, this might give you unexpected behavior:

```ruby
FakerMaker.factory :user do
name {'Patsy Stone'}
end

FakerMaker.factory :user do
name {'Patsy Stone'}
email {'[email protected]'}
end

FM[:user].as_json
=> {: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.

```ruby
FakerMaker.factory :user do
name {'Patsy Stone'}
end

FakerMaker.shut!(:user)

FakerMaker.factory :user do
name {'Patsy Stone'}
email {'[email protected]'}
end

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

It also provides the `shut_all!` method to remove all factories.
69 changes: 69 additions & 0 deletions usefakermaker.com/docs/usage/embedding-factories/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
layout: single
title: Embedding Factories
---

To use factories with factories, the following pattern is recommended:

```ruby
FakerMaker.factory :item do
name { Faker::Commerce.product_name }
price { Faker::Commerce.price }
end

FakerMaker.factory :basket do
items( has: 10, factory: :item )
end
```

In this example, FakerMaker will build an `item` (well, 10 `item`s in this case) using item factory as it is building a `basket`. The advantage of this method is that `item` factory can be declared *after* the `basket` factory.

If you want to select randomly from one or more factories, provide an array of factory names:

```ruby
FakerMaker.factory :coupon do
discount { Faker::Commerce.price }
end

FakerMaker.factory :item do
name { Faker::Commerce.product_name }
price { Faker::Commerce.price }
end

FakerMaker.factory :basket do
items( has: 10, factory: [:item, :discount] )
end
```

In this example, through 10 iterations, one of `item` and `discount` factories will be called to build their objects.

Blocks can still be provided and the referenced factory built object will be passed to the block:

```ruby
FakerMaker.factory :item do
name { Faker::Commerce.product_name }
price { Faker::Commerce.price }
end

FakerMaker.factory :basket do
items( has: 10, factory: :item ) { |item| item.price = 10.99 ; item}
end
```
**Important:** the value for the attribute will be the value returned from the block. If you want to modify the contents of the referenced factory's object, don't forget to return it at the end of the block (as above).

## Alternative method

There is an alternative style which might be of use:

```ruby
FakerMaker.factory :item do
name { Faker::Commerce.product_name }
price { Faker::Commerce.price }
end

FakerMaker.factory :basket do
items( has: 10 ) { FakerMaker[:item].build }
end
```

With this pattern, you might have to [manage your dependencies]({% link usage/dependencies.md %}) and `require` your referenced factory.
47 changes: 47 additions & 0 deletions usefakermaker.com/docs/usage/history-logging/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
layout: single
title: History logging
parent: Usage
nav_order: 10
---

_(since 1.3.0)_

# Audit logs

It might be useful to collect the history of all the fakes generated by your factories. FakerMaker allows you to stream (or write to a file) all the instances it builds for you. This is optional and disabled by default.

## Enable logging

By default audit logging is disabled. The default output stream is `STDOUT`. The output target can either be an object that responds to `puts`, or be a string which will be interpreted as a file location to use to write to. If file path string is used, it will be opened in 'append' mode.

```ruby
FakerMaker.configure do |config|
config.audit = true
config.audit_destination = '/tmp/faker_maker_audit_logs'
end
```

## Audit streams

Immediately after each object is built and after the post-build hooks have completed, the instance details will be logged in line-delimited JSON (JSONL), to the stream or file. Each line is contained in an envelope containing the following metadata:

* The timestamp at the time of logging
* The name of factory
* The class name of the object the factory instantiated

For example, given the factory:

```ruby
FakerMaker.factory :user do
name {'Patsy Stone'}
email {'[email protected]'}
admin {false}
end
```

The audit log, on build, would look like:

```
{"timestamp":"2023-05-15T15:46:30+01:00","factory":"user","class":"User","body":{"name":"Patsy Stone","email":"[email protected]","admin":false}}
```
27 changes: 27 additions & 0 deletions usefakermaker.com/docs/usage/lifecycle-hooks/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
layout: single
title: Lifecycle Hooks
---

Faker Maker has a few hooks which can be added to the factory which are triggered when the factory builds an instance.

* `before_build` the instance has been created but none of the values have been set yet
* `after_build` the instance has been created and all of the values have been set

For instance:

```ruby
FakerMaker.factory :user do
before_build do |instance, factory|
puts 'Building an instance of User'
end

name {'Patsy Stone'}
email {'[email protected]'}
admin {false}

after_build do |instance, factory|
puts "Built an instance of User (#{instance.name})"
end
end
```
38 changes: 38 additions & 0 deletions usefakermaker.com/docs/usage/omitting-fields/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
layout: single
title: Omitting Fields
---

Sometimes you want a field present, other times you don't. This is often the case when you want to skip fields which have null or empty values.

```ruby
FakerMaker.factory :user do
name {'Patsy Stone'}
email(omit: :nil) {'[email protected]'}
admin {false}
end

FM[:user].build.as_json
=> {:name=>"Patsy Stone", :email=>"[email protected]", :admin=>false}

FM[:user].build(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:

* `: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.

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

```ruby
FakerMaker.factory :user do
name {'Patsy Stone'}
email(omit: [:nil, :empty, '[email protected]']) {'[email protected]'}
admin {false}
end
```

0 comments on commit 18e251f

Please sign in to comment.