factory_bot 6.1.0 → 6.2.1

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: fe33ad3bb5d907e38ceac543f969484fb0ec67a4708a701cdfea0696d4a292c4
4
- data.tar.gz: 54cdb44f4ac7782360c8e9efd02ac46f40336d00c34a5767d5d7fc0f86f8d7a5
3
+ metadata.gz: 3bcbbd8bee01abdb25a5cfdbbbbca29396f587236f0c20f8300adbf6e32f783c
4
+ data.tar.gz: 94d8e73507ae61edba7fb3129ee74c4fe9998a8fb78614ecba9966199561c8e4
5
5
  SHA512:
6
- metadata.gz: cdc3ec9def71e797058fb13cff95b911eceb61d1488f193ef1bfb6bdf12c6c7835d1f67dc1885d5539e6da7135f04e4a417a16fbc60cbc0c4d60056a1948c89d
7
- data.tar.gz: 2f04ab1a184266a86cf8510be688b8a01b0dd570615d25e314176b4492f9635053596636aa4ec9ab8133e86e4c9f630acdb52468c01ea1bfd2fb8777fc27b2ab
6
+ metadata.gz: e97d9530810f0de00f6e0129df37db52722ee8d430f7b118ffdcebdc0eecc1e1532356b7c8e01cc85265c04f18eb174d3d5ff09fe235c5f30ceb7b5e16432508
7
+ data.tar.gz: 71b77c30b16c89588d6946505be547374321597e8e16f89673766cda94b22188dc28070a34144ae126dad93042de0173e1d92173237ae1e929a3131e85569a51
data/CONTRIBUTING.md CHANGED
@@ -51,6 +51,12 @@ Here are some ways *you* can contribute:
51
51
  asking for help. We love helping!
52
52
  * Please don't update the Gem version.
53
53
 
54
+ ## Setting up
55
+
56
+ ```sh
57
+ bundle install
58
+ ```
59
+
54
60
  ## Running the test suite
55
61
 
56
62
  The default rake task will run the full test suite and [standard]:
