factory_bot 5.0.0 → 5.1.2
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 +16 -16
- data/LICENSE +1 -1
- data/NEWS.md +347 -0
- data/README.md +13 -6
- data/lib/factory_bot.rb +43 -79
- data/lib/factory_bot/attribute/dynamic.rb +1 -0
- data/lib/factory_bot/attribute_assigner.rb +1 -1
- data/lib/factory_bot/callback.rb +2 -2
- data/lib/factory_bot/configuration.rb +10 -2
- data/lib/factory_bot/declaration/association.rb +11 -0
- data/lib/factory_bot/declaration/implicit.rb +4 -1
- data/lib/factory_bot/decorator.rb +1 -1
- data/lib/factory_bot/decorator/invocation_tracker.rb +1 -1
- data/lib/factory_bot/definition.rb +6 -4
- data/lib/factory_bot/definition_proxy.rb +16 -10
- data/lib/factory_bot/errors.rb +3 -0
- data/lib/factory_bot/evaluator.rb +2 -2
- data/lib/factory_bot/factory.rb +1 -1
- data/lib/factory_bot/factory_runner.rb +2 -2
- data/lib/factory_bot/internal.rb +102 -0
- data/lib/factory_bot/linter.rb +4 -4
- data/lib/factory_bot/null_factory.rb +1 -1
- data/lib/factory_bot/registry.rb +2 -2
- data/lib/factory_bot/reload.rb +3 -3
- data/lib/factory_bot/strategy/stub.rb +10 -3
- data/lib/factory_bot/strategy_calculator.rb +1 -1
- data/lib/factory_bot/syntax/default.rb +5 -5
- data/lib/factory_bot/syntax/methods.rb +3 -3
- data/lib/factory_bot/trait.rb +5 -3
- data/lib/factory_bot/version.rb +1 -1
- metadata +12 -11
- data/NEWS +0 -323
data/README.md
CHANGED
|
@@ -5,7 +5,7 @@ factory_bot is a fixtures replacement with a straightforward definition syntax,
|
|
|
5
5
|
If you want to use factory_bot with Rails, see
|
|
6
6
|
[factory_bot_rails](https://github.com/thoughtbot/factory_bot_rails).
|
|
7
7
|
|
|
8
|
-
_[Interested in the history of the project name?]
|
|
8
|
+
_[Interested in the history of the project name?][NAME]_
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
### Transitioning from factory\_girl?
|
|
@@ -59,9 +59,13 @@ More Information
|
|
|
59
59
|
* [Issues](https://github.com/thoughtbot/factory_bot/issues)
|
|
60
60
|
* [GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS](https://robots.thoughtbot.com/)
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
[GETTING_STARTED]: https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md
|
|
63
|
+
[NAME]: https://github.com/thoughtbot/factory_bot/blob/master/NAME.md
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
Useful Tools
|
|
66
|
+
------------
|
|
67
|
+
|
|
68
|
+
* [FactoryTrace](https://github.com/djezzzl/factory_trace) - helps to find unused factories and traits.
|
|
65
69
|
|
|
66
70
|
Contributing
|
|
67
71
|
------------
|
|
@@ -75,14 +79,17 @@ community](https://github.com/thoughtbot/factory_bot/graphs/contributors).
|
|
|
75
79
|
License
|
|
76
80
|
-------
|
|
77
81
|
|
|
78
|
-
factory_bot is Copyright © 2008-
|
|
82
|
+
factory_bot is Copyright © 2008-2019 Joe Ferris and thoughtbot. It is free
|
|
79
83
|
software, and may be redistributed under the terms specified in the
|
|
80
|
-
[LICENSE]
|
|
84
|
+
[LICENSE] file.
|
|
85
|
+
|
|
86
|
+
[LICENSE]: https://github.com/thoughtbot/factory_bot/blob/master/LICENSE
|
|
87
|
+
|
|
81
88
|
|
|
82
89
|
About thoughtbot
|
|
83
90
|
----------------
|
|
84
91
|
|
|
85
|
-

|
|
86
93
|
|
|
87
94
|
factory_bot is maintained and funded by thoughtbot, inc.
|
|
88
95
|
The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
data/lib/factory_bot.rb
CHANGED
|
@@ -45,16 +45,17 @@ require "factory_bot/decorator/invocation_tracker"
|
|
|
45
45
|
require "factory_bot/decorator/new_constructor"
|
|
46
46
|
require "factory_bot/linter"
|
|
47
47
|
require "factory_bot/version"
|
|
48
|
+
require "factory_bot/internal"
|
|
48
49
|
|
|
49
50
|
module FactoryBot
|
|
50
|
-
|
|
51
|
+
Deprecation = ActiveSupport::Deprecation.new("6.0", "factory_bot")
|
|
51
52
|
|
|
52
53
|
def self.configuration
|
|
53
|
-
|
|
54
|
+
Internal.configuration
|
|
54
55
|
end
|
|
55
56
|
|
|
56
57
|
def self.reset_configuration
|
|
57
|
-
|
|
58
|
+
Internal.reset_configuration
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
mattr_accessor :use_parent_strategy, instance_accessor: false
|
|
@@ -70,92 +71,55 @@ module FactoryBot
|
|
|
70
71
|
def self.lint(*args)
|
|
71
72
|
options = args.extract_options!
|
|
72
73
|
factories_to_lint = args[0] || FactoryBot.factories
|
|
73
|
-
Linter.new(factories_to_lint, options).lint!
|
|
74
|
+
Linter.new(factories_to_lint, **options).lint!
|
|
74
75
|
end
|
|
75
76
|
|
|
76
77
|
class << self
|
|
77
|
-
delegate :
|
|
78
|
+
delegate :callbacks,
|
|
79
|
+
:callback_names,
|
|
80
|
+
:constructor,
|
|
81
|
+
:factories,
|
|
82
|
+
:initialize_with,
|
|
78
83
|
:sequences,
|
|
79
|
-
:
|
|
80
|
-
:callbacks,
|
|
84
|
+
:skip_create,
|
|
81
85
|
:strategies,
|
|
82
|
-
:callback_names,
|
|
83
86
|
:to_create,
|
|
84
|
-
:
|
|
85
|
-
:initialize_with,
|
|
86
|
-
:constructor,
|
|
87
|
+
:traits,
|
|
87
88
|
to: :configuration
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def self.register_sequence(sequence)
|
|
105
|
-
sequence.names.each do |name|
|
|
106
|
-
sequences.register(name, sequence)
|
|
107
|
-
end
|
|
108
|
-
sequence
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def self.sequence_by_name(name)
|
|
112
|
-
sequences.find(name)
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def self.rewind_sequences
|
|
116
|
-
sequences.each(&:rewind)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def self.register_trait(trait)
|
|
120
|
-
trait.names.each do |name|
|
|
121
|
-
traits.register(name, trait)
|
|
122
|
-
end
|
|
123
|
-
trait
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def self.trait_by_name(name)
|
|
127
|
-
traits.find(name)
|
|
128
|
-
end
|
|
90
|
+
delegate :factory_by_name,
|
|
91
|
+
:register_callback,
|
|
92
|
+
:register_default_callbacks,
|
|
93
|
+
:register_default_strategies,
|
|
94
|
+
:register_factory,
|
|
95
|
+
:register_sequence,
|
|
96
|
+
:register_strategy,
|
|
97
|
+
:register_trait,
|
|
98
|
+
:rewind_sequences,
|
|
99
|
+
:sequence_by_name,
|
|
100
|
+
:strategy_by_name,
|
|
101
|
+
:trait_by_name,
|
|
102
|
+
to: Internal
|
|
129
103
|
|
|
130
|
-
|
|
131
|
-
strategies.register(strategy_name, strategy_class)
|
|
132
|
-
StrategySyntaxMethodRegistrar.new(strategy_name).define_strategy_methods
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def self.strategy_by_name(name)
|
|
136
|
-
strategies.find(name)
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def self.register_default_strategies
|
|
140
|
-
register_strategy(:build, FactoryBot::Strategy::Build)
|
|
141
|
-
register_strategy(:create, FactoryBot::Strategy::Create)
|
|
142
|
-
register_strategy(:attributes_for, FactoryBot::Strategy::AttributesFor)
|
|
143
|
-
register_strategy(:build_stubbed, FactoryBot::Strategy::Stub)
|
|
144
|
-
register_strategy(:null, FactoryBot::Strategy::Null)
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def self.register_default_callbacks
|
|
148
|
-
register_callback(:after_build)
|
|
149
|
-
register_callback(:after_create)
|
|
150
|
-
register_callback(:after_stub)
|
|
151
|
-
register_callback(:before_create)
|
|
152
|
-
end
|
|
104
|
+
attr_accessor :allow_class_lookup
|
|
153
105
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
106
|
+
deprecate :allow_class_lookup,
|
|
107
|
+
:allow_class_lookup=,
|
|
108
|
+
:callback_names,
|
|
109
|
+
:factory_by_name,
|
|
110
|
+
:register_callback,
|
|
111
|
+
:register_default_callbacks,
|
|
112
|
+
:register_default_strategies,
|
|
113
|
+
:register_factory,
|
|
114
|
+
:register_trait,
|
|
115
|
+
:sequence_by_name,
|
|
116
|
+
:sequences,
|
|
117
|
+
:strategies,
|
|
118
|
+
:trait_by_name,
|
|
119
|
+
:traits,
|
|
120
|
+
deprecator: Deprecation
|
|
157
121
|
end
|
|
158
122
|
end
|
|
159
123
|
|
|
160
|
-
FactoryBot.register_default_strategies
|
|
161
|
-
FactoryBot.register_default_callbacks
|
|
124
|
+
FactoryBot::Internal.register_default_strategies
|
|
125
|
+
FactoryBot::Internal.register_default_callbacks
|
|
@@ -2,7 +2,7 @@ module FactoryBot
|
|
|
2
2
|
# @api private
|
|
3
3
|
class AttributeAssigner
|
|
4
4
|
def initialize(evaluator, build_class, &instance_builder)
|
|
5
|
-
@build_class
|
|
5
|
+
@build_class = build_class
|
|
6
6
|
@instance_builder = instance_builder
|
|
7
7
|
@evaluator = evaluator
|
|
8
8
|
@attribute_list = evaluator.class.attribute_list
|
data/lib/factory_bot/callback.rb
CHANGED
|
@@ -28,9 +28,9 @@ module FactoryBot
|
|
|
28
28
|
private
|
|
29
29
|
|
|
30
30
|
def ensure_valid_callback_name!
|
|
31
|
-
unless FactoryBot.callback_names.include?(name)
|
|
31
|
+
unless FactoryBot::Internal.callback_names.include?(name)
|
|
32
32
|
raise InvalidCallbackNameError, "#{name} is not a valid callback name. " +
|
|
33
|
-
"Valid callback names are #{FactoryBot.callback_names.inspect}"
|
|
33
|
+
"Valid callback names are #{FactoryBot::Internal.callback_names.inspect}"
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
module FactoryBot
|
|
2
2
|
# @api private
|
|
3
3
|
class Configuration
|
|
4
|
-
attr_reader
|
|
4
|
+
attr_reader(
|
|
5
|
+
:callback_names,
|
|
6
|
+
:factories,
|
|
7
|
+
:inline_sequences,
|
|
8
|
+
:sequences,
|
|
9
|
+
:strategies,
|
|
10
|
+
:traits,
|
|
11
|
+
)
|
|
5
12
|
|
|
6
13
|
def initialize
|
|
7
14
|
@factories = Decorator::DisallowsDuplicatesRegistry.new(Registry.new("Factory"))
|
|
@@ -10,13 +17,14 @@ module FactoryBot
|
|
|
10
17
|
@strategies = Registry.new("Strategy")
|
|
11
18
|
@callback_names = Set.new
|
|
12
19
|
@definition = Definition.new(:configuration)
|
|
20
|
+
@inline_sequences = []
|
|
13
21
|
|
|
14
22
|
to_create(&:save!)
|
|
15
23
|
initialize_with { new }
|
|
16
24
|
end
|
|
17
25
|
|
|
18
26
|
delegate :to_create, :skip_create, :constructor, :before, :after,
|
|
19
|
-
|
|
27
|
+
:callback, :callbacks, to: :@definition
|
|
20
28
|
|
|
21
29
|
def initialize_with(&block)
|
|
22
30
|
@definition.define_constructor(&block)
|
|
@@ -22,9 +22,20 @@ module FactoryBot
|
|
|
22
22
|
private
|
|
23
23
|
|
|
24
24
|
def build
|
|
25
|
+
ensure_factory_is_not_a_declaration!
|
|
26
|
+
|
|
25
27
|
factory_name = @overrides[:factory] || name
|
|
26
28
|
[Attribute::Association.new(name, factory_name, [@traits, @overrides.except(:factory)].flatten)]
|
|
27
29
|
end
|
|
30
|
+
|
|
31
|
+
def ensure_factory_is_not_a_declaration!
|
|
32
|
+
if @overrides[:factory].is_a?(Declaration)
|
|
33
|
+
raise ArgumentError.new(<<~MSG)
|
|
34
|
+
Association '#{name}' received an invalid factory argument.
|
|
35
|
+
Did you mean? 'factory: :#{@overrides[:factory].name}'
|
|
36
|
+
MSG
|
|
37
|
+
end
|
|
38
|
+
end
|
|
28
39
|
end
|
|
29
40
|
end
|
|
30
41
|
end
|
|
@@ -23,8 +23,11 @@ module FactoryBot
|
|
|
23
23
|
def build
|
|
24
24
|
if FactoryBot.factories.registered?(name)
|
|
25
25
|
[Attribute::Association.new(name, name, {})]
|
|
26
|
-
elsif FactoryBot.sequences.registered?(name)
|
|
26
|
+
elsif FactoryBot::Internal.sequences.registered?(name)
|
|
27
27
|
[Attribute::Sequence.new(name, name, @ignored)]
|
|
28
|
+
elsif @factory.name.to_s == name.to_s
|
|
29
|
+
message = "Self-referencing trait '#{@name}'"
|
|
30
|
+
raise TraitDefinitionError, message
|
|
28
31
|
else
|
|
29
32
|
@factory.inherit_traits([name])
|
|
30
33
|
[]
|
|
@@ -6,7 +6,7 @@ module FactoryBot
|
|
|
6
6
|
@component = component
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def method_missing(name, *args, &block) # rubocop:disable Style/
|
|
9
|
+
def method_missing(name, *args, &block) # rubocop:disable Style/MethodMissingSuper
|
|
10
10
|
@component.send(name, *args, &block)
|
|
11
11
|
end
|
|
12
12
|
|
|
@@ -49,7 +49,7 @@ module FactoryBot
|
|
|
49
49
|
|
|
50
50
|
defined_traits.each do |defined_trait|
|
|
51
51
|
base_traits.each { |bt| bt.define_trait defined_trait }
|
|
52
|
-
additional_traits.each { |
|
|
52
|
+
additional_traits.each { |at| at.define_trait defined_trait }
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
@compiled = true
|
|
@@ -95,7 +95,7 @@ module FactoryBot
|
|
|
95
95
|
|
|
96
96
|
def callback(*names, &block)
|
|
97
97
|
names.each do |name|
|
|
98
|
-
FactoryBot.register_callback(name)
|
|
98
|
+
FactoryBot::Internal.register_callback(name)
|
|
99
99
|
add_callback(Callback.new(name, block))
|
|
100
100
|
end
|
|
101
101
|
end
|
|
@@ -111,17 +111,19 @@ module FactoryBot
|
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
def trait_by_name(name)
|
|
114
|
-
trait_for(name) ||
|
|
114
|
+
trait_for(name) || Internal.trait_by_name(name)
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
def trait_for(name)
|
|
118
|
-
defined_traits.
|
|
118
|
+
@defined_traits_by_name ||= defined_traits.each_with_object({}) { |t, memo| memo[t.name] ||= t }
|
|
119
|
+
@defined_traits_by_name[name.to_s]
|
|
119
120
|
end
|
|
120
121
|
|
|
121
122
|
def initialize_copy(source)
|
|
122
123
|
super
|
|
123
124
|
@attributes = nil
|
|
124
125
|
@compiled = false
|
|
126
|
+
@defined_traits_by_name = nil
|
|
125
127
|
end
|
|
126
128
|
|
|
127
129
|
def aggregate_from_traits_and_self(method_name, &block)
|
|
@@ -88,15 +88,18 @@ module FactoryBot
|
|
|
88
88
|
# end
|
|
89
89
|
#
|
|
90
90
|
# are equivalent.
|
|
91
|
-
def method_missing(name, *args, &block) # rubocop:disable Style/
|
|
92
|
-
|
|
91
|
+
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing, Style/MethodMissingSuper, Metrics/LineLength
|
|
92
|
+
association_options = args.first
|
|
93
|
+
|
|
94
|
+
if association_options.nil?
|
|
93
95
|
__declare_attribute__(name, block)
|
|
94
|
-
elsif
|
|
95
|
-
association(name,
|
|
96
|
+
elsif __valid_association_options?(association_options)
|
|
97
|
+
association(name, association_options)
|
|
96
98
|
else
|
|
97
|
-
raise NoMethodError.new(
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
raise NoMethodError.new(<<~MSG)
|
|
100
|
+
undefined method '#{name}' in '#{@definition.name}' factory
|
|
101
|
+
Did you mean? '#{name} { #{association_options.inspect} }'
|
|
102
|
+
MSG
|
|
100
103
|
end
|
|
101
104
|
end
|
|
102
105
|
|
|
@@ -117,9 +120,8 @@ module FactoryBot
|
|
|
117
120
|
#
|
|
118
121
|
# Except that no globally available sequence will be defined.
|
|
119
122
|
def sequence(name, *args, &block)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
FactoryBot.register_sequence(sequence)
|
|
123
|
+
sequence = Sequence.new(name, *args, &block)
|
|
124
|
+
FactoryBot::Internal.register_inline_sequence(sequence)
|
|
123
125
|
add_attribute(name) { increment_sequence(sequence) }
|
|
124
126
|
end
|
|
125
127
|
|
|
@@ -188,5 +190,9 @@ module FactoryBot
|
|
|
188
190
|
add_attribute(name, &block)
|
|
189
191
|
end
|
|
190
192
|
end
|
|
193
|
+
|
|
194
|
+
def __valid_association_options?(options)
|
|
195
|
+
options.respond_to?(:has_key?) && options.has_key?(:factory)
|
|
196
|
+
end
|
|
191
197
|
end
|
|
192
198
|
end
|
data/lib/factory_bot/errors.rb
CHANGED
|
@@ -2,6 +2,9 @@ module FactoryBot
|
|
|
2
2
|
# Raised when a factory is defined that attempts to instantiate itself.
|
|
3
3
|
class AssociationDefinitionError < RuntimeError; end
|
|
4
4
|
|
|
5
|
+
# Raised when a trait is defined that references itself.
|
|
6
|
+
class TraitDefinitionError < RuntimeError; end
|
|
7
|
+
|
|
5
8
|
# Raised when a callback is defined that has an invalid name
|
|
6
9
|
class InvalidCallbackNameError < RuntimeError; end
|
|
7
10
|
|
|
@@ -37,7 +37,7 @@ module FactoryBot
|
|
|
37
37
|
@instance = object_instance
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
def method_missing(method_name, *args, &block) # rubocop:disable Style/
|
|
40
|
+
def method_missing(method_name, *args, &block) # rubocop:disable Style/MethodMissingSuper
|
|
41
41
|
if @instance.respond_to?(method_name)
|
|
42
42
|
@instance.send(method_name, *args, &block)
|
|
43
43
|
else
|
|
@@ -66,7 +66,7 @@ module FactoryBot
|
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def self.define_attribute(name, &block)
|
|
69
|
-
if
|
|
69
|
+
if instance_methods(false).include?(name) || private_instance_methods(false).include?(name)
|
|
70
70
|
undef_method(name)
|
|
71
71
|
end
|
|
72
72
|
|
data/lib/factory_bot/factory.rb
CHANGED
|
@@ -5,11 +5,11 @@ module FactoryBot
|
|
|
5
5
|
@strategy = strategy
|
|
6
6
|
|
|
7
7
|
@overrides = traits_and_overrides.extract_options!
|
|
8
|
-
@traits = traits_and_overrides
|
|
8
|
+
@traits = traits_and_overrides
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def run(runner_strategy = @strategy, &block)
|
|
12
|
-
factory = FactoryBot.factory_by_name(@name)
|
|
12
|
+
factory = FactoryBot::Internal.factory_by_name(@name)
|
|
13
13
|
|
|
14
14
|
factory.compile
|
|
15
15
|
|