factory_bot 6.5.4 → 6.5.5

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.
@@ -72,7 +72,7 @@ module FactoryBot
72
72
  non_ignored_attribute_names +
73
73
  override_names -
74
74
  ignored_attribute_names -
75
- alias_names_to_ignore
75
+ aliased_attribute_names_to_ignore
76
76
  end
77
77
 
78
78
  def non_ignored_attribute_names
@@ -91,22 +91,39 @@ module FactoryBot
91
91
  @evaluator.__override_names__
92
92
  end
93
93
 
94
+ def attribute_names
95
+ @attribute_list.names
96
+ end
97
+
94
98
  def hash_instance_methods_to_respond_to
95
- @attribute_list.names + override_names + @build_class.instance_methods
99
+ attribute_names + override_names + @build_class.instance_methods
96
100
  end
97
101
 
98
- def alias_names_to_ignore
102
+ ##
103
+ # Creat a list of attribute names that will be
104
+ # overridden by an alias, so any defaults can
105
+ # ignored.
106
+ #
107
+ def aliased_attribute_names_to_ignore
99
108
  @attribute_list.non_ignored.flat_map { |attribute|
100
109
  override_names.map do |override|
101
- attribute.name if ignorable_alias?(attribute, override)
110
+ attribute.name if aliased_attribute?(attribute, override)
102
111
  end
103
112
  }.compact
104
113
  end
105
114
 
106
- def ignorable_alias?(attribute, override)
107
- attribute.alias_for?(override) &&
108
- attribute.name != override &&
109
- !ignored_attribute_names.include?(override)
115
+ ##
116
+ # Is the override an alias for the attribute and not the
117
+ # actual name of another attribute?
118
+ #
119
+ # Note: Checking against the names of all attributes, resolves any
120
+ # issues with having both <attribute> and <attribute>_id
121
+ # in the same factory.
122
+ #
123
+ def aliased_attribute?(attribute, override)
124
+ return false if attribute_names.include?(override)
125
+
126
+ attribute.alias_for?(override)
110
127
  end
111
128
  end
112
129
  end
@@ -4,11 +4,15 @@ module FactoryBot
4
4
  def initialize(callbacks, evaluator)
5
5
  @callbacks = callbacks
6
6
  @evaluator = evaluator
7
+ @completed = []
7
8
  end
8
9
 
9
10
  def update(name, result_instance)
10
11
  callbacks_by_name(name).each do |callback|
11
- callback.run(result_instance, @evaluator)
12
+ if !completed?(result_instance, callback)
13
+ callback.run(result_instance, @evaluator)
14
+ record_completion!(result_instance, callback)
15
+ end
12
16
  end
13
17
  end
14
18
 
@@ -17,5 +21,19 @@ module FactoryBot
17
21
  def callbacks_by_name(name)
18
22
  @callbacks.select { |callback| callback.name == name }
19
23
  end
24
+
25
+ def completed?(instance, callback)
26
+ key = completion_key_for(instance, callback)
27
+ @completed.include?(key)
28
+ end
29
+
30
+ def record_completion!(instance, callback)
31
+ key = completion_key_for(instance, callback)
32
+ @completed << key
33
+ end
34
+
35
+ def completion_key_for(instance, callback)
36
+ "#{instance.object_id}-#{callback.object_id}"
37
+ end
20
38
  end
21
39
  end
@@ -1,4 +1,3 @@
1
- require "active_support/core_ext/hash/except"
2
1
  require "active_support/core_ext/class/attribute"
3
2
 
4
3
  module FactoryBot
@@ -51,8 +50,15 @@ module FactoryBot
51
50
  @overrides.keys
52
51
  end
53
52
 
54
- def increment_sequence(sequence)
55
- sequence.next(self)
53
+ def increment_sequence(sequence, scope: self)
54
+ value = sequence.next(scope)
55
+
56
+ raise if value.respond_to?(:start_with?) && value.start_with?("#<FactoryBot::Declaration")
57
+
58
+ value
59
+ rescue
60
+ raise ArgumentError, "Sequence '#{sequence.uri_manager.first}' failed to " \
61
+ "return a value. Perhaps it needs a scope to operate? (scope: <object>)"
56
62
  end
57
63
 
58
64
  def self.attribute_list
@@ -33,6 +33,7 @@ module FactoryBot
33
33
 
34
34
  def run(build_strategy, overrides, &block)
35
35
  block ||= ->(result) { result }
36
+
36
37
  compile
37
38
 
38
39
  strategy = StrategyCalculator.new(build_strategy).strategy.new
@@ -44,7 +45,11 @@ module FactoryBot
44
45
  evaluation =
45
46
  Evaluation.new(evaluator, attribute_assigner, compiled_to_create, observer)
46
47
 