data/GETTING_STARTED.md CHANGED
@@ -37,12 +37,15 @@ Getting Started
37
37
  * [Associations](#associations)
38
38
  + [Implicit definition](#implicit-definition)
39
39
  + [Explicit definition](#explicit-definition)
40
+ + [Inline definition](#inline-definition)
40
41
  + [Specifying the factory](#specifying-the-factory)
41
42
  + [Overriding attributes](#overriding-attributes)
43
+ + [Association overrides](#association-overrides)
42
44
  + [Build strategies](#build-strategies-1)
43
45
  + [`has_many` associations](#has_many-associations)
44
46
  + [`has_and_belongs_to_many` associations](#has_and_belongs_to_many-associations)
45
47
  + [Polymorphic associations](#polymorphic-associations)
48
+ + [Interconnected associations](#interconnected-associations)
46
49
  * [Sequences](#sequences)
47
50
  + [Global sequences](#global-sequences)
48
51
  + [With dynamic attributes](#with-dynamic-attributes)
@@ -197,17 +200,15 @@ It is also possible to explicitly specify the class:
197
200
 
198
201
  ```ruby
199
202
  # This will use the User class (otherwise Admin would have been guessed)
200
- factory :admin, class: User
203
+ factory :admin, class: "User"
201
204
  ```
202
205
 
203
- If the constant is not available
204
- (if you are using a Rails engine that waits to load models, for example),
205
- you can also pass a symbol or string,
206
- which factory\_bot will constantize later, once you start building objects:
206
+ You can pass a constant as well, if the constant is available (note that this
207
+ can cause test performance problems in large Rails applications, since
208
+ referring to the constant will cause it to be eagerly loaded).
207
209
 
208
210
  ```ruby
209
- # It's OK if Doorkeeper::AccessToken isn't loaded yet
210
- factory :access_token, class: "Doorkeeper::AccessToken"
211
+ factory :access_token, class: User
211
212
  ```
212
213
 
213
214
  ### Hash attributes
@@ -312,17 +313,17 @@ factory :user, aliases: [:author, :commenter] do
312
313
  end
313
314
 
314
315
  factory :post do
315
- author
316
- # instead of
316
+ # The alias allows us to write author instead of
317
317
  # association :author, factory: :user
318
+ author
318
319
  title { "How to read a book effectively" }
319
320
  body { "There are five steps involved." }
320
321
  end
321
322
 
322
323
  factory :comment do
323
- commenter
324
- # instead of
324
+ # The alias allows us to write commenter instead of
325
325
  # association :commenter, factory: :user
326
+ commenter
326
327
  body { "Great article!" }
327
328
  end
328
329
  ```
@@ -346,6 +347,7 @@ create(:user, last_name: "Doe").email
346
347
 
347
348
  Transient Attributes
348
349
  --------------------
350
+ Transient attributes are attributes only available within the factory definition, and not set on the object being built. This allows for more complex logic inside factories.
349
351
 
350
352
  ### With other attributes
351
353
 
@@ -505,6 +507,19 @@ factory :post do
505
507
  end
506
508
  ```
507
509
 
510
+ ### Inline definition
511
+
512
+ You can also define associations inline within regular attributes,
513
+ but note that the value will be `nil`
514
+ when using the `attributes_for` strategy.
515
+
516
+ ```ruby
517
+ factory :post do
518
+ # ...
519
+ author { association :author }
520
+ end
521
+ ```
522
+
508
523
  ### Specifying the factory
509
524
 
510
525
  You can specify a different factory (although [Aliases](#aliases) might also
@@ -528,6 +543,15 @@ factory :post do
528
543
  end
529
544
  ```
530
545
 
546
+ Inline:
547
+
548
+ ```ruby
549
+ factory :post do
550
+ # ...
551
+ author { association :user }
552
+ end
553
+ ```
554
+
531
555
  ### Overriding attributes
532
556
 
533
557
  You can also override attributes.
@@ -551,6 +575,35 @@ factory :post do
551
575
  end
552
576
  ```
553
577
 
578
+ Or inline using attributes from the factory:
579
+
580
+ ```rb
581
+ factory :post do
582
+ # ...
583
+ author_last_name { "Writely" }
584
+ author { association :author, last_name: author_last_name }
585
+ end
586
+ ```
587
+
588
+ ### Association overrides
589
+
590
+ Attribute overrides can be used to link associated objects:
591
+
592
+ ```ruby
593
+ FactoryBot.define do
594
+ factory :author do
595
+ name { 'Taylor' }
596
+ end
597
+
598
+ factory :post do
599
+ author
600
+ end
601
+ end
602
+
603
+ eunji = build(:author, name: 'Eunji')
604
+ post = build(:post, author: eunji)
605
+ ```
606
+
554
607
  ### Build strategies
555
608
 
556
609
  In factory\_bot 5, associations default to using the same build strategy as
@@ -620,27 +673,51 @@ factory :post do
620
673
 
621
674
  ### `has_many` associations
622
675
 
623
- Generating data for a `has_many` relationship is a bit more involved,
624
- depending on the amount of flexibility desired, but here's a surefire example
625
- of generating associated data.
676
+ There are a few ways to generate data for a `has_many` relationship. The
677
+ simplest approach is to write a helper method in plain Ruby to tie together the
678
+ different records:
626
679
 
627
680
  ```ruby
628
681
  FactoryBot.define do
682
+ factory :post do
683
+ title { "Through the Looking Glass" }
684
+ user
685
+ end
686
+
687
+ factory :user do
688
+ name { "Rachel Sanchez" }
689
+ end
690
+ end
691
+
692
+ def user_with_posts(posts_count: 5)
693
+ FactoryBot.create(:user) do |user|
694
+ FactoryBot.create_list(:post, posts_count, user: user)
695
+ end
696
+ end
697
+
698
+ create(:user).posts.length # 0
699
+ user_with_posts.posts.length # 5
700
+ user_with_posts(posts_count: 15).posts.length # 15
701
+ ```
629
702
 
630
- # post factory with a `belongs_to` association for the user
703
+ If you prefer to keep the object creation fully within factory\_bot, you can
704
+ build the posts in an `after(:create)` callback.
705
+
706
+
707
+ ```ruby
708
+ FactoryBot.define do
631
709
  factory :post do
632
710
  title { "Through the Looking Glass" }
633
711
  user
634
712
  end
635
713
 
636
- # user factory without associated posts
637
714
  factory :user do
638
715
  name { "John Doe" }
639
716
 
640
717
  # user_with_posts will create post data after the user has been created
641
718
  factory :user_with_posts do
642
- # posts_count is declared as a transient attribute and available in
643
- # attributes on the factory, as well as the callback via the evaluator
719
+ # posts_count is declared as a transient attribute available in the
720
+ # callback via the evaluator
644
721
  transient do
645
722
  posts_count { 5 }
646
723
  end
@@ -651,71 +728,122 @@ FactoryBot.define do
651
728
  # to create and we make sure the user is associated properly to the post
652
729
  after(:create) do |user, evaluator|
653
730
  create_list(:post, evaluator.posts_count, user: user)
731
+
732
+ # You may need to reload the record here, depending on your application
733
+ user.reload
654
734
  end
655
735
  end
656
736
  end
657
737
  end
738
+
739
+ create(:user).posts.length # 0
740
+ create(:user_with_posts).posts.length # 5
741
+ create(:user_with_posts, posts_count: 15).posts.length # 15
658
742
  ```
659
743
 
660
- This allows us to do:
744
+ Or, for a solution that works with `build`, `build_stubbed`, and `create`
745
+ (although it doesn't work well with `attributes_for`), you can use inline
746
+ associations:
661
747
 
662
748
  ```ruby
749
+ FactoryBot.define do
750
+ factory :post do
751
+ title { "Through the Looking Glass" }
752
+ user
753
+ end
754
+
755
+ factory :user do
756
+ name { "Taylor Kim" }
757
+
758
+ factory :user_with_posts do
759
+ posts { [association(:post)] }
760
+ end
761
+ end
762
+ end
763
+
663
764
  create(:user).posts.length # 0
765
+ create(:user_with_posts).posts.length # 1
766
+ build(:user_with_posts).posts.length # 1
767
+ build_stubbed(:user_with_posts).posts.length # 1
768
+ ```
769
+
770
+ For more flexibility you can combine this with the `posts_count` transient
771
+ attribute from the callback example:
772
+
773
+ ```ruby
774
+ FactoryBot.define do
775
+ factory :post do
776
+ title { "Through the Looking Glass" }
777
+ user
778
+ end
779
+
780
+ factory :user do
781
+ name { "Adiza Kumato" }
782
+
783
+ factory :user_with_posts do
784
+ transient do
785
+ posts_count { 5 }
786
+ end
787
+
788
+ posts do
789
+ Array.new(posts_count) { association(:post) }
790
+ end
791
+ end
792
+ end
793
+ end
794
+
664
795
  create(:user_with_posts).posts.length # 5
665
796
  create(:user_with_posts, posts_count: 15).posts.length # 15
797
+ build(:user_with_posts, posts_count: 15).posts.length # 15
798
+ build_stubbed(:user_with_posts, posts_count: 15).posts.length # 15
666
799
  ```
667
800
 
668
801
  ### `has_and_belongs_to_many` associations
669
802
 
670
803
  Generating data for a `has_and_belongs_to_many` relationship is very similar
671
- to the above `has_many` relationship, with a small change, you need to pass an
804
+ to the above `has_many` relationship, with a small change: you need to pass an
672
805
  array of objects to the model's pluralized attribute name rather than a single
673
806
  object to the singular version of the attribute name.
674
807
 
675
- Here's an example with two models that are related via
676
- `has_and_belongs_to_many`:
677
808
 
678
809
  ```ruby
679
- FactoryBot.define do
680
-
681
- # language factory with a `belongs_to` association for the profile
682
- factory :language do
683
- title { "Through the Looking Glass" }
684
- profile
810
+ def profile_with_languages(languages_count: 2)
811
+ FactoryBot.create(:profile) do |profile|
812
+ FactoryBot.create_list(:language, languages_count, profiles: [profile])
685
813
  end
814
+ end
815
+ ```
686
816
 
687
- # profile factory without associated languages
688
- factory :profile do
689
- name { "John Doe" }
817
+ Or with the callback approach:
690
818
 
691
- # profile_with_languages will create language data after the profile has
692
- # been created
693
- factory :profile_with_languages do
694
- # languages_count is declared as an ignored attribute and available in
695
- # attributes on the factory, as well as the callback via the evaluator
696
- transient do
697
- languages_count { 5 }
698
- end
819
+ ```ruby
820
+ factory :profile_with_languages do
821
+ transient do
822
+ languages_count { 2 }
823
+ end
699
824
 
700
- # the after(:create) yields two values; the profile instance itself and
701
- # the evaluator, which stores all values from the factory, including
702
- # ignored attributes; `create_list`'s second argument is the number of
703
- # records to create and we make sure the profile is associated properly
704
- # to the language
705
- after(:create) do |profile, evaluator|
706
- create_list(:language, evaluator.languages_count, profiles: [profile])
707
- end
708
- end
825
+ after(:create) do |profile, evaluator|
826
+ create_list(:language, evaluator.languages_count, profiles: [profile])
827
+ profile.reload
709
828
  end
710
829
  end
711
830
  ```
712
831
 
713
- This allows us to do:
832
+ Or the inline association approach (note the use of the `instance` method here
833
+ to refer to the profile being built):
714
834
 
715
835
  ```ruby
716
- create(:profile).languages.length # 0
717
- create(:profile_with_languages).languages.length # 5
718
- create(:profile_with_languages, languages_count: 15).languages.length # 15
836
+ factory :profile_with_languages do
837
+ transient do
838
+ languages_count { 2 }
839
+ end
840
+
841
+ languages do
842
+ Array.new(languages_count) do
843
+ association(:language, profiles: [instance])
844
+ end
845
+ end
846
+ end
719
847
  ```
720
848
 
721
849
  ### Polymorphic associations
@@ -749,6 +877,61 @@ create(:comment, :for_video)
749
877
  create(:comment, :for_photo)
750
878
  ```
751
879
 
880
+ ### Interconnected associations
881
+
882
+ There are limitless ways objects might be interconnected, and
883
+ factory\_bot may not always be suited to handle those relationships. In some
884
+ cases it makes sense to use factory\_bot to build each individual object, and
885
+ then to write helper methods in plain Ruby to tie those objects together.
886
+
887
+ That said, some more complex, interconnected relationships can be built in factory\_bot
888
+ using inline associations with reference to the `instance` being built.
889
+
890
+ Let's say your models look like this, where an associated `Student` and
891
+ `Profile` should both belong to the same `School`:
892
+
893
+ ```ruby
894
+ class Student < ApplicationRecord
895
+ belongs_to :school
896
+ has_one :profile
897
+ end
898
+
899
+ class Profile < ApplicationRecord
900
+ belongs_to :school
901
+ belongs_to :student
902
+ end
903
+
904
+ class School < ApplicationRecord
905
+ has_many :students
906
+ has_many :profiles
907
+ end
908
+ ```
909
+
910
+ We can ensure the student and profile are connected to each other and to the
911
+ same school with a factory like this:
912
+
913
+ ```ruby
914
+ FactoryBot.define do
915
+ factory :student do
916
+ school
917
+ profile { association :profile, student: instance, school: school }
918
+ end
919
+
920
+ factory :profile do
921
+ school
922
+ student { association :student, profile: instance, school: school }
923
+ end
924
+
925
+ factory :school
926
+ end
927
+ ```
928
+
929
+ Note that this approach works with `build`, `build_stubbed`, and `create`, but
930
+ the associations will return `nil` when using `attributes_for`.
931
+
932
+ Also, note that if you assign any attributes inside a custom `initialize_with`
933
+ (e.g. `initialize_with { new(**attributes) }`), those attributes should not refer to `instance`,
934
+ since it will be `nil`.
752
935
 
753
936
  Sequences
754
937
  ---------
@@ -811,7 +994,7 @@ end
811
994
 
812
995
  ### Initial value
813
996
 
814
- You can override the initial value. Any value that response to the `#next`
997
+ You can override the initial value. Any value that responds to the `#next`
815
998
  method will work (e.g. 1, 2, 3, 'a', 'b', 'c')
816
999
 
817
1000
  ```ruby
@@ -830,6 +1013,15 @@ factory :post do
830
1013
  end
831
1014
  ```
832
1015
 
1016
+ Please note, that the value for the sequence could be any Enumerable instance,
1017
+ as long as it responds to `#next`:
1018
+
1019
+ ```ruby
1020
+ factory :task do
1021
+ sequence :priority, %i[low medium high urgent].cycle
1022
+ end
1023
+ ```
1024
+
833
1025
  ### Aliases
834
1026
 
835
1027
  Sequences can also have aliases. The sequence aliases share the same counter:
@@ -960,16 +1152,16 @@ factory :user do
960
1152
  name { "Friendly User" }
961
1153
  login { name }
962
1154
 
963
- trait :male do
1155
+ trait :active do
964
1156
  name { "John Doe" }
965
- gender { "Male" }
966
- login { "#{name} (M)" }
1157
+ status { :active }
1158
+ login { "#{name} (active)" }
967
1159
  end
968
1160
 
969
- trait :female do
1161
+ trait :inactive do
970
1162
  name { "Jane Doe" }
971
- gender { "Female" }
972
- login { "#{name} (F)" }
1163
+ status { :inactive }
1164
+ login { "#{name} (inactive)" }
973
1165
  end
974
1166
 
975
1167
  trait :admin do
@@ -977,8 +1169,8 @@ factory :user do
977
1169
  login { "admin-#{name}" }
978
1170
  end
979
1171
 
980
- factory :male_admin, traits: [:male, :admin] # login will be "admin-John Doe"
981
- factory :female_admin, traits: [:admin, :female] # login will be "Jane Doe (F)"
1172
+ factory :active_admin, traits: [:active, :admin] # login will be "admin-John Doe"
1173
+ factory :inactive_admin, traits: [:admin, :inactive] # login will be "Jane Doe (inactive)"
982
1174
  end
983
1175
  ```
984
1176
 
@@ -991,19 +1183,41 @@ factory :user do
991
1183
  name { "Friendly User" }
992
1184
  login { name }
993
1185
 
994
- trait :male do
1186
+ trait :active do
995
1187
  name { "John Doe" }
996
- gender { "Male" }
1188
+ status { :active }
997
1189
  login { "#{name} (M)" }
998
1190
  end
999
1191
 
1000
1192
  factory :brandon do
1001
- male
1193
+ active
1002
1194
  name { "Brandon" }
1003
1195
  end
1004
1196
  end
1005
1197
  ```
1006
1198
 
1199
+ ### As mixins
1200
+
1201
+ Traits can be defined outside of factories and used as mixins to compose shared attributes
1202
+
1203
+ ```ruby
1204
+ FactoryBot.define do
1205
+ trait :timestamps do
1206
+ created_at { 8.days.ago }
1207
+ updated_at { 4.days.ago }
1208
+ end
1209
+
1210
+ factory :user, traits: [:timestamps] do
1211
+ username { "john_doe" }
1212
+ end
1213
+
1214
+ factory :post do
1215
+ timestamps
1216
+ title { "Traits rock" }
1217
+ end
1218
+ end
1219
+ ```
1220
+
1007
1221
  ### Using traits
1008
1222
 
1009
1223
  Traits can also be passed in as a list of symbols when you construct an instance
@@ -1013,9 +1227,9 @@ from factory\_bot.
1013
1227
  factory :user do
1014
1228
  name { "Friendly User" }
1015
1229
 
1016
- trait :male do
1230
+ trait :active do
1017
1231
  name { "John Doe" }
1018
- gender { "Male" }
1232
+ status { :active }
1019
1233
  end
1020
1234
 
1021
1235
  trait :admin do
@@ -1023,8 +1237,8 @@ factory :user do
1023
1237
  end
1024
1238
  end
1025
1239
 
1026
- # creates an admin user with gender "Male" and name "Jon Snow"
1027
- create(:user, :admin, :male, name: "Jon Snow")
1240
+ # creates an admin user with :active status and name "Jon Snow"
1241
+ create(:user, :admin, :active, name: "Jon Snow")
1028
1242
  ```
1029
1243
 
1030
1244
  This ability works with `build`, `build_stubbed`, `attributes_for`, and `create`.
@@ -1042,8 +1256,8 @@ factory :user do
1042
1256
  end
1043
1257
  end
1044
1258
 
1045
- # creates 3 admin users with gender "Male" and name "Jon Snow"
1046
- create_list(:user, 3, :admin, :male, name: "Jon Snow")
1259
+ # creates 3 admin users with :active status and name "Jon Snow"
1260
+ create_list(:user, 3, :admin, :active, name: "Jon Snow")
1047
1261
  ```
1048
1262
 
1049
1263
  ### With associations
@@ -1342,7 +1556,6 @@ FactoryBot.define do
1342
1556
  factory :application_user, parent: :user do
1343
1557
  full_name { "Jane Doe" }
1344
1558
  date_of_birth { 21.years.ago }
1345
- gender { "Female" }
1346
1559
  health { 90 }
1347
1560
  end
1348
1561
  end
@@ -1355,7 +1568,6 @@ FactoryBot.modify do
1355
1568
  factory :user do
1356
1569
  full_name { "Jane Doe" }
1357
1570
  date_of_birth { 21.years.ago }
1358
- gender { "Female" }
1359
1571
  health { 90 }
1360
1572
  end
1361
1573
  end
@@ -1393,6 +1605,15 @@ twenty_somethings = build_list(:user, 10) do |user, i|
1393
1605
  end
1394
1606
  ```
1395
1607
 
1608
+ `create_list` passes saved instances into the block. If you modify the instance, you must save it again:
1609
+
1610
+ ```ruby
1611
+ twenty_somethings = create_list(:user, 10) do |user, i|
1612
+ user.date_of_birth = (20 + i).years.ago
1613
+ user.save!
1614
+ end
1615
+ ```
1616
+
1396
1617
  `build_stubbed_list` will give you fully stubbed out instances:
1397
1618
 
1398
1619
  ```ruby
@@ -1567,7 +1788,7 @@ factory :user do
1567
1788
 
1568
1789
  name "John Doe"
1569
1790
 
1570
- initialize_with { new(attributes) }
1791
+ initialize_with { new(**attributes) }
1571
1792
  end
1572
1793
  ```
1573
1794
 
data/NEWS.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # News
2
2
 
3
+ ## 6.2.1 (March 8, 2022)
4
+ * Added: CI testing against truffleruby
5
+ * Changed: Documentation improvements for sequences and traits
6
+ * Fixed: ActiveSupport::Notifications reporting strategy through associations now report as symbols
7
+ * Fixed: `add_attribute` with reserved keywords assigns values correctly
8
+
9
+ ## 6.2.0 (May 7, 2021)
10
+ * Added: support for Ruby 3.0
11
+ * Changed: Include factory or trait name in error messages for missing traits. d05a9a3c
12
+ * Changed: Switched from Travis CI to GitHub Actions
13
+ * Fixed: More Ruby 2.7 kwarg deprecation warnings
14
+
3
15
  ## 6.1.0 (July 8, 2020)
4
16
  * Added: public reader for the evaluation instance, helpful for building interrelated associations
5
17
  * Changed: raise a more helpful error when passing an invalid argument to an association
@@ -20,6 +32,7 @@
20
32
  * Added: `build_stubbed_starting_id=` option to define the starting id for `build_stubbed`
21
33
  * Removed: deprecated methods on the top-level `FactoryBot` module meant only for internal use
22
34
  * Removed: support for EOL versions of Ruby (2.3, 2.4) and Rails (4.2)
35
+ * Removed: support for "abstract" factories with no associated class; use traits instead.
23
36
 
24
37
  ## 5.2.0 (April 24, 2020)
25
38
  * Added: Pass index to block for `*_list` methods
data/README.md CHANGED
@@ -43,7 +43,7 @@ gem install factory_bot
43
43
  Supported Ruby versions
44
44
  -----------------------
45
45
 
46
- Supported Ruby versions are listed in [`.travis.yml`](https://github.com/thoughtbot/factory_bot/blob/master/.travis.yml)
46
+ Supported Ruby versions are listed in [`.github/workflows/build.yml`](https://github.com/thoughtbot/factory_bot/blob/master/.github/workflows/build.yml)
47
47
 
48
48
  More Information
49
49
  ----------------
@@ -94,8 +94,8 @@ See [our other projects][community] or
94
94
 
95
95
  [community]: https://thoughtbot.com/community?utm_source=github
96
96
  [hire]: https://thoughtbot.com/hire-us?utm_source=github
97
- [ci-image]: https://travis-ci.org/thoughtbot/factory_bot.svg
98
- [ci]: https://travis-ci.org/thoughtbot/factory_bot?branch=master
97
+ [ci-image]: https://github.com/thoughtbot/factory_bot/actions/workflows/build.yml/badge.svg
98
+ [ci]: https://github.com/thoughtbot/factory_bot/actions?query=workflow%3A.github%2Fworkflows%2Fbuild.yml+branch%3Amaster++
99
99
  [grade-image]: https://codeclimate.com/github/thoughtbot/factory_bot/badges/gpa.svg
100
100
  [grade]: https://codeclimate.com/github/thoughtbot/factory_bot
101
101
  [version-image]: https://badge.fury.io/rb/factory_bot.svg
@@ -10,7 +10,7 @@ module FactoryBot
10
10
 
11
11
  def self.aliases_for(attribute)
12
12
  aliases.map { |(pattern, replace)|
13
- if pattern.match(attribute.to_s)
13
+ if pattern.match?(attribute)
14
14
  attribute.to_s.sub(pattern, replace).to_sym
15
15
  end
16
16
  }.compact << attribute
@@ -12,7 +12,7 @@ module FactoryBot
12
12
 
13
13
  -> {
14
14
  value = case block.arity
15
- when 1, -1 then instance_exec(self, &block)
15
+ when 1, -1, -2 then instance_exec(self, &block)
16
16
  else instance_exec(&block)
17
17
  end
18
18
  raise SequenceAbuseError if FactoryBot::Sequence === value
@@ -37,8 +37,9 @@ module FactoryBot
37
37
  end
38
38
 
39
39
  def decorated_evaluator
40
- Decorator::InvocationTracker.new(
41
- Decorator::NewConstructor.new(@evaluator, @build_class)
40
+ Decorator::NewConstructor.new(
41
+ Decorator::InvocationTracker.new(@evaluator),
42
+ @build_class
42
43
  )
43
44
  end
44
45
 
@@ -9,7 +9,7 @@ module FactoryBot
9
9
 
10
10
  def run(instance, evaluator)
11
11
  case block.arity
12
- when 1, -1 then syntax_runner.instance_exec(instance, &block)
12
+ when 1, -1, -2 then syntax_runner.instance_exec(instance, &block)
13
13
  when 2 then syntax_runner.instance_exec(instance, evaluator, &block)
14
14
  else syntax_runner.instance_exec(&block)
15
15
  end
@@ -6,17 +6,11 @@ module FactoryBot
6
6
  @invoked_methods = []
7
7
  end
8
8
 
9
- if ::Gem::Version.new(::RUBY_VERSION) >= ::Gem::Version.new("2.7")
10
- def method_missing(name, *args, **kwargs, &block) # rubocop:disable Style/MissingRespondToMissing
11
- @invoked_methods << name
12
- super
13
- end
14
- else
15
- def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
16
- @invoked_methods << name
17
- super
18
- end
9
+ def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
10
+ @invoked_methods << name
11
+ super
19
12
  end
13
+ ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
20
14
 
21
15
  def __invoked_methods__
22
16
  @invoked_methods.uniq
@@ -17,7 +17,7 @@ module FactoryBot
17
17
  end
18
18
  RUBY
19
19
  else
20
- def method_missing(name, *args, &block) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
20
+ def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
21
21
  @component.send(name, *args, &block)
22
22
  end
23
23
 
@@ -30,7 +30,7 @@ module FactoryBot
30
30
  end
31
31
 
32
32
  def to_create(&block)
33
- if block_given?
33
+ if block
34
34
  @to_create = block
35
35
  else
36
36
  aggregate_from_traits_and_self(:to_create) { @to_create }.last
@@ -111,6 +111,20 @@ module FactoryBot
111
111
 
112
112
  def base_traits
113
113
  @base_traits.map { |name| trait_by_name(name) }
114
+ rescue KeyError => error
115
+ raise error_with_definition_name(error)
116
+ end
117
+
118
+ def error_with_definition_name(error)
119
+ message = error.message
120
+ message.insert(
121
+ message.index("\nDid you mean?") || message.length,
122
+ " referenced within \"#{name}\" definition"
123
+ )
124
+
125
+ error.class.new(message).tap do |new_error|
126
+ new_error.set_backtrace(error.backtrace)
127
+ end
114
128
  end
115
129
 
116
130
  def additional_traits
@@ -88,7 +88,7 @@ module FactoryBot
88
88
  # end
89
89
  #
90
90
  # are equivalent.
91
- def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing, Style/MethodMissingSuper
91
+ def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
92
92
  association_options = args.first
93
93
 
94
94
  if association_options.nil?
@@ -24,7 +24,7 @@ module FactoryBot
24
24
  def association(factory_name, *traits_and_overrides)
25
25
  overrides = traits_and_overrides.extract_options!
26
26
  strategy_override = overrides.fetch(:strategy) {
27
- FactoryBot.use_parent_strategy ? @build_strategy.class : :create
27
+ FactoryBot.use_parent_strategy ? @build_strategy.to_sym : :create
28
28
  }
29
29
 
30
30
  traits_and_overrides += [overrides.except(:strategy)]
@@ -35,23 +35,14 @@ module FactoryBot
35
35
 
36
36
  attr_accessor :instance
37
37
 
38
- if ::Gem::Version.new(::RUBY_VERSION) >= ::Gem::Version.new("2.7")
39
- def method_missing(method_name, *args, **kwargs, &block) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
40
- if @instance.respond_to?(method_name)
41
- @instance.send(method_name, *args, **kwargs, &block)
42
- else
43
- SyntaxRunner.new.send(method_name, *args, **kwargs, &block)
44
- end
45
- end
46
- else
47
- def method_missing(method_name, *args, &block) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
48
- if @instance.respond_to?(method_name)
49
- @instance.send(method_name, *args, &block)
50
- else
51
- SyntaxRunner.new.send(method_name, *args, &block)
52
- end
38
+ def method_missing(method_name, *args, &block)
39
+ if @instance.respond_to?(method_name)
40
+ @instance.send(method_name, *args, &block)
41
+ else
42
+ SyntaxRunner.new.send(method_name, *args, &block)
53
43
  end
54
44
  end
45
+ ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
55
46
 
56
47
  def respond_to_missing?(method_name, _include_private = false)
57
48
  @instance.respond_to?(method_name) || SyntaxRunner.new.respond_to?(method_name)
@@ -25,7 +25,7 @@ module FactoryBot
25
25
  raise key_error_with_custom_message(e)
26
26
  end
27
27
 
28
- alias [] find
28
+ alias_method :[], :find
29
29
 
30
30
  def register(name, item)
31
31
  @items[name] = item
@@ -8,6 +8,10 @@ module FactoryBot
8
8
  def result(evaluation)
9
9
  evaluation.hash
10
10
  end
11
+
12
+ def to_sym
13
+ :attributes_for
14
+ end
11
15
  end
12
16
  end
13
17
  end
@@ -10,6 +10,10 @@ module FactoryBot
10
10
  evaluation.notify(:after_build, instance)
11
11
  end
12
12
  end
13
+
14
+ def to_sym
15
+ :build
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -13,6 +13,10 @@ module FactoryBot
13
13
  evaluation.notify(:after_create, instance)
14
14
  end
15
15
  end
16
+
17
+ def to_sym
18
+ :create
19
+ end
16
20
  end
17
21
  end
18
22
  end
@@ -6,6 +6,10 @@ module FactoryBot
6
6
 
7
7
  def result(evaluation)
8
8
  end
9
+
10
+ def to_sym
11
+ :null
12
+ end
9
13
  end
10
14
  end
11
15
  end
@@ -41,6 +41,10 @@ module FactoryBot
41
41
  end
42
42
  end
43
43
 
44
+ def to_sym
45
+ :stub
46
+ end
47
+
44
48
  private
45
49
 
46
50
  def next_id
@@ -15,7 +15,7 @@ module FactoryBot
15
15
  def factory(name, options = {}, &block)
16
16
  factory = Factory.new(name, options)
17
17
  proxy = FactoryBot::DefinitionProxy.new(factory.definition)
18
- proxy.instance_eval(&block) if block_given?
18
+ proxy.instance_eval(&block) if block
19
19
 
20
20
  Internal.register_factory(factory)
21
21
 
@@ -9,7 +9,7 @@ module FactoryBot
9
9
  @definition = Definition.new(@name)
10
10
  proxy = FactoryBot::DefinitionProxy.new(@definition)
11
11
 
12
- if block_given?
12
+ if block
13
13
  proxy.instance_eval(&@block)
14
14
  end
15
15
  end
@@ -1,3 +1,3 @@
1
1
  module FactoryBot
2
- VERSION = "6.1.0".freeze
2
+ VERSION = "6.2.1".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.1.0
4
+ version: 6.2.1
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: 2020-07-08 00:00:00.000000000 Z
12
+ date: 2022-03-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -237,7 +237,7 @@ homepage: https://github.com/thoughtbot/factory_bot
237
237
  licenses:
238
238
  - MIT
239
239
  metadata: {}
240
- post_install_message:
240
+ post_install_message:
241
241
  rdoc_options: []
242
242
  require_paths:
243
243
  - lib
@@ -252,8 +252,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
252
252
  - !ruby/object:Gem::Version
253
253
  version: '0'
254
254
  requirements: []
255
- rubygems_version: 3.1.2
256
- signing_key:
255
+ rubygems_version: 3.1.6
256
+ signing_key:
257
257
  specification_version: 4
258
258
  summary: factory_bot provides a framework and DSL for defining and using model instance
259
259
  factories.