factory_bot 6.5.5 → 6.5.6
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 +4 -4
- data/GETTING_STARTED.md +86 -85
- data/NEWS.md +19 -1
- data/README.md +11 -19
- data/lib/factory_bot/attribute_assigner.rb +63 -24
- data/lib/factory_bot/factory.rb +2 -3
- data/lib/factory_bot/sequence.rb +2 -2
- data/lib/factory_bot/strategy.rb +15 -0
- data/lib/factory_bot/syntax/methods.rb +3 -3
- data/lib/factory_bot/version.rb +1 -1
- data/lib/factory_bot.rb +1 -6
- metadata +6 -6
- data/lib/factory_bot/strategy_calculator.rb +0 -26
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5268f67c49f294395edabe86ef2bf7bdd3644db872328f0134d832b8cbfe5396
|
|
4
|
+
data.tar.gz: 5e51702b4c819af99587ea2355b43b5770b228e1f0b81483b1bc9aa28806c630
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 80f08c8d63755aa32390aadfd2b5c653915a2d8920b58d56b89a6091c029a0194a007b5f6c99277f94c175a0c0c83463ce24d5849268ac8d3ab76c059379116d
|
|
7
|
+
data.tar.gz: f092552d291c38644d02d77a73722b5966cc33397a1dcd06cb90164da65779c14f8a0352c77fd19890d30ccbe112d66a21c130865486da0b8059168e3f4a30e7
|
data/GETTING_STARTED.md
CHANGED
|
@@ -17,9 +17,9 @@ at any time.
|
|
|
17
17
|
Getting Started
|
|
18
18
|
===============
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
- [Setup](#setup)
|
|
21
|
+
- [Update Your Gemfile](#update-your-gemfile)
|
|
22
|
+
- [Configure your test suite](#configure-your-test-suite)
|
|
23
23
|
- [RSpec](#rspec)
|
|
24
24
|
- [Test::Unit](#testunit)
|
|
25
25
|
- [Cucumber](#cucumber)
|
|
@@ -27,76 +27,77 @@ Getting Started
|
|
|
27
27
|
- [Minitest](#minitest)
|
|
28
28
|
- [Minitest::Spec](#minitestspec)
|
|
29
29
|
- [minitest-rails](#minitest-rails)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
30
|
+
- [Defining factories](#defining-factories)
|
|
31
|
+
- [Factory name and attributes](#factory-name-and-attributes)
|
|
32
|
+
- [Specifying the class explicitly](#specifying-the-class-explicitly)
|
|
33
|
+
- [Hash attributes](#hash-attributes)
|
|
34
|
+
- [Best practices](#best-practices)
|
|
35
|
+
- [Definition file paths](#definition-file-paths)
|
|
36
|
+
- [Static Attributes](#static-attributes)
|
|
37
|
+
- [Using factories](#using-factories)
|
|
38
|
+
- [Build strategies](#build-strategies)
|
|
39
|
+
- [Attribute overrides](#attribute-overrides)
|
|
40
|
+
- [build\_stubbed and Marshal.dump](#build_stubbed-and-marshaldump)
|
|
41
|
+
- [Aliases](#aliases)
|
|
42
|
+
- [Dependent Attributes](#dependent-attributes)
|
|
43
|
+
- [Transient Attributes](#transient-attributes)
|
|
44
|
+
- [With other attributes](#with-other-attributes)
|
|
45
|
+
- [With attributes\_for](#with-attributes_for)
|
|
46
|
+
- [With callbacks](#with-callbacks)
|
|
47
|
+
- [With associations](#with-associations)
|
|
48
|
+
- [Method Name / Reserved Word Attributes](#method-name--reserved-word-attributes)
|
|
49
|
+
- [Inheritance](#inheritance)
|
|
50
|
+
- [Nested factories](#nested-factories)
|
|
51
|
+
- [Assigning parent explicitly](#assigning-parent-explicitly)
|
|
52
|
+
- [Best practices](#best-practices-1)
|
|
53
|
+
- [Associations](#associations)
|
|
54
|
+
- [Implicit definition](#implicit-definition)
|
|
55
|
+
- [Explicit definition](#explicit-definition)
|
|
56
|
+
- [Inline definition](#inline-definition)
|
|
57
|
+
- [Specifying the factory](#specifying-the-factory)
|
|
58
|
+
- [Overriding attributes](#overriding-attributes)
|
|
59
|
+
- [Association overrides](#association-overrides)
|
|
60
|
+
- [Build strategies](#build-strategies-1)
|
|
61
|
+
- [has\_many associations](#has_many-associations)
|
|
62
|
+
- [has\_and\_belongs\_to\_many associations](#has_and_belongs_to_many-associations)
|
|
63
|
+
- [Polymorphic associations](#polymorphic-associations)
|
|
64
|
+
- [Interconnected associations](#interconnected-associations)
|
|
65
|
+
- [Sequences](#sequences)
|
|
66
|
+
- [Global sequences](#global-sequences)
|
|
67
|
+
- [With dynamic attributes](#with-dynamic-attributes)
|
|
68
|
+
- [As implicit attributes](#as-implicit-attributes)
|
|
69
|
+
- [Inline sequences](#inline-sequences)
|
|
70
|
+
- [Initial value](#initial-value)
|
|
71
|
+
- [Without a block](#without-a-block)
|
|
72
|
+
- [Aliases](#aliases-1)
|
|
73
|
+
- [Rewinding](#rewinding)
|
|
74
|
+
- [Uniqueness](#uniqueness)
|
|
75
|
+
- [Traits](#traits)
|
|
76
|
+
- [Defining traits](#defining-traits)
|
|
77
|
+
- [As implicit attributes](#as-implicit-attributes-1)
|
|
78
|
+
- [Attribute precedence](#attribute-precedence)
|
|
79
|
+
- [In child factories](#in-child-factories)
|
|
80
|
+
- [As mixins](#as-mixins)
|
|
81
|
+
- [Using traits](#using-traits)
|
|
82
|
+
- [With associations](#with-associations-1)
|
|
83
|
+
- [Traits within traits](#traits-within-traits)
|
|
84
|
+
- [With transient attributes](#with-transient-attributes)
|
|
85
|
+
- [Enum traits](#enum-traits)
|
|
86
|
+
- [Callbacks](#callbacks)
|
|
87
|
+
- [Default callbacks](#default-callbacks)
|
|
88
|
+
- [Multiple callbacks](#multiple-callbacks)
|
|
89
|
+
- [Global callbacks](#global-callbacks)
|
|
90
|
+
- [Symbol#to\_proc](#symbolto_proc)
|
|
91
|
+
- [Modifying factories](#modifying-factories)
|
|
92
|
+
- [Building or Creating Multiple Records](#building-or-creating-multiple-records)
|
|
93
|
+
- [Linting Factories](#linting-factories)
|
|
94
|
+
- [Custom Construction](#custom-construction)
|
|
95
|
+
- [Custom Strategies](#custom-strategies)
|
|
96
|
+
- [Custom Callbacks](#custom-callbacks)
|
|
97
|
+
- [Custom Methods to Persist Objects](#custom-methods-to-persist-objects)
|
|
98
|
+
- [ActiveSupport Instrumentation](#activesupport-instrumentation)
|
|
99
|
+
- [Rails Preloaders and RSpec](#rails-preloaders-and-rspec)
|
|
100
|
+
- [Using Without Bundler](#using-without-bundler)
|
|
100
101
|
|
|
101
102
|
Setup
|
|
102
103
|
-----
|
|
@@ -354,7 +355,7 @@ user = build(:user, account:, friends:)
|
|
|
354
355
|
|
|
355
356
|
[omitting values]: https://docs.ruby-lang.org/en/3.1/syntax/literals_rdoc.html#label-Hash+Literals
|
|
356
357
|
|
|
357
|
-
###
|
|
358
|
+
### build_stubbed and Marshal.dump
|
|
358
359
|
|
|
359
360
|
Note that objects created with `build_stubbed` cannot be serialized with
|
|
360
361
|
`Marshal.dump`, since factory\_bot defines singleton methods on these objects.
|
|
@@ -435,7 +436,7 @@ create(:user, rockstar: false).name
|
|
|
435
436
|
#=> "John Doe"
|
|
436
437
|
```
|
|
437
438
|
|
|
438
|
-
### With
|
|
439
|
+
### With attributes_for
|
|
439
440
|
|
|
440
441
|
Transient attributes will be ignored within attributes\_for and won't be set on
|
|
441
442
|
the model, even if the attribute exists or you attempt to override it.
|
|
@@ -641,7 +642,7 @@ end
|
|
|
641
642
|
|
|
642
643
|
Or inline using attributes from the factory:
|
|
643
644
|
|
|
644
|
-
```
|
|
645
|
+
```ruby
|
|
645
646
|
factory :post do
|
|
646
647
|
# ...
|
|
647
648
|
author_last_name { "Writely" }
|
|
@@ -735,7 +736,7 @@ factory :post do
|
|
|
735
736
|
author strategy: :build # <<< this does *not* work; causes author_id to be nil
|
|
736
737
|
```
|
|
737
738
|
|
|
738
|
-
###
|
|
739
|
+
### has_many associations
|
|
739
740
|
|
|
740
741
|
There are a few ways to generate data for a `has_many` relationship. The
|
|
741
742
|
simplest approach is to write a helper method in plain Ruby to tie together the
|
|
@@ -862,7 +863,7 @@ build(:user_with_posts, posts_count: 15).posts.length # 15
|
|
|
862
863
|
build_stubbed(:user_with_posts, posts_count: 15).posts.length # 15
|
|
863
864
|
```
|
|
864
865
|
|
|
865
|
-
###
|
|
866
|
+
### has_and_belongs_to_many associations
|
|
866
867
|
|
|
867
868
|
Generating data for a `has_and_belongs_to_many` relationship is very similar
|
|
868
869
|
to the above `has_many` relationship, with a small change: you need to pass an
|
|
@@ -1152,7 +1153,7 @@ When working with uniqueness constraints, be careful not to pass in override val
|
|
|
1152
1153
|
|
|
1153
1154
|
In this example the email will be the same for both users. If email must be unique, this code will error:
|
|
1154
1155
|
|
|
1155
|
-
```
|
|
1156
|
+
```ruby
|
|
1156
1157
|
factory :user do
|
|
1157
1158
|
sequence(:email) { |n| "person#{n}@example.com" }
|
|
1158
1159
|
end
|
|
@@ -1418,7 +1419,7 @@ create :invoice, :with_amount, amount: 2
|
|
|
1418
1419
|
|
|
1419
1420
|
Given an Active Record model with an enum attribute:
|
|
1420
1421
|
|
|
1421
|
-
```
|
|
1422
|
+
```ruby
|
|
1422
1423
|
class Task < ActiveRecord::Base
|
|
1423
1424
|
enum status: {queued: 0, started: 1, finished: 2}
|
|
1424
1425
|
end
|
|
@@ -1428,7 +1429,7 @@ end
|
|
|
1428
1429
|
factory\_bot will automatically define traits for each possible value of the
|
|
1429
1430
|
enum:
|
|
1430
1431
|
|
|
1431
|
-
```
|
|
1432
|
+
```ruby
|
|
1432
1433
|
FactoryBot.define do
|
|
1433
1434
|
factory :task
|
|
1434
1435
|
end
|
|
@@ -1440,7 +1441,7 @@ FactoryBot.build(:task, :finished)
|
|
|
1440
1441
|
|
|
1441
1442
|
Writing the traits out manually would be cumbersome, and is not necessary:
|
|
1442
1443
|
|
|
1443
|
-
```
|
|
1444
|
+
```ruby
|
|
1444
1445
|
FactoryBot.define do
|
|
1445
1446
|
factory :task do
|
|
1446
1447
|
trait :queued do
|
|
@@ -1465,7 +1466,7 @@ desired, it is possible to disable the feature by setting
|
|
|
1465
1466
|
In that case, it is still possible to explicitly define traits for an enum
|
|
1466
1467
|
attribute in a particular factory:
|
|
1467
1468
|
|
|
1468
|
-
```
|
|
1469
|
+
```ruby
|
|
1469
1470
|
FactoryBot.automatically_define_enum_traits = false
|
|
1470
1471
|
|
|
1471
1472
|
FactoryBot.define do
|
|
@@ -1480,7 +1481,7 @@ specifically tied to Active Record enum attributes.
|
|
|
1480
1481
|
|
|
1481
1482
|
With an array:
|
|
1482
1483
|
|
|
1483
|
-
```
|
|
1484
|
+
```ruby
|
|
1484
1485
|
class Task
|
|
1485
1486
|
attr_accessor :status
|
|
1486
1487
|
end
|
|
@@ -1494,7 +1495,7 @@ end
|
|
|
1494
1495
|
|
|
1495
1496
|
Or with a hash:
|
|
1496
1497
|
|
|
1497
|
-
```
|
|
1498
|
+
```ruby
|
|
1498
1499
|
class Task
|
|
1499
1500
|
attr_accessor :status
|
|
1500
1501
|
end
|
data/NEWS.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# News
|
|
2
2
|
|
|
3
|
+
## 6.5.6 (October 22, 2025)
|
|
4
|
+
|
|
5
|
+
* Fix: Enforce association override precedence over trait foreign keys by @JinOketani in [#1768](https://github.com/thoughtbot/factory_bot/pull/1768)
|
|
6
|
+
* Build: Add ostruct as a development dependency by @ydah in [#1778](https://github.com/thoughtbot/factory_bot/pull/1778)
|
|
7
|
+
* Build: Bump standard from v1.44.0 to v1.51.1 by @ydah in [#1779](https://github.com/thoughtbot/factory_bot/pull/1779)
|
|
8
|
+
* Build: Add Ruby 3.4 to CI matrix by @ydah in [#1780](https://github.com/thoughtbot/factory_bot/pull/1780)
|
|
9
|
+
* Build: Remove unnecessary development dependencies by @ydah in [#1781](https://github.com/thoughtbot/factory_bot/pull/1781)
|
|
10
|
+
* Build: update gem versions and dependencies by @ydah in [#1782](https://github.com/thoughtbot/factory_bot/pull/1782)
|
|
11
|
+
* Build: revert removal of mutex_m by @vburzynski in [#1784](https://github.com/thoughtbot/factory_bot/pull/1784)
|
|
12
|
+
* Refactor: factory calculator cleanup by @vburzynski in [#1770](https://github.com/thoughtbot/factory_bot/pull/1770)
|
|
13
|
+
* Chore(ci): Bump actions/checkout from 4 to 5 by @dependabot[bot] in [#1765](https://github.com/thoughtbot/factory_bot/pull/1765)
|
|
14
|
+
* Chore(specs): tag slow specs by @vburzynski in [#1776](https://github.com/thoughtbot/factory_bot/pull/1776)
|
|
15
|
+
* Docs: Update RELEASING.md by @vburzynski in [#1763](https://github.com/thoughtbot/factory_bot/pull/1763)
|
|
16
|
+
* Docs: Update link to FactoryGirl upgrade guide by @imRohan in [#1769](https://github.com/thoughtbot/factory_bot/pull/1769)
|
|
17
|
+
* Docs: Fix some typos by @ydah in [#1783](https://github.com/thoughtbot/factory_bot/pull/1783)
|
|
18
|
+
* Docs(yard): resolve yard doc warnings by @vburzynski in [#1764](https://github.com/thoughtbot/factory_bot/pull/1764)
|
|
19
|
+
* Docs(yard): ruby syntax highlighting in yard docs by @djbender in [#1777](https://github.com/thoughtbot/factory_bot/pull/1777)
|
|
20
|
+
|
|
3
21
|
## 6.5.5 (August 15, 2025)
|
|
4
22
|
|
|
5
23
|
* Feat: Adds developer console features (CodeMeister)
|
|
@@ -118,7 +136,7 @@
|
|
|
118
136
|
* Docs: re-write into mdBook (Mike Burns, Sara Jackson, Stefanni Brasil)
|
|
119
137
|
* Docs: clarify that automatic trait definitions could introduce new linting errors (Lawrence Chou).
|
|
120
138
|
* Internal: skip TruffleRuby on Rails 5.0, 5.1, 5.2 (Andrii Konchyn).
|
|
121
|
-
* Internal: fix
|
|
139
|
+
* Internal: fix typos throughout codebase (Yudai Takada).
|
|
122
140
|
* Internal: run CI on `actions/checkout` v3 (Yudai Takada).
|
|
123
141
|
* Internal: follow standardrb code style (Yudai Takada).
|
|
124
142
|
* Internal: stop using Hound (Daniel Nolan).
|
data/README.md
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
# factory_bot
|
|
1
|
+
# factory_bot
|
|
2
|
+
|
|
3
|
+
[![Build Status][ci-image]][ci] [![Code Climate][grade-image]][grade] [![Gem Version][version-image]][version]
|
|
2
4
|
|
|
3
5
|
factory_bot is a fixtures replacement with a straightforward definition syntax, support for multiple build strategies (saved instances, unsaved instances, attribute hashes, and stubbed objects), and support for multiple factories for the same class (user, admin_user, and so on), including factory inheritance.
|
|
4
6
|
|
|
5
7
|
If you want to use factory_bot with Rails, see
|
|
6
8
|
[factory_bot_rails](https://github.com/thoughtbot/factory_bot_rails).
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
### Transitioning from factory\_girl?
|
|
10
|
+
Interested in the history of the project name? You can find the history [here](https://github.com/thoughtbot/factory_bot/blob/main/NAME.md)
|
|
12
11
|
|
|
13
|
-
Check out the [guide](https://github.com/thoughtbot/factory_bot/blob/v4.9.0/UPGRADE_FROM_FACTORY_GIRL.md).
|
|
12
|
+
Transitioning from factory\_girl? Check out the [upgrade guide](https://github.com/thoughtbot/factory_bot/blob/v4.9.0/UPGRADE_FROM_FACTORY_GIRL.md).
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
Documentation
|
|
17
|
-
-------------
|
|
14
|
+
## Documentation
|
|
18
15
|
|
|
19
16
|
See our extensive reference, guides, and cookbook in [the factory_bot book][].
|
|
20
17
|
|
|
@@ -27,8 +24,7 @@ Rails, see [the factory_bot wiki][].
|
|
|
27
24
|
[the factory_bot book]: https://thoughtbot.github.io/factory_bot
|
|
28
25
|
[the factory_bot wiki]: https://github.com/thoughtbot/factory_bot/wiki
|
|
29
26
|
|
|
30
|
-
Install
|
|
31
|
-
--------
|
|
27
|
+
## Install
|
|
32
28
|
|
|
33
29
|
Run:
|
|
34
30
|
|
|
@@ -42,13 +38,11 @@ To install the gem manually from your shell, run:
|
|
|
42
38
|
gem install factory_bot
|
|
43
39
|
```
|
|
44
40
|
|
|
45
|
-
Supported Ruby versions
|
|
46
|
-
-----------------------
|
|
41
|
+
## Supported Ruby versions
|
|
47
42
|
|
|
48
|
-
Supported Ruby versions are listed in
|
|
43
|
+
Supported Ruby versions are listed in `.github/workflows/build.yml` ([source](https://github.com/thoughtbot/factory_bot/blob/main/.github/workflows/build.yml))
|
|
49
44
|
|
|
50
|
-
More Information
|
|
51
|
-
----------------
|
|
45
|
+
## More Information
|
|
52
46
|
|
|
53
47
|
* [Rubygems](https://rubygems.org/gems/factory_bot)
|
|
54
48
|
* [Stack Overflow](https://stackoverflow.com/questions/tagged/factory-bot)
|
|
@@ -56,10 +50,8 @@ More Information
|
|
|
56
50
|
* [GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS](https://robots.thoughtbot.com/)
|
|
57
51
|
|
|
58
52
|
[GETTING_STARTED]: https://github.com/thoughtbot/factory_bot/blob/main/GETTING_STARTED.md
|
|
59
|
-
[NAME]: https://github.com/thoughtbot/factory_bot/blob/main/NAME.md
|
|
60
53
|
|
|
61
|
-
Useful Tools
|
|
62
|
-
------------
|
|
54
|
+
## Useful Tools
|
|
63
55
|
|
|
64
56
|
* [FactoryTrace](https://github.com/djezzzl/factory_trace) - helps to find unused factories and traits.
|
|
65
57
|
* [ruby-lsp-factory_bot](https://github.com/donny741/ruby-lsp-factory_bot) / [ruby-lsp-rails-factory-bot](https://github.com/johansenja/ruby-lsp-rails-factory-bot) - integration with [ruby-lsp](https://github.com/Shopify/ruby-lsp) to provide intellisense
|
|
@@ -9,6 +9,7 @@ module FactoryBot
|
|
|
9
9
|
@attribute_names_assigned = []
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
+
# constructs an object-based factory product
|
|
12
13
|
def object
|
|
13
14
|
@evaluator.instance = build_class_instance
|
|
14
15
|
build_class_instance.tap do |instance|
|
|
@@ -19,6 +20,7 @@ module FactoryBot
|
|
|
19
20
|
end
|
|
20
21
|
end
|
|
21
22
|
|
|
23
|
+
# constructs a Hash-based factory product
|
|
22
24
|
def hash
|
|
23
25
|
@evaluator.instance = build_hash
|
|
24
26
|
|
|
@@ -29,6 +31,8 @@ module FactoryBot
|
|
|
29
31
|
|
|
30
32
|
private
|
|
31
33
|
|
|
34
|
+
# Track evaluation of methods on the evaluator to prevent the duplicate
|
|
35
|
+
# assignment of attributes accessed and via `initialize_with` syntax
|
|
32
36
|
def method_tracking_evaluator
|
|
33
37
|
@method_tracking_evaluator ||= Decorator::AttributeHash.new(
|
|
34
38
|
decorated_evaluator,
|
|
@@ -67,12 +71,15 @@ module FactoryBot
|
|
|
67
71
|
attribute_names_to_assign - association_names
|
|
68
72
|
end
|
|
69
73
|
|
|
74
|
+
# Builds a list of attributes names that should be assigned to the factory product
|
|
70
75
|
def attribute_names_to_assign
|
|
71
|
-
@attribute_names_to_assign ||=
|
|
72
|
-
|
|
73
|
-
override_names
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
@attribute_names_to_assign ||= begin
|
|
77
|
+
# start a list of candidates containing non-transient attributes and overrides
|
|
78
|
+
assignment_candidates = non_ignored_attribute_names + override_names
|
|
79
|
+
# then remove any transient attributes (potentially reintroduced by the overrides),
|
|
80
|
+
# and remove ignorable aliased attributes from the candidate list
|
|
81
|
+
assignment_candidates - ignored_attribute_names - attribute_names_overriden_by_alias
|
|
82
|
+
end
|
|
76
83
|
end
|
|
77
84
|
|
|
78
85
|
def non_ignored_attribute_names
|
|
@@ -99,31 +106,63 @@ module FactoryBot
|
|
|
99
106
|
attribute_names + override_names + @build_class.instance_methods
|
|
100
107
|
end
|
|
101
108
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
# Builds a list of attribute names which are slated to be interrupted by an override.
|
|
110
|
+
def attribute_names_overriden_by_alias
|
|
111
|
+
@attribute_list
|
|
112
|
+
.non_ignored
|
|
113
|
+
.flat_map { |attribute|
|
|
114
|
+
override_names.map do |override|
|
|
115
|
+
attribute.name if ignorable_alias?(attribute, override)
|
|
116
|
+
end
|
|
117
|
+
}
|
|
118
|
+
.compact
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Is the attribute an ignorable alias of the override?
|
|
122
|
+
# An attribute is ignorable when it is an alias of the override AND it is
|
|
123
|
+
# either interrupting an assocciation OR is not the name of another attribute
|
|
106
124
|
#
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
125
|
+
# @note An "alias" is currently an overloaded term for two distinct cases:
|
|
126
|
+
# (1) attributes which are aliases and reference the same value
|
|
127
|
+
# (2) a logical grouping of a foreign key and an associated object
|
|
128
|
+
def ignorable_alias?(attribute, override)
|
|
129
|
+
return false unless attribute.alias_for?(override)
|
|
130
|
+
|
|
131
|
+
# The attribute alias should be ignored when the override interrupts an association
|
|
132
|
+
return true if override_interrupts_association?(attribute, override)
|
|
133
|
+
|
|
134
|
+
# Remaining aliases should be ignored when the override does not match a declared attribute.
|
|
135
|
+
# An override which is an alias to a declared attribute should not interrupt the aliased
|
|
136
|
+
# attribute and interrupt only the attribute with a matching name. This workaround allows a
|
|
137
|
+
# factory to declare both <attribute> and <attribute>_id as separate and distinct attributes.
|
|
138
|
+
!override_matches_declared_attribute?(override)
|
|
113
139
|
end
|
|
114
140
|
|
|
115
|
-
|
|
116
|
-
#
|
|
117
|
-
#
|
|
141
|
+
# Does this override interrupt an association?
|
|
142
|
+
# When true, this indicates the aliased attribute is related to a declared association and the
|
|
143
|
+
# override does not match the attribute name.
|
|
144
|
+
#
|
|
145
|
+
# @note Association overrides should take precedence over a declared foreign key attribute.
|
|
118
146
|
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
# in the same factory.
|
|
147
|
+
# @note An override may interrupt an association by providing the associated object or
|
|
148
|
+
# by providing the foreign key.
|
|
122
149
|
#
|
|
123
|
-
|
|
124
|
-
|
|
150
|
+
# @param [FactoryBot::Attribute] aliased_attribute
|
|
151
|
+
# @param [Symbol] override name of an override which is an alias to the attribute name
|
|
152
|
+
def override_interrupts_association?(aliased_attribute, override)
|
|
153
|
+
(aliased_attribute.association? || association_names.include?(override)) &&
|
|
154
|
+
aliased_attribute.name != override
|
|
155
|
+
end
|
|
125
156
|
|
|
126
|
-
|
|
157
|
+
# Does this override match the name of any declared attribute?
|
|
158
|
+
#
|
|
159
|
+
# @note Checking against the names of all attributes, resolves any issues with having both
|
|
160
|
+
# <attribute> and <attribute>_id in the same factory. This also takes into account ignored
|
|
161
|
+
# attributes that should not be assigned (aka transient attributes)
|
|
162
|
+
#
|
|
163
|
+
# @param [Symbol] override the name of an override
|
|
164
|
+
def override_matches_declared_attribute?(override)
|
|
165
|
+
attribute_names.include?(override)
|
|
127
166
|
end
|
|
128
167
|
end
|
|
129
168
|
end
|
data/lib/factory_bot/factory.rb
CHANGED
|
@@ -36,14 +36,13 @@ module FactoryBot
|
|
|
36
36
|
|
|
37
37
|
compile
|
|
38
38
|
|
|
39
|
-
strategy =
|
|
39
|
+
strategy = Strategy.lookup_strategy(build_strategy).new
|
|
40
40
|
|
|
41
41
|
evaluator = evaluator_class.new(strategy, overrides.symbolize_keys)
|
|
42
42
|
attribute_assigner = AttributeAssigner.new(evaluator, build_class, &compiled_constructor)
|
|
43
43
|
|
|
44
44
|
observer = CallbacksObserver.new(callbacks, evaluator)
|
|
45
|
-
evaluation =
|
|
46
|
-
Evaluation.new(evaluator, attribute_assigner, compiled_to_create, observer)
|
|
45
|
+
evaluation = Evaluation.new(evaluator, attribute_assigner, compiled_to_create, observer)
|
|
47
46
|
|
|
48
47
|
evaluation.notify(:before_all, nil)
|
|
49
48
|
instance = strategy.result(evaluation).tap(&block)
|
data/lib/factory_bot/sequence.rb
CHANGED
|
@@ -17,8 +17,8 @@ module FactoryBot
|
|
|
17
17
|
|
|
18
18
|
def self.find_by_uri(uri)
|
|
19
19
|
uri = uri.to_sym
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
FactoryBot::Internal.sequences.to_a.find { |seq| seq.has_uri?(uri) } ||
|
|
21
|
+
FactoryBot::Internal.inline_sequences.find { |seq| seq.has_uri?(uri) }
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def initialize(name, *args, &proc)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require "factory_bot/strategy/build"
|
|
2
|
+
require "factory_bot/strategy/create"
|
|
3
|
+
require "factory_bot/strategy/attributes_for"
|
|
4
|
+
require "factory_bot/strategy/stub"
|
|
5
|
+
require "factory_bot/strategy/null"
|
|
6
|
+
|
|
7
|
+
module FactoryBot
|
|
8
|
+
module Strategy
|
|
9
|
+
def self.lookup_strategy(name_or_object)
|
|
10
|
+
return name_or_object if name_or_object.is_a?(Class)
|
|
11
|
+
|
|
12
|
+
FactoryBot::Internal.strategy_by_name(name_or_object)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -83,20 +83,20 @@ module FactoryBot
|
|
|
83
83
|
# (see #strategy_method_pair)
|
|
84
84
|
# @return [Array<Hash>] pair of attribute hashes for the factory
|
|
85
85
|
|
|
86
|
-
# @!method strategy_method
|
|
86
|
+
# @!method strategy_method(name, traits_and_overrides, &block)
|
|
87
87
|
# @!visibility private
|
|
88
88
|
# @param [Symbol] name the name of the factory to build
|
|
89
89
|
# @param [Array<Symbol, Symbol, Hash>] traits_and_overrides splat args traits and a hash of overrides
|
|
90
90
|
# @param [Proc] block block to be executed
|
|
91
91
|
|
|
92
|
-
# @!method strategy_method_list
|
|
92
|
+
# @!method strategy_method_list(name, amount, traits_and_overrides, &block)
|
|
93
93
|
# @!visibility private
|
|
94
94
|
# @param [Symbol] name the name of the factory to execute
|
|
95
95
|
# @param [Integer] amount the number of instances to execute
|
|
96
96
|
# @param [Array<Symbol, Symbol, Hash>] traits_and_overrides splat args traits and a hash of overrides
|
|
97
97
|
# @param [Proc] block block to be executed
|
|
98
98
|
|
|
99
|
-
# @!method strategy_method_pair
|
|
99
|
+
# @!method strategy_method_pair(name, traits_and_overrides, &block)
|
|
100
100
|
# @!visibility private
|
|
101
101
|
# @param [Symbol] name the name of the factory to execute
|
|
102
102
|
# @param [Array<Symbol, Symbol, Hash>] traits_and_overrides splat args traits and a hash of overrides
|
data/lib/factory_bot/version.rb
CHANGED
data/lib/factory_bot.rb
CHANGED
|
@@ -11,12 +11,7 @@ require "factory_bot/configuration"
|
|
|
11
11
|
require "factory_bot/errors"
|
|
12
12
|
require "factory_bot/factory_runner"
|
|
13
13
|
require "factory_bot/strategy_syntax_method_registrar"
|
|
14
|
-
require "factory_bot/
|
|
15
|
-
require "factory_bot/strategy/build"
|
|
16
|
-
require "factory_bot/strategy/create"
|
|
17
|
-
require "factory_bot/strategy/attributes_for"
|
|
18
|
-
require "factory_bot/strategy/stub"
|
|
19
|
-
require "factory_bot/strategy/null"
|
|
14
|
+
require "factory_bot/strategy"
|
|
20
15
|
require "factory_bot/registry"
|
|
21
16
|
require "factory_bot/null_factory"
|
|
22
17
|
require "factory_bot/null_object"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: factory_bot
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.5.
|
|
4
|
+
version: 6.5.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Josh Clayton
|
|
8
8
|
- Joe Ferris
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -67,7 +67,7 @@ dependencies:
|
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '0'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
70
|
+
name: mutex_m
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
73
|
- - ">="
|
|
@@ -81,7 +81,7 @@ dependencies:
|
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: ostruct
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
87
|
- - ">="
|
|
@@ -233,12 +233,12 @@ files:
|
|
|
233
233
|
- lib/factory_bot/registry.rb
|
|
234
234
|
- lib/factory_bot/reload.rb
|
|
235
235
|
- lib/factory_bot/sequence.rb
|
|
236
|
+
- lib/factory_bot/strategy.rb
|
|
236
237
|
- lib/factory_bot/strategy/attributes_for.rb
|
|
237
238
|
- lib/factory_bot/strategy/build.rb
|
|
238
239
|
- lib/factory_bot/strategy/create.rb
|
|
239
240
|
- lib/factory_bot/strategy/null.rb
|
|
240
241
|
- lib/factory_bot/strategy/stub.rb
|
|
241
|
-
- lib/factory_bot/strategy_calculator.rb
|
|
242
242
|
- lib/factory_bot/strategy_syntax_method_registrar.rb
|
|
243
243
|
- lib/factory_bot/syntax.rb
|
|
244
244
|
- lib/factory_bot/syntax/default.rb
|
|
@@ -266,7 +266,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
266
266
|
- !ruby/object:Gem::Version
|
|
267
267
|
version: '0'
|
|
268
268
|
requirements: []
|
|
269
|
-
rubygems_version: 3.
|
|
269
|
+
rubygems_version: 3.7.1
|
|
270
270
|
specification_version: 4
|
|
271
271
|
summary: factory_bot provides a framework and DSL for defining and using model instance
|
|
272
272
|
factories.
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
module FactoryBot
|
|
2
|
-
# @api private
|
|
3
|
-
class StrategyCalculator
|
|
4
|
-
def initialize(name_or_object)
|
|
5
|
-
@name_or_object = name_or_object
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def strategy
|
|
9
|
-
if strategy_is_object?
|
|
10
|
-
@name_or_object
|
|
11
|
-
else
|
|
12
|
-
strategy_name_to_object
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
private
|
|
17
|
-
|
|
18
|
-
def strategy_is_object?
|
|
19
|
-
@name_or_object.is_a?(Class)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def strategy_name_to_object
|
|
23
|
-
FactoryBot::Internal.strategy_by_name(@name_or_object)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|