47
- strategy.result(evaluation).tap(&block)
48
+ evaluation.notify(:before_all, nil)
49
+ instance = strategy.result(evaluation).tap(&block)
50
+ evaluation.notify(:after_all, instance)
51
+
52
+ instance
48
53
  end
49
54
 
50
55
  def human_names
@@ -1,4 +1,4 @@
1
- require "active_support/core_ext/hash/indifferent_access"
1
+ require "active_support/hash_with_indifferent_access"
2
2
 
3
3
  module FactoryBot
4
4
  class Registry
@@ -150,25 +150,24 @@ module FactoryBot
150
150
  end
151
151
 
152
152
  class EnumeratorAdapter
153
- def initialize(value)
154
- @first_value = value
155
- @value = value
153
+ def initialize(initial_value)
154
+ @initial_value = initial_value
156
155
  end
157
156
 
158
157
  def peek
159
- @value
158
+ value
160
159
  end
161
160
 
162
161
  def next
163
- @value = @value.next
162
+ @value = value.next
164
163
  end
165
164
 
166
165
  def rewind
167
- @value = @first_value
166
+ @value = first_value
168
167
  end
169
168
 
170
169
  def set_value(new_value)
171
- if new_value >= @first_value
170
+ if new_value >= first_value
172
171
  @value = new_value
173
172
  else
174
173
  fail ArgumentError, "Value cannot be less than: #{@first_value}"
@@ -176,7 +175,22 @@ module FactoryBot
176
175
  end
177
176
 
178
177
  def integer_value?
179
- @first_value.is_a?(Integer)
178
+ first_value.is_a?(Integer)
179
+ end
180
+
181
+ private
182
+
183
+ def first_value
184
+ @first_value ||= initial_value
185
+ end
186
+
187
+ def value
188
+ @value ||= initial_value
189
+ end
190
+
191
+ def initial_value
192
+ @value = @initial_value.respond_to?(:call) ? @initial_value.call : @initial_value
193
+ @first_value = @value
180
194
  end
181
195
  end
182
196
  end
@@ -6,6 +6,8 @@ module FactoryBot
6
6
  end
7
7
 
8
8
  def result(evaluation)
9
+ evaluation.notify(:before_build, nil)
10
+
9
11
  evaluation.object.tap do |instance|
10
12
  evaluation.notify(:after_build, instance)
11
13
  end
@@ -6,6 +6,8 @@ module FactoryBot
6
6
  end
7
7
 
8
8
  def result(evaluation)
9
+ evaluation.notify(:before_build, nil)
10
+
9
11
  evaluation.object.tap do |instance|
10
12
  evaluation.notify(:after_build, instance)
11
13
  evaluation.notify(:before_create, instance)
@@ -123,7 +123,7 @@ module FactoryBot
123
123
  raise(KeyError,
124
124
  "Sequence not registered: #{FactoryBot::UriManager.build_uri(uri_parts)}")
125
125
 
126
- increment_sequence(uri, sequence, scope: scope)
126
+ increment_sequence(sequence, scope: scope)
127
127
  end
128
128
 
129
129
  # Generates and returns the list of values in a global or factory sequence.
@@ -147,7 +147,7 @@ module FactoryBot
147
147
  raise(KeyError, "Sequence not registered: '#{uri}'")
148
148
 
149
149
  (1..count).map do
150
- increment_sequence(uri, sequence, scope: scope)
150
+ increment_sequence(sequence, scope: scope)
151
151
  end
152
152
  end
153
153
 
@@ -161,21 +161,19 @@ module FactoryBot
161
161
  # Increments the given sequence and returns the value.
162
162
  #
163
163
  # Arguments:
164
- # uri: (Symbol)
165
- # The URI for the sequence
166
164
  # sequence:
167
165
  # The sequence instance
168
166
  # scope: (object)(optional)
169
167
  # The object the sequence should be evaluated within
170
168
  #
171
- def increment_sequence(uri, sequence, scope: nil)
169
+ def increment_sequence(sequence, scope: nil)
172
170
  value = sequence.next(scope)
173
171
 
174
172
  raise if value.respond_to?(:start_with?) && value.start_with?("#<FactoryBot::Declaration")
175
173
 
176
174
  value
177
175
  rescue
178
- raise ArgumentError, "Sequence '#{uri}' failed to " \
176
+ raise ArgumentError, "Sequence '#{sequence.uri_manager.first}' failed to " \
179
177
  "return a value. Perhaps it needs a scope to operate? (scope: <object>)"
180
178
  end
181
179
  end
@@ -1,3 +1,3 @@
1
1
  module FactoryBot
2
- VERSION = "6.5.4".freeze
2
+ VERSION = "6.5.5".freeze
3
3
  end
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
4
+ version: 6.5.5
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: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2025-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -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.6.7
269
+ rubygems_version: 3.6.2
270
270
  specification_version: 4
271
271
  summary: factory_bot provides a framework and DSL for defining and using model instance
272
272
  factories.