factory_bot 6.3.0 → 6.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be53175a79d79c70dbaae41a86638d7013b968cecf59aaaa1cedc813ef4e4bc6
4
- data.tar.gz: 4d3312a1ec50b608daa376d41e176ee713fba29ee80c1ce0acd0a646ce4a9956
3
+ metadata.gz: 3a7ebed6c784cdfb3ea79c03d84a65a36727a1410365921f559f342810c3302d
4
+ data.tar.gz: 5b3c7a8d107633fa5025cbd3c1d5e3fceac5ba53a820a17328be22ca1aa80f8c
5
5
  SHA512:
6
- metadata.gz: 6077f43c7fc1486a2b1ac6d009f3c95e5c736afbe76c62d1818eb8ad26e77aa9f249b74dd1715b11da3bc989abee47a9a28f4da250e8fe10b036aa4121afc786
7
- data.tar.gz: c4de0a35286906b04e4d4d0e489e437135a1553241f80e5338332b90657e253f055084e5c040e4dc6097b79102a5781c5226a89d89c9108edfb97c1b616fdaa0
6
+ metadata.gz: 0d067eb0c20f31211b496b34c6470df84d31a3db63d7e6b9f7f051ed890669c8220224dfb5451d13397c0b24a395ff032cb2e1be05b15f0ef13fd034293878cd
7
+ data.tar.gz: 988911756ac353fb3db10d73280b1acdb07618166e7fdec256601dd1051c2a15200c47ecbd18490253d76abc2bf46b3652c9c7f8aee47816210e3c3ee2d93b30
data/GETTING_STARTED.md CHANGED
@@ -285,6 +285,9 @@ user = create(:user)
285
285
  # Returns a hash of attributes that can be used to build a User instance
286
286
  attrs = attributes_for(:user)
287
287
 
288
+ # Integrates with Ruby 3.0's support for pattern matching assignment
289
+ attributes_for(:user) => {email:, name:, **attrs}
290
+
288
291
  # Returns an object with all defined attributes stubbed out
289
292
  stub = build_stubbed(:user)
290
293
 
@@ -297,7 +300,7 @@ end
297
300
  ### Attribute overrides
298
301
 
299
302
  No matter which strategy is used, it's possible to override the defined
300
- attributes by passing a hash:
303
+ attributes by passing a Hash:
301
304
 
302
305
  ```ruby
303
306
  # Build a User instance and override the first_name property
@@ -306,6 +309,29 @@ user.first_name
306
309
  # => "Joe"
307
310
  ```
308
311
 
312
+ Overriding associations is also supported:
313
+
314
+ ```ruby
315
+ account = build(:account, :deluxe)
316
+ friends = build_list(:user, 2)
317
+
318
+ user = build(:user, account: account, friends: friends)
319
+ ```
320
+
321
+ Ruby 3.1's support for [omitting values][] from `Hash` literals dovetails with
322
+ attribute overrides and provides an opportunity to limit the repetition of
323
+ variable names:
324
+
325
+ ```ruby
326
+ account = build(:account, :deluxe)
327
+ friends = build_list(:user, 2)
328
+
329
+ # The keyword arguments correspond to local variable names, so omit their values
330
+ user = build(:user, account:, friends:)
331
+ ```
332
+
333
+ [omitting values]: https://docs.ruby-lang.org/en/3.1/syntax/literals_rdoc.html#label-Hash+Literals
334
+
309
335
  ### `build_stubbed` and `Marshal.dump`
310
336
 
311
337
  Note that objects created with `build_stubbed` cannot be serialized with
@@ -945,7 +971,7 @@ end
945
971
  Note that this approach works with `build`, `build_stubbed`, and `create`, but
946
972
  the associations will return `nil` when using `attributes_for`.
947
973
 
948
- Also, note that if you assign any attributes inside a custom `initialize_with`
974
+ Also, note that if you assign any attributes inside a custom `initialize_with`
949
975
  (e.g. `initialize_with { new(**attributes) }`), those attributes should not refer to `instance`,
950
976
  since it will be `nil`.
951
977
 
