factory_bot 5.2.0 → 6.2.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 +4 -4
- data/CONTRIBUTING.md +58 -13
- data/GETTING_STARTED.md +684 -136
- data/NEWS.md +30 -2
- data/README.md +4 -10
- data/lib/factory_bot.rb +19 -53
- data/lib/factory_bot/aliases.rb +3 -3
- data/lib/factory_bot/attribute/association.rb +2 -2
- data/lib/factory_bot/attribute/dynamic.rb +2 -2
- data/lib/factory_bot/attribute_assigner.rb +9 -10
- data/lib/factory_bot/attribute_list.rb +1 -1
- data/lib/factory_bot/callback.rb +3 -11
- data/lib/factory_bot/configuration.rb +7 -7
- data/lib/factory_bot/declaration.rb +1 -1
- data/lib/factory_bot/declaration/association.rb +23 -6
- data/lib/factory_bot/declaration_list.rb +2 -2
- data/lib/factory_bot/decorator.rb +18 -6
- data/lib/factory_bot/decorator/invocation_tracker.rb +1 -0
- data/lib/factory_bot/definition.rb +61 -16
- data/lib/factory_bot/definition_proxy.rb +63 -5
- data/lib/factory_bot/enum.rb +27 -0
- data/lib/factory_bot/evaluator.rb +6 -7
- data/lib/factory_bot/evaluator_class_definer.rb +1 -1
- data/lib/factory_bot/factory.rb +12 -12
- data/lib/factory_bot/factory_runner.rb +3 -3
- data/lib/factory_bot/find_definitions.rb +1 -1
- data/lib/factory_bot/internal.rb +12 -25
- data/lib/factory_bot/linter.rb +8 -12
- data/lib/factory_bot/null_factory.rb +11 -5
- data/lib/factory_bot/null_object.rb +2 -6
- data/lib/factory_bot/registry.rb +2 -2
- data/lib/factory_bot/reload.rb +0 -1
- data/lib/factory_bot/sequence.rb +5 -5
- data/lib/factory_bot/strategy/null.rb +4 -2
- data/lib/factory_bot/strategy/stub.rb +6 -2
- data/lib/factory_bot/syntax/default.rb +7 -7
- data/lib/factory_bot/trait.rb +2 -2
- data/lib/factory_bot/version.rb +1 -1
- metadata +12 -40
data/NEWS.md
CHANGED
@@ -1,8 +1,36 @@
|
|
1
1
|
# News
|
2
2
|
|
3
|
+
## 6.2.0 (May 7, 2021)
|
4
|
+
* Added: support for Ruby 3.0
|
5
|
+
* Changed: Include factory or trait name in error messages for missing traits. d05a9a3c
|
6
|
+
* Changed: Switched from Travis CI to GitHub Actions
|
7
|
+
* Fixed: More Ruby 2.7 kwarg deprecation warnings
|
8
|
+
|
9
|
+
## 6.1.0 (July 8, 2020)
|
10
|
+
* Added: public reader for the evaluation instance, helpful for building interrelated associations
|
11
|
+
* Changed: raise a more helpful error when passing an invalid argument to an association
|
12
|
+
* Fixed: Ruby 2.7 kwarg deprecation warnings
|
13
|
+
|
14
|
+
## 6.0.2 (June 19, 2020)
|
15
|
+
* Fixed: bug causing traits to consume more memory each time they were used
|
16
|
+
|
17
|
+
## 6.0.1 (June 19, 2020)
|
18
|
+
* Fixed: bug with constant resolution causing unexpected uninitialized constant errors
|
19
|
+
|
20
|
+
## 6.0.0 (June 18, 2020)
|
21
|
+
* Added: automatic definition of traits for Active Record enum attributes, enabled by default
|
22
|
+
(Note that this required changing where factory_bot constantizes the build
|
23
|
+
class, which may affect applications that were using abstract factories for
|
24
|
+
inheritance. See issue #1409.)
|
25
|
+
* Added: `traits_for_enum` method to define traits for non-Active Record enums
|
26
|
+
* Added: `build_stubbed_starting_id=` option to define the starting id for `build_stubbed`
|
27
|
+
* Removed: deprecated methods on the top-level `FactoryBot` module meant only for internal use
|
28
|
+
* Removed: support for EOL versions of Ruby (2.3, 2.4) and Rails (4.2)
|
29
|
+
* Removed: support for "abstract" factories with no associated class; use traits instead.
|
30
|
+
|
3
31
|
## 5.2.0 (April 24, 2020)
|
4
32
|
* Added: Pass index to block for `*_list` methods
|
5
|
-
* Deprecated: top-level
|
33
|
+
* Deprecated: methods on the top-level `FactoryBot` module meant only for internal use: `callbacks`, `configuration`, `constructor`, `initialize_with`, `register_sequence`, `resent_configuration`, `skip_create`, `to_create`
|
6
34
|
|
7
35
|
## 5.1.2 (March 25, 2020)
|
8
36
|
* Fixed: Ruby 2.7 keyword deprecation warning in FactoryBot.lint
|
@@ -17,7 +45,7 @@
|
|
17
45
|
* Fixed: avoid undefining inherited evaluator methods
|
18
46
|
* Fixed: avoid stubbing id for records without a primary key
|
19
47
|
* Fixed: raise a helpful error for self-referencing traits to avoid a `SystemStackError`
|
20
|
-
* Deprecated: top-level
|
48
|
+
* Deprecated: methods on the top-level `FactoryBot` module meant only for internal use: `allow_class_lookup`, `allow_class_lookup`=, `register_trait`, `trait_by_name`, `traits`, `sequence_by_name`, `sequences`, `factory_by_name`, `register_factory`, `callback_names`, `register_callback`, `register_default_callbacks`, `register_default_strategies`, `strategies`
|
21
49
|
|
22
50
|
## 5.0.2 (February 22, 2019)
|
23
51
|
* Bugfix: raise "Trait not registered" error when passing invalid trait arguments
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# factory_bot [![Build Status][ci-image]][ci] [![Code Climate][grade-image]][grade] [![Gem Version][version-image]][version]
|
1
|
+
# factory_bot [![Build Status][ci-image]][ci] [![Code Climate][grade-image]][grade] [![Gem Version][version-image]][version]
|
2
2
|
|
3
3
|
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
4
|
|
@@ -43,13 +43,7 @@ gem install factory_bot
|
|
43
43
|
Supported Ruby versions
|
44
44
|
-----------------------
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
The factory_bot 3.x+ series supports MRI Ruby 1.9. Additionally, factory_bot
|
49
|
-
3.6+ supports JRuby 1.6.7.2+ while running in 1.9 mode. See [GETTING_STARTED]
|
50
|
-
for more information on configuring the JRuby environment.
|
51
|
-
|
52
|
-
For versions of Ruby prior to 1.9, please use factory_bot 2.x.
|
46
|
+
Supported Ruby versions are listed in [`.github/workflows/build.yml`](https://github.com/thoughtbot/factory_bot/blob/master/.github/workflows/build.yml)
|
53
47
|
|
54
48
|
More Information
|
55
49
|
----------------
|
@@ -100,8 +94,8 @@ See [our other projects][community] or
|
|
100
94
|
|
101
95
|
[community]: https://thoughtbot.com/community?utm_source=github
|
102
96
|
[hire]: https://thoughtbot.com/hire-us?utm_source=github
|
103
|
-
[ci-image]: https://
|
104
|
-
[ci]: https://
|
97
|
+
[ci-image]: https://github.com/thoughtbot/factory_bot/actions/workflows/build.yml/badge.svg
|
98
|
+
[ci]: https://github.com/thoughtbot/factory_bot/actions?query=workflow%3A.github%2Fworkflows%2Fbuild.yml+branch%3Amaster++
|
105
99
|
[grade-image]: https://codeclimate.com/github/thoughtbot/factory_bot/badges/gpa.svg
|
106
100
|
[grade]: https://codeclimate.com/github/thoughtbot/factory_bot
|
107
101
|
[version-image]: https://badge.fury.io/rb/factory_bot.svg
|
data/lib/factory_bot.rb
CHANGED
@@ -32,6 +32,7 @@ require "factory_bot/declaration"
|
|
32
32
|
require "factory_bot/sequence"
|
33
33
|
require "factory_bot/attribute_list"
|
34
34
|
require "factory_bot/trait"
|
35
|
+
require "factory_bot/enum"
|
35
36
|
require "factory_bot/aliases"
|
36
37
|
require "factory_bot/definition"
|
37
38
|
require "factory_bot/definition_proxy"
|
@@ -48,11 +49,14 @@ require "factory_bot/linter"
|
|
48
49
|
require "factory_bot/version"
|
49
50
|
|
50
51
|
module FactoryBot
|
51
|
-
Deprecation = ActiveSupport::Deprecation.new("
|
52
|
+
Deprecation = ActiveSupport::Deprecation.new("7.0", "factory_bot")
|
52
53
|
|
53
54
|
mattr_accessor :use_parent_strategy, instance_accessor: false
|
54
55
|
self.use_parent_strategy = true
|
55
56
|
|
57
|
+
mattr_accessor :automatically_define_enum_traits, instance_accessor: false
|
58
|
+
self.automatically_define_enum_traits = true
|
59
|
+
|
56
60
|
# Look for errors in factories and (optionally) their traits.
|
57
61
|
# Parameters:
|
58
62
|
# factories - which factories to lint; omit for all factories
|
@@ -66,60 +70,22 @@ module FactoryBot
|
|
66
70
|
Linter.new(factories_to_lint, **options).lint!
|
67
71
|
end
|
68
72
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
:register_callback,
|
78
|
-
:register_default_callbacks,
|
79
|
-
:register_default_strategies,
|
80
|
-
:register_factory,
|
81
|
-
:register_sequence,
|
82
|
-
:register_strategy,
|
83
|
-
:register_trait,
|
84
|
-
:reset_configuration,
|
85
|
-
:rewind_sequences,
|
86
|
-
:sequence_by_name,
|
87
|
-
:sequences,
|
88
|
-
:skip_create,
|
89
|
-
:strategies,
|
90
|
-
:strategy_by_name,
|
91
|
-
:to_create,
|
92
|
-
:trait_by_name,
|
93
|
-
:traits,
|
94
|
-
to: Internal
|
95
|
-
|
96
|
-
attr_accessor :allow_class_lookup
|
73
|
+
# Set the starting value for ids when using the build_stubbed strategy
|
74
|
+
#
|
75
|
+
# Arguments:
|
76
|
+
# * starting_id +Integer+
|
77
|
+
# The new starting id value.
|
78
|
+
def self.build_stubbed_starting_id=(starting_id)
|
79
|
+
Strategy::Stub.next_id = starting_id - 1
|
80
|
+
end
|
97
81
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
:factory_by_name,
|
105
|
-
:initialize_with,
|
106
|
-
:register_callback,
|
107
|
-
:register_default_callbacks,
|
108
|
-
:register_default_strategies,
|
109
|
-
:register_factory,
|
110
|
-
:register_sequence,
|
111
|
-
:register_trait,
|
112
|
-
:reset_configuration,
|
113
|
-
:sequence_by_name,
|
114
|
-
:sequences,
|
115
|
-
:skip_create,
|
116
|
-
:strategies,
|
117
|
-
:to_create,
|
118
|
-
:trait_by_name,
|
119
|
-
:traits,
|
120
|
-
deprecator: Deprecation
|
82
|
+
class << self
|
83
|
+
delegate :factories,
|
84
|
+
:register_strategy,
|
85
|
+
:rewind_sequences,
|
86
|
+
:strategy_by_name,
|
87
|
+
to: Internal
|
121
88
|
end
|
122
89
|
end
|
123
90
|
|
124
91
|
FactoryBot::Internal.register_default_strategies
|
125
|
-
FactoryBot::Internal.register_default_callbacks
|
data/lib/factory_bot/aliases.rb
CHANGED
@@ -5,14 +5,14 @@ module FactoryBot
|
|
5
5
|
|
6
6
|
self.aliases = [
|
7
7
|
[/(.+)_id/, '\1'],
|
8
|
-
[/(.*)/, '\1_id']
|
8
|
+
[/(.*)/, '\1_id']
|
9
9
|
]
|
10
10
|
|
11
11
|
def self.aliases_for(attribute)
|
12
|
-
aliases.map
|
12
|
+
aliases.map { |(pattern, replace)|
|
13
13
|
if pattern.match(attribute.to_s)
|
14
14
|
attribute.to_s.sub(pattern, replace).to_sym
|
15
15
|
end
|
16
|
-
|
16
|
+
}.compact << attribute
|
17
17
|
end
|
18
18
|
end
|
@@ -6,12 +6,12 @@ module FactoryBot
|
|
6
6
|
|
7
7
|
def initialize(name, factory, overrides)
|
8
8
|
super(name, false)
|
9
|
-
@factory
|
9
|
+
@factory = factory
|
10
10
|
@overrides = overrides
|
11
11
|
end
|
12
12
|
|
13
13
|
def to_proc
|
14
|
-
factory
|
14
|
+
factory = @factory
|
15
15
|
overrides = @overrides
|
16
16
|
traits_and_overrides = [factory, overrides].flatten
|
17
17
|
factory_name = traits_and_overrides.shift
|
@@ -12,9 +12,9 @@ module FactoryBot
|
|
12
12
|
|
13
13
|
-> {
|
14
14
|
value = case block.arity
|
15
|
-
when 1, -1 then instance_exec(self, &block)
|
15
|
+
when 1, -1, -2 then instance_exec(self, &block)
|
16
16
|
else instance_exec(&block)
|
17
|
-
|
17
|
+
end
|
18
18
|
raise SequenceAbuseError if FactoryBot::Sequence === value
|
19
19
|
|
20
20
|
value
|
@@ -2,10 +2,10 @@ module FactoryBot
|
|
2
2
|
# @api private
|
3
3
|
class AttributeAssigner
|
4
4
|
def initialize(evaluator, build_class, &instance_builder)
|
5
|
-
@build_class
|
6
|
-
@instance_builder
|
7
|
-
@evaluator
|
8
|
-
@attribute_list
|
5
|
+
@build_class = build_class
|
6
|
+
@instance_builder = instance_builder
|
7
|
+
@evaluator = evaluator
|
8
|
+
@attribute_list = evaluator.class.attribute_list
|
9
9
|
@attribute_names_assigned = []
|
10
10
|
end
|
11
11
|
|
@@ -22,9 +22,8 @@ module FactoryBot
|
|
22
22
|
def hash
|
23
23
|
@evaluator.instance = build_hash
|
24
24
|
|
25
|
-
attributes_to_set_on_hash.
|
25
|
+
attributes_to_set_on_hash.each_with_object({}) do |attribute, result|
|
26
26
|
result[attribute] = get(attribute)
|
27
|
-
result
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
@@ -33,13 +32,13 @@ module FactoryBot
|
|
33
32
|
def method_tracking_evaluator
|
34
33
|
@method_tracking_evaluator ||= Decorator::AttributeHash.new(
|
35
34
|
decorated_evaluator,
|
36
|
-
attribute_names_to_assign
|
35
|
+
attribute_names_to_assign
|
37
36
|
)
|
38
37
|
end
|
39
38
|
|
40
39
|
def decorated_evaluator
|
41
40
|
Decorator::InvocationTracker.new(
|
42
|
-
Decorator::NewConstructor.new(@evaluator, @build_class)
|
41
|
+
Decorator::NewConstructor.new(@evaluator, @build_class)
|
43
42
|
)
|
44
43
|
end
|
45
44
|
|
@@ -96,11 +95,11 @@ module FactoryBot
|
|
96
95
|
end
|
97
96
|
|
98
97
|
def alias_names_to_ignore
|
99
|
-
@attribute_list.non_ignored.flat_map
|
98
|
+
@attribute_list.non_ignored.flat_map { |attribute|
|
100
99
|
override_names.map do |override|
|
101
100
|
attribute.name if ignorable_alias?(attribute, override)
|
102
101
|
end
|
103
|
-
|
102
|
+
}.compact
|
104
103
|
end
|
105
104
|
|
106
105
|
def ignorable_alias?(attribute, override)
|
data/lib/factory_bot/callback.rb
CHANGED
@@ -3,16 +3,15 @@ module FactoryBot
|
|
3
3
|
attr_reader :name
|
4
4
|
|
5
5
|
def initialize(name, block)
|
6
|
-
@name
|
6
|
+
@name = name.to_sym
|
7
7
|
@block = block
|
8
|
-
ensure_valid_callback_name!
|
9
8
|
end
|
10
9
|
|
11
10
|
def run(instance, evaluator)
|
12
11
|
case block.arity
|
13
|
-
when 1, -1 then syntax_runner.instance_exec(instance, &block)
|
12
|
+
when 1, -1, -2 then syntax_runner.instance_exec(instance, &block)
|
14
13
|
when 2 then syntax_runner.instance_exec(instance, evaluator, &block)
|
15
|
-
else
|
14
|
+
else syntax_runner.instance_exec(&block)
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
@@ -27,13 +26,6 @@ module FactoryBot
|
|
27
26
|
|
28
27
|
private
|
29
28
|
|
30
|
-
def ensure_valid_callback_name!
|
31
|
-
unless FactoryBot::Internal.callback_names.include?(name)
|
32
|
-
raise InvalidCallbackNameError, "#{name} is not a valid callback name. " +
|
33
|
-
"Valid callback names are #{FactoryBot::Internal.callback_names.inspect}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
29
|
def syntax_runner
|
38
30
|
@syntax_runner ||= SyntaxRunner.new
|
39
31
|
end
|
@@ -7,16 +7,16 @@ module FactoryBot
|
|
7
7
|
:inline_sequences,
|
8
8
|
:sequences,
|
9
9
|
:strategies,
|
10
|
-
:traits
|
10
|
+
:traits
|
11
11
|
)
|
12
12
|
|
13
13
|
def initialize
|
14
|
-
@factories
|
15
|
-
@sequences
|
16
|
-
@traits
|
17
|
-
@strategies
|
14
|
+
@factories = Decorator::DisallowsDuplicatesRegistry.new(Registry.new("Factory"))
|
15
|
+
@sequences = Decorator::DisallowsDuplicatesRegistry.new(Registry.new("Sequence"))
|
16
|
+
@traits = Decorator::DisallowsDuplicatesRegistry.new(Registry.new("Trait"))
|
17
|
+
@strategies = Registry.new("Strategy")
|
18
18
|
@callback_names = Set.new
|
19
|
-
@definition
|
19
|
+
@definition = Definition.new(:configuration)
|
20
20
|
@inline_sequences = []
|
21
21
|
|
22
22
|
to_create(&:save!)
|
@@ -24,7 +24,7 @@ module FactoryBot
|
|
24
24
|
end
|
25
25
|
|
26
26
|
delegate :to_create, :skip_create, :constructor, :before, :after,
|
27
|
-
|
27
|
+
:callback, :callbacks, to: :@definition
|
28
28
|
|
29
29
|
def initialize_with(&block)
|
30
30
|
@definition.define_constructor(&block)
|
@@ -6,6 +6,7 @@ module FactoryBot
|
|
6
6
|
super(name, false)
|
7
7
|
@options = options.dup
|
8
8
|
@overrides = options.extract_options!
|
9
|
+
@factory_name = @overrides.delete(:factory) || name
|
9
10
|
@traits = options
|
10
11
|
end
|
11
12
|
|
@@ -21,20 +22,36 @@ module FactoryBot
|
|
21
22
|
|
22
23
|
private
|
23
24
|
|
25
|
+
attr_reader :factory_name, :overrides, :traits
|
26
|
+
|
24
27
|
def build
|
25
|
-
|
28
|
+
raise_if_arguments_are_declarations!
|
26
29
|
|
27
|
-
|
28
|
-
|
30
|
+
[
|
31
|
+
Attribute::Association.new(
|
32
|
+
name,
|
33
|
+
factory_name,
|
34
|
+
[traits, overrides].flatten
|
35
|
+
)
|
36
|
+
]
|
29
37
|
end
|
30
38
|
|
31
|
-
def
|
32
|
-
if
|
39
|
+
def raise_if_arguments_are_declarations!
|
40
|
+
if factory_name.is_a?(Declaration)
|
33
41
|
raise ArgumentError.new(<<~MSG)
|
34
42
|
Association '#{name}' received an invalid factory argument.
|
35
|
-
Did you mean? 'factory: :#{
|
43
|
+
Did you mean? 'factory: :#{factory_name.name}'
|
36
44
|
MSG
|
37
45
|
end
|
46
|
+
|
47
|
+
overrides.each do |attribute, value|
|
48
|
+
if value.is_a?(Declaration)
|
49
|
+
raise ArgumentError.new(<<~MSG)
|
50
|
+
Association '#{name}' received an invalid attribute override.
|
51
|
+
Did you mean? '#{attribute}: :#{value.name}'
|
52
|
+
MSG
|
53
|
+
end
|
54
|
+
end
|
38
55
|
end
|
39
56
|
end
|
40
57
|
end
|
@@ -6,18 +6,30 @@ module FactoryBot
|
|
6
6
|
@component = component
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
if ::Gem::Version.new(::RUBY_VERSION) >= ::Gem::Version.new("2.7")
|
10
|
+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
11
|
+
def method_missing(...) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
|
12
|
+
@component.send(...)
|
13
|
+
end
|
14
|
+
|
15
|
+
def send(...)
|
16
|
+
__send__(...)
|
17
|
+
end
|
18
|
+
RUBY
|
19
|
+
else
|
20
|
+
def method_missing(name, *args, &block) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
|
21
|
+
@component.send(name, *args, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def send(symbol, *args, &block)
|
25
|
+
__send__(symbol, *args, &block)
|
26
|
+
end
|
11
27
|
end
|
12
28
|
|
13
29
|
def respond_to_missing?(name, include_private = false)
|
14
30
|
@component.respond_to?(name, true) || super
|
15
31
|
end
|
16
32
|
|
17
|
-
def send(symbol, *args, &block)
|
18
|
-
__send__(symbol, *args, &block)
|
19
|
-
end
|
20
|
-
|
21
33
|
def self.const_missing(name)
|
22
34
|
::Object.const_get(name)
|
23
35
|
end
|