factory_bot 6.5.1 → 6.5.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 71c90d06521a4d6e1bbd613bdc1494919b2acde4117153524a11d8fbea53301c
4
- data.tar.gz: 7e19bf127cf040c9f59fea525894019358e0502de695cf5957ac5eb91280e1d1
3
+ metadata.gz: 3ccc22d510028071ae2280e2c34cb7320bf433337da499e8692aedce4b67edba
4
+ data.tar.gz: 3c9b2f007fd5086de47e1a20f0ea721179aa2b39eb9007238dec107454923ae6
5
5
  SHA512:
6
- metadata.gz: ff1b56b976b423b91d8f633fdb0d1ed2d13b5c75665547adbb4d6f1d90b15aff35459dcb2fd6479e6dccdfd98ce3a9bd2a13b1ced002704fb84c39e2d5ebb3f3
7
- data.tar.gz: dfc7713d8511e0723ab41da77257c901ca2d5abdf04b21b8f81332bd4f6e6568d403a68fc7831529ab8cbed531c25bc068458ee28fb2b1d7f0b7ebeafda02a3a
6
+ metadata.gz: 9c466fd487ceaa143f8d021033af08519b2c804740279c0fa13337e2834003ce6b716b960db2aff75d283ab75a69d62c88b0193fbd7f1fe80247938cae8c28d7
7
+ data.tar.gz: 5ba4abca5823566a808f4ebfd5ac8e65efadc90dad30cb9c501ec788a95c544969105f5b687550cc1cac5696e139eea536d96326167007ec7f485dc5c016ae88
data/GETTING_STARTED.md CHANGED
@@ -255,10 +255,12 @@ Factories can be defined anywhere, but will be automatically loaded after
255
255
  calling `FactoryBot.find_definitions` if factories are defined in files at the
256
256
  following locations:
257
257
 
258
+ factories.rb
259
+ factories/**/*.rb
258
260
  test/factories.rb
261
+ test/factories/**/*.rb
259
262
  spec/factories.rb
260
- test/factories/*.rb
261
- spec/factories/*.rb
263
+ spec/factories/**/*.rb
262
264
 
263
265
  ### Static Attributes
264
266
 
data/NEWS.md CHANGED
@@ -1,9 +1,25 @@
1
1
  # News
2
2
 
3
+ ## 6.5.3 (June 2, 2025)
4
+
5
+ * Fix: Factory sequences without blocks (CodeMeister)
6
+ * Added: New methods for setting, generating and rewinding sequences (CodeMeister)
7
+
8
+ ## 6.5.2 (May 30, 2025)
9
+
10
+ * Changed: Updated "verbose linting" test to allow for backtrace changes in Ruby 3.4 (CodeMeister)
11
+ * Fix: Set the same timestamps for `created_at` and `updated_at` on `build_stubbed` (Kim Emmanuel)
12
+ * Fix: Refactored sequences to ensure cloned traits use parent sequences. (CodeMeister)
13
+ * Docs: Fix definition_file_paths comment (Milo Winningham)
14
+ * Docs: Add ruby-lsp extensions to Useful Tools in README.md (johansenja)
15
+ * Docs: Fix docs about definition file paths (Ryo Nakamura)
16
+ * Docs: Update has_many-associations.md to mention that traits can use inline associations (Matthew Zagaja)
17
+ * Docs: Fix "Transitioning from Factory Girl" guide link (Neil Carvalho)
18
+
3
19
  ## 6.5.1 (January 31, 2025)
4
20
 
5
21
  * Changed: execute linting tests within ActiveRecord transactions when available (Sean Doyle)
6
- * Fix: Random test failure when tracking compilation time (CodeMeinster)
22
+ * Fix: Random test failure when tracking compilation time (CodeMeister)
7
23
  * Fix: Bump the minimum required activesupport version to 6.1 (Earlopain)
8
24
  * Internal: Update development dependencies (Neil Carvalho)
9
25
 
data/README.md CHANGED
@@ -10,7 +10,7 @@ _[Interested in the history of the project name?][NAME]_
10
10
 
11
11
  ### Transitioning from factory\_girl?