@@ -1008,6 +1034,17 @@ factory :user do
1008
1034
  end
1009
1035
  ```
1010
1036
 
1037
+ With Ruby 2.7's support for [numbered parameters][], inline definitions can be
1038
+ even more abbreviated:
1039
+
1040
+ ```ruby
1041
+ factory :user do
1042
+ sequence(:email) { "person#{_1}@example.com" }
1043
+ end
1044
+ ```
1045
+
1046
+ [numbered parameters]: https://ruby-doc.org/core-2.7.1/Proc.html#class-Proc-label-Numbered+parameters
1047
+
1011
1048
  ### Initial value
1012
1049
 
1013
1050
  You can override the initial value. Any value that responds to the `#next`
@@ -1222,11 +1259,11 @@ FactoryBot.define do
1222
1259
  created_at { 8.days.ago }
1223
1260
  updated_at { 4.days.ago }
1224
1261
  end
1225
-
1262
+
1226
1263
  factory :user, traits: [:timestamps] do
1227
1264
  username { "john_doe" }
1228
1265
  end
1229
-
1266
+
1230
1267
  factory :post do
1231
1268
  timestamps
1232
1269
  title { "Traits rock" }
data/NEWS.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # News
2
2
 
3
+ ## 6.4.6 (January 30, 2023)
4
+
5
+ * Fix: Bump minimum required Ruby in gemspec (Earlopain).
6
+ * Fix: Broken link in `FactoryBot.modify` docs (Matt Brictson).
7
+ * Fix: Broken link in `FactoryBot.lint` docs (Anton Dieterle).
8
+
9
+ ## 6.4.5 (December 29, 2023)
10
+
11
+ * Changed: Support Ruby 3.0+, Rails 6.1+ (Mike Burns).
12
+
13
+ ## 6.4.4 (December 27, 2023)
14
+
15
+ * Internal: Remove observer dependency (Earlopain).
16
+
17
+ ## 6.4.3 (December 26, 2023)
18
+
19
+ * Fix: Support models without ID setters in build_stubbed (Olivier Bellone).
20
+ * Fix: Explicit observer dependency (Oleg Antonyan).
21
+ * Internal: Add Rails 7.1 to CI (Olivier Bellone).
22
+ * Internal: Bump github actions/checkout to v4 (Lorenzo Zabot)
23
+ * Internal: Stop passing disable-error_highlight in CI (Mike Burns).
24
+ * Internal: Relax the exception message check (Mike Burns).
25
+
26
+ ## 6.4.2 (November 22, 2023)
27
+
28
+ * Fix: top-level traits pass their class to ActiveSupport::Notifications
29
+ (makicamel).
30
+
31
+ ## 6.4.1 (November 20, 2023)
32
+
33
+ * Fix: factories with traits pass their class to ActiveSupport::Notifications
34
+ (makicamel).
35
+
36
+ ## 6.4.0 (November 17, 2023)
37
+
38
+ * Added: if `build_stubbed` detects a UUID primary key, generate the correct
39
+ type (Peter Boling, Alexandre Ruban).
40
+ * Docs: show examples of Ruby 3 syntactic sugars (Sean Doyle).
41
+ * Internal: resolve test warning messages (Mike Burns).
42
+
43
+
3
44
  ## 6.3.0 (September 1, 2023)
4
45
 
5
46
  * Fix: link to changelog for RubyGems (Berkan Ünal).
@@ -6,24 +6,12 @@ module FactoryBot
6
6
  @component = component
7
7
  end
8
8
 
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/MissingRespondToMissing
21
- @component.send(name, *args, &block)
22
- end
9
+ def method_missing(...) # rubocop:disable Style/MethodMissingSuper
10
+ @component.send(...)
11
+ end
23
12
 
24
- def send(symbol, *args, &block)
25
- __send__(symbol, *args, &block)
26
- end
13
+ def send(...)
14
+ __send__(...)
27
15
  end
28
16
 
29
17
  def respond_to_missing?(name, include_private = false)
@@ -2,6 +2,7 @@ module FactoryBot
2
2
  # @api private
