factory_bot 6.3.0 → 6.4.6

Sign up to get free protection for your applications and to get access to all the features.
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.