12
12
 
13
- Check out the [guide](https://github.com/thoughtbot/factory_bot/blob/4-9-0-stable/UPGRADE_FROM_FACTORY_GIRL.md).
13
+ Check out the [guide](https://github.com/thoughtbot/factory_bot/blob/v4.9.0/UPGRADE_FROM_FACTORY_GIRL.md).
14
14
 
15
15
 
16
16
  Documentation
@@ -62,6 +62,7 @@ Useful Tools
62
62
  ------------
63
63
 
64
64
  * [FactoryTrace](https://github.com/djezzzl/factory_trace) - helps to find unused factories and traits.
65
+ * [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
65
66
 
66
67
  Contributing
67
68
  ------------
@@ -96,7 +97,6 @@ We are [available for hire][hire].
96
97
  [community]: https://thoughtbot.com/community?utm_source=github
97
98
  [hire]: https://thoughtbot.com/hire-us?utm_source=github
98
99
 
99
-
100
100
  <!-- END /templates/footer.md -->
101
101
 
102
102
  [ci-image]: https://github.com/thoughtbot/factory_bot/actions/workflows/build.yml/badge.svg?branch=main
@@ -1,11 +1,12 @@
1
1
  module FactoryBot
2
2
  # @api private
3
3
  class Definition
4
- attr_reader :defined_traits, :declarations, :name, :registered_enums
4
+ attr_reader :defined_traits, :declarations, :name, :registered_enums, :uri_manager
5
5
  attr_accessor :klass
6
6
 
7
- def initialize(name, base_traits = [])
7
+ def initialize(name, base_traits = [], **opts)
8
8
  @name = name
9
+ @uri_manager = opts[:uri_manager]
9
10
  @declarations = DeclarationList.new(name)
10
11
  @callbacks = []
11
12
  @defined_traits = Set.new
@@ -21,7 +21,7 @@ module FactoryBot
21
21
 
22
22
  delegate :before, :after, :callback, to: :@definition
23
23
 
24
- attr_reader :child_factories
24
+ attr_reader :child_factories, :definition
25
25
 
26
26
  def initialize(definition, ignore = false)
27
27
  @definition = definition
@@ -119,10 +119,14 @@ module FactoryBot
119
119
  # end
120
120
  #
121
121
  # Except that no globally available sequence will be defined.
122
- def sequence(name, ...)
123
- sequence = Sequence.new(name, ...)
124
- FactoryBot::Internal.register_inline_sequence(sequence)
125
- add_attribute(name) { increment_sequence(sequence) }
122
+ def sequence(name, *args, &block)
123
+ options = args.extract_options!
124
+ options[:uri_paths] = definition.uri_manager.to_a
125
+ args << options
126
+
127
+ new_sequence = Sequence.new(name, *args, &block)
128
+ registered_sequence = __fetch_or_register_sequence(new_sequence)
129
+ add_attribute(name) { increment_sequence(registered_sequence) }
126
130
  end
127
131
 
128
132
  # Adds an attribute that builds an association. The associated instance will
@@ -169,11 +173,11 @@ module FactoryBot
169
173
  end
170
174
 
171
175
  def factory(name, options = {}, &block)
172
- @child_factories << [name, options, block]
176
+ child_factories << [name, options, block]
173
177
  end
174
178
 
175
179
  def trait(name, &block)
176
- @definition.define_trait(Trait.new(name, &block))
180
+ @definition.define_trait(Trait.new(name, uri_paths: definition.uri_manager.to_a, &block))
177
181
  end
178
182
 
179
183
  # Creates traits for enumerable values.
@@ -252,5 +256,14 @@ module FactoryBot
252
256
  def __valid_association_options?(options)
253
257
  options.respond_to?(:has_key?) && options.has_key?(:factory)
254
258
  end
259
+
260
+ ##
261
+ # If the inline sequence has already been registered by a parent,
262
+ # return that one, otherwise register and return the given sequence
263
+ #
264
+ def __fetch_or_register_sequence(sequence)
265
+ FactoryBot::Sequence.find_by_uri(sequence.uri_manager.first) ||
266
+ FactoryBot::Internal.register_inline_sequence(sequence)
267
+ end
255
268
  end
256
269
  end
@@ -12,7 +12,8 @@ module FactoryBot
12
12
  @parent = options[:parent]
13
13
  @aliases = options[:aliases] || []
14
14
  @class_name = options[:class]
15
- @definition = Definition.new(@name, options[:traits] || [])
15
+ @uri_manager = FactoryBot::UriManager.new(names)
16
+ @definition = Definition.new(@name, options[:traits] || [], uri_manager: @uri_manager)
16
17
  @compiled = false
17
18
  end
18
19
 
@@ -2,8 +2,8 @@ module FactoryBot
2
2
  class << self
3
3
  # An Array of strings specifying locations that should be searched for
4
4
  # factory definitions. By default, factory_bot will attempt to require
5
- # "factories", "test/factories" and "spec/factories". Only the first
6
- # existing file will be loaded.
5
+ # "factories.rb", "factories/**/*.rb", "test/factories.rb",
6
+ # "test/factories/**.rb", "spec/factories.rb", and "spec/factories/**.rb".
7
7
  attr_accessor :definition_file_paths
8
8
  end
9
9
 
@@ -26,6 +26,7 @@ module FactoryBot
26
26
 
27
27
  def register_inline_sequence(sequence)
28
28
  inline_sequences.push(sequence)
29
+ sequence
29
30
  end
30
31
 
31
32
  def rewind_inline_sequences
@@ -59,6 +60,22 @@ module FactoryBot
59
60
  rewind_inline_sequences
60
61
  end
61
62
 
63
+ def rewind_sequence(*uri_parts)
64
+ fail_argument_count(0, "1+") if uri_parts.empty?
65
+
66
+ uri = build_uri(uri_parts)
67
+ sequence = Sequence.find_by_uri(uri) || fail_unregistered_sequence(uri)
68
+
69
+ sequence.rewind
70
+ end
71
+
72
+ def set_sequence(*uri_parts, value)
73
+ uri = build_uri(uri_parts) || fail_argument_count(uri_parts.size, "2+")
74
+ sequence = Sequence.find(*uri) || fail_unregistered_sequence(uri)
75
+
76
+ sequence.set_value(value)
77
+ end
78
+
62
79
  def register_factory(factory)
63
80
  factory.names.each do |name|
64
81
  factories.register(name, factory)
@@ -86,6 +103,22 @@ module FactoryBot
86
103
  register_strategy(:build_stubbed, FactoryBot::Strategy::Stub)
87
104
  register_strategy(:null, FactoryBot::Strategy::Null)
88
105
  end
106
+
107
+ private
108
+
109
+ def build_uri(...)
110
+ FactoryBot::UriManager.build_uri(...)
111
+ end
112
+
113
+ def fail_argument_count(received, expected)
114
+ fail ArgumentError,
115
+ "wrong number of arguments (given #{received}, expected #{expected})"
116
+ end
117
+
118
+ def fail_unregistered_sequence(uri)
119
+ fail KeyError,
120
+ "Sequence not registered: '#{uri}'."
121
+ end
89
122
  end
90
123
  end
91
124
  end
@@ -1,17 +1,33 @@
1
+ require "timeout"
2
+
1
3
  module FactoryBot
2
4
  # Sequences are defined using sequence within a FactoryBot.define block.
3
5
  # Sequence values are generated using next.
4
6
  # @api private
5
7
  class Sequence
6
- attr_reader :name
8
+ attr_reader :name, :uri_manager, :aliases
9
+
10
+ def self.find(*uri_parts)
11
+ if uri_parts.empty?
12
+ fail ArgumentError, "wrong number of arguments, expected 1+)"
13
+ else
14
+ find_by_uri FactoryBot::UriManager.build_uri(*uri_parts)
15
+ end
16
+ end
17
+
18
+ def self.find_by_uri(uri)
19
+ uri = uri.to_sym
20
+ (FactoryBot::Internal.sequences.to_a.find { |seq| seq.has_uri?(uri) }) ||
21
+ (FactoryBot::Internal.inline_sequences.find { |seq| seq.has_uri?(uri) })
22
+ end
7
23
 
8
24
  def initialize(name, *args, &proc)
25
+ options = args.extract_options!
9
26
  @name = name
10
27
  @proc = proc
11
-
12
- options = args.extract_options!
28
+ @aliases = options.fetch(:aliases, []).map(&:to_sym)
29
+ @uri_manager = FactoryBot::UriManager.new(names, paths: options[:uri_paths])
13
30
  @value = args.first || 1
14
- @aliases = options.fetch(:aliases) { [] }
15
31
 
16
32
  unless @value.respond_to?(:peek)
17
33
  @value = EnumeratorAdapter.new(@value)
@@ -34,10 +50,40 @@ module FactoryBot
34
50
  [@name] + @aliases
35
51
  end
36
52
 
53
+ def has_name?(test_name)
54
+ names.include?(test_name.to_sym)
55
+ end
56
+
57
+ def has_uri?(uri)
58
+ uri_manager.include?(uri)
59
+ end
60
+
61
+ def for_factory?(test_factory_name)
62
+ FactoryBot::Internal.factory_by_name(factory_name).names.include?(test_factory_name.to_sym)
63
+ end
64
+
37
65
  def rewind
38
66
  @value.rewind
39
67
  end
40
68
 
69
+ ##
70
+ # If it's an Integer based sequence, set the new value directly,
71
+ # else rewind and seek from the beginning until a match is found.
72
+ #
73
+ def set_value(new_value)
74
+ if can_set_value_directly?(new_value)
75
+ @value.set_value(new_value)
76
+ elsif can_set_value_by_index?
77
+ set_value_by_index(new_value)
78
+ else
79
+ seek_value(new_value)
80
+ end
81
+ end
82
+
83
+ protected
84
+
85
+ attr_reader :proc
86
+
41
87
  private
42
88
 
43
89
  def value
@@ -48,6 +94,61 @@ module FactoryBot
48
94
  @value.next
49
95
  end
50
96
 
97
+ def can_set_value_by_index?
98
+ @value.respond_to?(:find_index)
99
+ end
100
+
101
+ ##
102
+ # Set to the given value, or fail if not found
103
+ #
104
+ def set_value_by_index(value)
105
+ index = @value.find_index(value) || fail_value_not_found(value)
106
+ @value.rewind
107
+ index.times { @value.next }
108
+ end
109
+
110
+ ##
111
+ # Rewind index and seek until the value is found or the max attempts
112
+ # have been tried. If not found, the sequence is rewound to its original value
113
+ #
114
+ def seek_value(value)
115
+ original_value = @value.peek
116
+
117
+ # rewind and search for the new value
118
+ @value.rewind
119
+ Timeout.timeout(FactoryBot.sequence_setting_timeout) do
120
+ loop do
121
+ return if @value.peek == value
122
+ increment_value
123
+ end
124
+
125
+ # loop auto-recues a StopIteration error, so if we
126
+ # reached this point, re-raise it now
127
+ fail StopIteration
128
+ end
129
+ rescue Timeout::Error, StopIteration
130
+ reset_original_value(original_value)
131
+ fail_value_not_found(value)
132
+ end
133
+
134
+ def reset_original_value(original_value)
135
+ @value.rewind
136
+
137
+ until @value.peek == original_value
138
+ increment_value
139
+ end
140
+ end
141
+
142
+ def can_set_value_directly?(value)
143
+ return false unless value.is_a?(Integer)
144
+ return false unless @value.is_a?(EnumeratorAdapter)
145
+ @value.integer_value?
146
+ end
147
+
148
+ def fail_value_not_found(value)
149
+ fail ArgumentError, "Unable to find '#{value}' in the sequence."
150
+ end
151
+
51
152
  class EnumeratorAdapter
52
153
  def initialize(value)
53
154
  @first_value = value
@@ -65,6 +166,18 @@ module FactoryBot
65
166
  def rewind
66
167
  @value = @first_value
67
168
  end
169
+
170
+ def set_value(new_value)
171
+ if new_value >= @first_value
172
+ @value = new_value
173
+ else
174
+ fail ArgumentError, "Value cannot be less than: #{@first_value}"
175
+ end
176
+ end
177
+
178
+ def integer_value?
179
+ @first_value.is_a?(Integer)
180
+ end
68
181
  end
69
182
  end
70
183
  end
@@ -102,12 +102,14 @@ module FactoryBot
102
102
  end
103
103
 
104
104
  def set_timestamps(result_instance)
105
+ timestamp = Time.current
106
+
105
107
  if missing_created_at?(result_instance)
106
- result_instance.created_at = Time.current
108
+ result_instance.created_at = timestamp
107
109
  end
108
110
 
109
111
  if missing_updated_at?(result_instance)
110
- result_instance.updated_at = Time.current
112
+ result_instance.updated_at = timestamp
111
113
  end
112
114
  end
113
115
 
@@ -102,33 +102,82 @@ module FactoryBot
102
102
  # @param [Array<Symbol, Symbol, Hash>] traits_and_overrides splat args traits and a hash of overrides
103
103
  # @param [Proc] block block to be executed
104
104
 
105
- # Generates and returns the next value in a sequence.
105
+ # Generates and returns the next value in a global or factory sequence.
106
106
  #
107
107
  # Arguments:
108
- # name: (Symbol)
109
- # The name of the sequence that a value should be generated for.
108
+ # context: (Array of Symbols)
109
+ # The definition context of the sequence, with the sequence name
110
+ # as the final entry
111
+ # scope: (object)(optional)
112
+ # The object the sequence should be evaluated within
110
113
  #
111
114
  # Returns:
112
115
  # The next value in the sequence. (Object)
113
- def generate(name)
114
- Internal.sequence_by_name(name).next
116
+ #
117
+ # Example:
118
+ # generate(:my_factory, :my_trair, :my_sequence)
119
+ #
120
+ def generate(*uri_parts, scope: nil)
121
+ uri = FactoryBot::UriManager.build_uri(uri_parts)
122
+ sequence = Sequence.find_by_uri(uri) ||
123
+ raise(KeyError,
124
+ "Sequence not registered: #{FactoryBot::UriManager.build_uri(uri_parts)}")
125
+
126
+ increment_sequence(uri, sequence, scope: scope)
115
127
  end
116
128
 
117
- # Generates and returns the list of values in a sequence.
129
+ # Generates and returns the list of values in a global or factory sequence.
118
130
  #
119
131
  # Arguments:
120
- # name: (Symbol)
121
- # The name of the sequence that a value should be generated for.
122
- # count: (Fixnum)
123
- # Count of values
132
+ # uri_parts: (Array of Symbols)
133
+ # The definition context of the sequence, with the sequence name
134
+ # as the final entry
135
+ # scope: (object)(optional)
136
+ # The object the sequence should be evaluated within
124
137
  #
125
138
  # Returns:
126
139
  # The next value in the sequence. (Object)
127
- def generate_list(name, count)
140
+ #
141
+ # Example:
142
+ # generate_list(:my_factory, :my_trair, :my_sequence, 5)
143
+ #
144
+ def generate_list(*uri_parts, count, scope: nil)
145
+ uri = FactoryBot::UriManager.build_uri(uri_parts)
146
+ sequence = Sequence.find_by_uri(uri) ||
147
+ raise(KeyError, "Sequence not registered: '#{uri}'")
148
+
128
149
  (1..count).map do
129
- Internal.sequence_by_name(name).next
150
+ increment_sequence(uri, sequence, scope: scope)
130
151
  end
131
152
  end
153
+
154
+ # ======================================================================
155
+ # = PRIVATE
156
+ # ======================================================================
157
+ #
158
+ private
159
+
160
+ ##
161
+ # Increments the given sequence and returns the value.
162
+ #
163
+ # Arguments:
164
+ # uri: (Symbol)
165
+ # The URI for the sequence
166
+ # sequence:
167
+ # The sequence instance
168
+ # scope: (object)(optional)
169
+ # The object the sequence should be evaluated within
170
+ #
171
+ def increment_sequence(uri, sequence, scope: nil)
172
+ value = sequence.next(scope)
173
+
174
+ raise if value.respond_to?(:start_with?) && value.start_with?("#<FactoryBot::Declaration")
175
+
176
+ value
177
+ rescue
178
+ raise ArgumentError, "Sequence '#{uri}' failed to " \
179
+ "return a value. Perhaps it needs a scope to operate? (scope: <object>)"
180
+ end
132
181
  end
133
182
  end
134
183
  end
@@ -1,12 +1,17 @@
1
1
  module FactoryBot
2
2
  # @api private
3
3
  class Trait
4
- attr_reader :name, :definition
4
+ attr_reader :name, :uid, :definition
5
5
 
6
- def initialize(name, &block)
6
+ delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor,
7
+ :callbacks, :attributes, :klass, :klass=, to: :@definition
8
+
9
+ def initialize(name, **options, &block)
7
10
  @name = name.to_s
8
11
  @block = block
9
- @definition = Definition.new(@name)
12
+ @uri_manager = FactoryBot::UriManager.new(names, paths: options[:uri_paths])
13
+
14
+ @definition = Definition.new(@name, uri_manager: @uri_manager)
10
15
  proxy = FactoryBot::DefinitionProxy.new(@definition)
11
16
 
12
17
  if block
@@ -15,12 +20,9 @@ module FactoryBot
15
20
  end
16
21
 
17
22
  def clone
18
- Trait.new(name, &block)
23
+ Trait.new(name, uri_paths: definition.uri_manager.paths, &block)
19
24
  end
20
25
 
21
- delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor,
22
- :callbacks, :attributes, :klass, :klass=, to: :@definition
23
-
24
26
  def names
25
27
  [@name]
26
28
  end
@@ -0,0 +1,63 @@
1
+ module FactoryBot
2
+ # @api private
3
+ class UriManager
4
+ attr_reader :endpoints, :paths, :uri_list
5
+
6
+ delegate :size, :any?, :empty?, :each?, :include?, :first, to: :@uri_list
7
+ delegate :build_uri, to: :class
8
+
9
+ # Concatenate the parts, sripping leading/following slashes
10
+ # and returning a Symbolized String or nil.
11
+ #
12
+ # Example:
13
+ # build_uri(:my_factory, :my_trait, :my_sequence)
14
+ # #=> :"myfactory/my_trait/my_sequence"
15
+ #
16
+ def self.build_uri(*parts)
17
+ return nil if parts.empty?
18
+
19
+ parts.join("/")
20
+ .sub(/\A\/+/, "")
21
+ .sub(/\/+\z/, "")
22
+ .tr(" ", "_")
23
+ .to_sym
24
+ end
25
+
26
+ # Configures the new UriManager
27
+ #
28
+ # Arguments:
29
+ # endpoints: (Array of Strings or Symbols)
30
+ # the objects endpoints.
31
+ #
32
+ # paths: (Array of Strings or Symbols)
33
+ # the parent URIs to prepend to each endpoint
34
+ #
35
+ def initialize(*endpoints, paths: [])
36
+ if endpoints.empty?
37
+ fail ArgumentError, "wrong number of arguments (given 0, expected 1+)"
38
+ end
39
+
40
+ @uri_list = []
41
+ @endpoints = endpoints.flatten
42
+ @paths = Array(paths).flatten
43
+
44
+ build_uri_list
45
+ end
46
+
47
+ def to_a
48
+ @uri_list.dup
49
+ end
50
+
51
+ private
52
+
53
+ def build_uri_list
54
+ @endpoints.each do |endpoint|
55
+ if @paths.any?
56
+ @paths.each { |path| @uri_list << build_uri(path, endpoint) }
57
+ else
58
+ @uri_list << build_uri(endpoint)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,3 +1,3 @@
1
1
  module FactoryBot
2
- VERSION = "6.5.1".freeze
2
+ VERSION = "6.5.3".freeze
3
3
  end
data/lib/factory_bot.rb CHANGED
@@ -46,6 +46,7 @@ require "factory_bot/decorator/attribute_hash"
46
46
  require "factory_bot/decorator/disallows_duplicates_registry"
47
47
  require "factory_bot/decorator/invocation_tracker"
48
48
  require "factory_bot/decorator/new_constructor"
49
+ require "factory_bot/uri_manager"
49
50
  require "factory_bot/linter"
50
51
  require "factory_bot/version"
51
52
 
@@ -58,6 +59,9 @@ module FactoryBot
58
59
  mattr_accessor :automatically_define_enum_traits, instance_accessor: false
59
60
  self.automatically_define_enum_traits = true
60
61
 
62
+ mattr_accessor :sequence_setting_timeout, instance_accessor: false
63
+ self.sequence_setting_timeout = 3
64
+
61
65
  # Look for errors in factories and (optionally) their traits.
62
66
  # Parameters:
63
67
  # factories - which factories to lint; omit for all factories
@@ -73,17 +77,43 @@ module FactoryBot
73
77
 
74
78
  # Set the starting value for ids when using the build_stubbed strategy
75
79
  #
76
- # Arguments:
77
- # * starting_id +Integer+
78
- # The new starting id value.
80
+ # @param [Integer] starting_id The new starting id value.
79
81
  def self.build_stubbed_starting_id=(starting_id)
80
82
  Strategy::Stub.next_id = starting_id - 1
81
83
  end
82
84
 
83
85
  class << self
86
+ # @!method rewind_sequence(*uri_parts)
87
+ # Rewind an individual global or inline sequence.
88
+ #
89
+ # @param [Array<Symbol>, String] uri_parts The components of the sequence URI.
90
+ #
91
+ # @example Rewinding a sequence by its URI parts
92
+ # rewind_sequence(:factory_name, :trait_name, :sequence_name)
93
+ #
94
+ # @example Rewinding a sequence by its URI string
95
+ # rewind_sequence("factory_name/trait_name/sequence_name")
96
+ #
97
+ # @!method set_sequence(*uri_parts, value)
98
+ # Set the sequence to a specific value, providing the new value is within
99
+ # the sequence set.
100
+ #
101
+ # @param [Array<Symbol>, String] uri_parts The components of the sequence URI.
102
+ # @param [Object] value The new value for the sequence. This must be a value that is
103
+ # within the sequence definition. For example, you cannot set
104
+ # a String sequence to an Integer value.
105
+ #
106
+ # @example
107
+ # set_sequence(:factory_name, :trait_name, :sequence_name, 450)
108
+ # @example
109
+ # set_sequence([:factory_name, :trait_name, :sequence_name], 450)
110
+ # @example
111
+ # set_sequence("factory_name/trait_name/sequence_name", 450)
84
112
  delegate :factories,
85
113
  :register_strategy,
86
114
  :rewind_sequences,
115
+ :rewind_sequence,
116
+ :set_sequence,
87
117
  :strategy_by_name,
88
118
  to: Internal
89
119
  end
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factory_bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.5.1
4
+ version: 6.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Clayton
8
8
  - Joe Ferris
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2025-01-31 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: activesupport
@@ -246,13 +245,13 @@ files:
246
245
  - lib/factory_bot/syntax/methods.rb
247
246
  - lib/factory_bot/syntax_runner.rb
248
247
  - lib/factory_bot/trait.rb
248
+ - lib/factory_bot/uri_manager.rb
249
249
  - lib/factory_bot/version.rb
250
250
  homepage: https://github.com/thoughtbot/factory_bot
251
251
  licenses:
252
252
  - MIT
253
253
  metadata:
254
254
  changelog_uri: https://github.com/thoughtbot/factory_bot/blob/main/NEWS.md
255
- post_install_message:
256
255
  rdoc_options: []
257
256
  require_paths:
258
257
  - lib
@@ -267,8 +266,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
267
266
  - !ruby/object:Gem::Version
268
267
  version: '0'
269
268
  requirements: []
270
- rubygems_version: 3.5.22
271
- signing_key:
269
+ rubygems_version: 3.6.7
272
270
  specification_version: 4
273
271
  summary: factory_bot provides a framework and DSL for defining and using model instance
274
272
  factories.