3
3
  class Definition
4
4
  attr_reader :defined_traits, :declarations, :name, :registered_enums
5
+ attr_accessor :klass
5
6
 
6
7
  def initialize(name, base_traits = [])
7
8
  @name = name
@@ -51,7 +52,9 @@ module FactoryBot
51
52
 
52
53
  declarations.attributes
53
54
 
55
+ self.klass ||= klass
54
56
  defined_traits.each do |defined_trait|
57
+ defined_trait.klass ||= klass
55
58
  base_traits.each { |bt| bt.define_trait defined_trait }
56
59
  additional_traits.each { |at| at.define_trait defined_trait }
57
60
  end
@@ -62,7 +65,7 @@ module FactoryBot
62
65
  name: name,
63
66
  attributes: declarations.attributes,
64
67
  traits: defined_traits,
65
- class: klass
68
+ class: klass || self.klass
66
69
  }
67
70
  end
68
71
  end
@@ -150,7 +153,7 @@ module FactoryBot
150
153
  end
151
154
 
152
155
  def trait_by_name(name)
153
- trait_for(name) || Internal.trait_by_name(name)
156
+ trait_for(name) || Internal.trait_by_name(name, klass)
154
157
  end
155
158
 
156
159
  def trait_for(name)
@@ -119,8 +119,8 @@ module FactoryBot
119
119
  # end
120
120
  #
121
121
  # Except that no globally available sequence will be defined.
122
- def sequence(name, *args, &block)
123
- sequence = Sequence.new(name, *args, &block)
122
+ def sequence(name, ...)
123
+ sequence = Sequence.new(name, ...)
124
124
  FactoryBot::Internal.register_inline_sequence(sequence)
125
125
  add_attribute(name) { increment_sequence(sequence) }
126
126
  end
@@ -1,13 +1,10 @@
1
- require "observer"
2
-
3
1
  module FactoryBot
4
2
  class Evaluation
5
- include Observable
6
-
7
- def initialize(evaluator, attribute_assigner, to_create)
3
+ def initialize(evaluator, attribute_assigner, to_create, observer)
8
4
  @evaluator = evaluator
9
5
  @attribute_assigner = attribute_assigner
10
6
  @to_create = to_create
7
+ @observer = observer
11
8
  end
12
9
 
13
10
  delegate :object, :hash, to: :@attribute_assigner
@@ -20,8 +17,7 @@ module FactoryBot
20
17
  end
21
18
 
22
19
  def notify(name, result_instance)
23
- changed
24
- notify_observers(name, result_instance)
20
+ @observer.update(name, result_instance)
25
21
  end
26
22
  end
27
23
  end
@@ -35,14 +35,13 @@ module FactoryBot
35
35
 
36
36
  attr_accessor :instance
37
37
 
38
- def method_missing(method_name, *args, &block)
38
+ def method_missing(method_name, ...)
39
39
  if @instance.respond_to?(method_name)
40
- @instance.send(method_name, *args, &block)
40
+ @instance.send(method_name, ...)
41
41
  else
42
- SyntaxRunner.new.send(method_name, *args, &block)
42
+ SyntaxRunner.new.send(method_name, ...)
43
43
  end
44
44
  end
45
- ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
46
45
 
47
46
  def respond_to_missing?(method_name, _include_private = false)
48
47
  @instance.respond_to?(method_name) || SyntaxRunner.new.respond_to?(method_name)
@@ -36,9 +36,9 @@ module FactoryBot
36
36
  evaluator = evaluator_class.new(strategy, overrides.symbolize_keys)
37
37
  attribute_assigner = AttributeAssigner.new(evaluator, build_class, &compiled_constructor)
38
38
 
39
+ observer = CallbacksObserver.new(callbacks, evaluator)
39
40
  evaluation =
40
- Evaluation.new(evaluator, attribute_assigner, compiled_to_create)
41
- evaluation.add_observer(CallbacksObserver.new(callbacks, evaluator))
41
+ Evaluation.new(evaluator, attribute_assigner, compiled_to_create, observer)
42
42
 
43
43
  strategy.result(evaluation).tap(&block)
44
44
  end
@@ -39,8 +39,8 @@ module FactoryBot
39
39
  trait
40
40
  end
41
41
 
42
- def trait_by_name(name)
43
- traits.find(name)
42
+ def trait_by_name(name, klass)
43
+ traits.find(name).tap { |t| t.klass = klass }
44
44
  end
45
45
 
46
46
  def register_sequence(sequence)
@@ -47,13 +47,17 @@ module FactoryBot
47
47
 
48
48
  private
49
49
 
50
- def next_id
51
- @@next_id += 1
50
+ def next_id(result_instance)
51
+ if uuid_primary_key?(result_instance)
52
+ SecureRandom.uuid
53
+ else
54
+ @@next_id += 1
55
+ end
52
56
  end
53
57
 
54
58
  def stub_database_interaction_on_result(result_instance)
55
59
  if has_settable_id?(result_instance)
56
- result_instance.id ||= next_id
60
+ result_instance.id ||= next_id(result_instance)
57
61
  end
58
62
 
59
63
  result_instance.instance_eval do
@@ -79,8 +83,16 @@ module FactoryBot
79
83
  end
80
84
 
81
85
  def has_settable_id?(result_instance)
82
- !result_instance.class.respond_to?(:primary_key) ||
83
- result_instance.class.primary_key
86
+ result_instance.respond_to?(:id=) &&
87
+ (!result_instance.class.respond_to?(:primary_key) ||
88
+ result_instance.class.primary_key)
89
+ end
90
+
91
+ def uuid_primary_key?(result_instance)
92
+ result_instance.respond_to?(:column_for_attribute) &&
93
+ (column = result_instance.column_for_attribute(result_instance.class.primary_key)) &&
94
+ column.respond_to?(:sql_type) &&
95
+ column.sql_type == "uuid"
84
96
  end
85
97
 
86
98
  def clear_changes_information(result_instance)
@@ -25,8 +25,8 @@ module FactoryBot
25
25
  end
26
26
  end
27
27
 
28
- def sequence(name, *args, &block)
29
- Internal.register_sequence(Sequence.new(name, *args, &block))
28
+ def sequence(name, ...)
29
+ Internal.register_sequence(Sequence.new(name, ...))
30
30
  end
31
31
 
32
32
  def trait(name, &block)
@@ -15,7 +15,7 @@ module FactoryBot
15
15
  end
16
16
 
17
17
  delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor,
18
- :callbacks, :attributes, to: :@definition
18
+ :callbacks, :attributes, :klass, :klass=, to: :@definition
19
19
 
20
20
  def names
21
21
  [@name]
@@ -1,3 +1,3 @@
1
1
  module FactoryBot
2
- VERSION = "6.3.0".freeze
2
+ VERSION = "6.4.6".freeze
3
3
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factory_bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.3.0
4
+ version: 6.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Clayton
8
8
  - Joe Ferris
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-09-01 00:00:00.000000000 Z
12
+ date: 2024-01-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -238,7 +238,7 @@ licenses:
238
238
  - MIT
239
239
  metadata:
240
240
  changelog_uri: https://github.com/thoughtbot/factory_bot/blob/main/NEWS.md
241
- post_install_message:
241
+ post_install_message:
242
242
  rdoc_options: []
243
243
  require_paths:
244
244
  - lib
@@ -246,15 +246,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
246
246
  requirements:
247
247
  - - ">="
248
248
  - !ruby/object:Gem::Version
249
- version: 2.5.0
249
+ version: 3.0.0
250
250
  required_rubygems_version: !ruby/object:Gem::Requirement
251
251
  requirements:
252
252
  - - ">="
253
253
  - !ruby/object:Gem::Version
254
254
  version: '0'
255
255
  requirements: []
256
- rubygems_version: 3.4.13
257
- signing_key:
256
+ rubygems_version: 3.4.10
257
+ signing_key:
258
258
  specification_version: 4
259
259
  summary: factory_bot provides a framework and DSL for defining and using model instance
260
260
  factories.