sorbet-rails 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sorbet-rails/active_record_rbi_formatter.rb +295 -0
  3. data/lib/sorbet-rails/config.rb +0 -1
  4. data/lib/sorbet-rails/custom_types/boolean_string.rb +10 -0
  5. data/lib/sorbet-rails/custom_types/integer_string.rb +10 -0
  6. data/lib/sorbet-rails/dependent_gem_rbis/activerecord.rbi +11 -0
  7. data/lib/sorbet-rails/deprecation.rb +5 -0
  8. data/lib/sorbet-rails/model_plugins/active_record_assoc.rb +27 -6
  9. data/lib/sorbet-rails/model_plugins/active_record_attribute.rb +20 -8
  10. data/lib/sorbet-rails/model_plugins/base.rb +9 -0
  11. data/lib/sorbet-rails/model_plugins/enumerable_collections.rb +0 -50
  12. data/lib/sorbet-rails/model_plugins/plugins.rb +0 -3
  13. data/lib/sorbet-rails/model_rbi_formatter.rb +2 -2
  14. data/lib/sorbet-rails/model_utils.rb +15 -6
  15. data/lib/sorbet-rails/rails_mixins/custom_params_methods.rb +11 -0
  16. data/lib/sorbet-rails/tasks/rails_rbi.rake +20 -4
  17. data/sorbet-rails.gemspec +2 -2
  18. data/spec/active_record_rbi_formatter_spec.rb +24 -0
  19. data/spec/generators/rails-template.rb +88 -1
  20. data/spec/generators/sorbet_test_cases.rb +146 -42
  21. data/spec/model_rbi_formatter_spec.rb +1 -1
  22. data/spec/rails_helper.rb +14 -1
  23. data/spec/rake_rails_rbi_active_record_spec.rb +21 -0
  24. data/spec/rake_rails_rbi_models_spec.rb +7 -0
  25. data/spec/sorbet_spec.rb +12 -1
  26. data/spec/support/v5.0/Gemfile.lock +8 -8
  27. data/spec/support/v5.0/app/models/headmaster.rb +8 -0
  28. data/spec/support/v5.0/app/models/school.rb +2 -0
  29. data/spec/support/v5.0/app/models/spell.rb +5 -0
  30. data/spec/support/v5.0/app/models/spell_book.rb +3 -0
  31. data/spec/support/v5.0/app/models/subject.rb +5 -0
  32. data/spec/support/v5.0/app/models/wizard.rb +6 -1
  33. data/spec/support/v5.0/db/migrate/20190620000010_add_subject.rb +8 -0
  34. data/spec/support/v5.0/db/migrate/20190620000011_add_subjects_wizards.rb +8 -0
  35. data/spec/support/v5.0/db/migrate/20190620000012_add_spell.rb +8 -0
  36. data/spec/support/v5.0/db/migrate/20190620000013_add_spells_spell_books.rb +8 -0
  37. data/spec/support/v5.0/db/migrate/20190620000014_create_headmasters.rb +9 -0
  38. data/spec/support/v5.0/db/schema.rb +28 -1
  39. data/spec/support/v5.0/lib/mythical_rbi_plugin.rb +1 -1
  40. data/spec/support/v5.0/sorbet_test_cases.rb +146 -42
  41. data/spec/support/v5.1/Gemfile.lock +8 -8
  42. data/spec/support/v5.1/app/models/headmaster.rb +8 -0
  43. data/spec/support/v5.1/app/models/school.rb +2 -0
  44. data/spec/support/v5.1/app/models/spell.rb +5 -0
  45. data/spec/support/v5.1/app/models/spell_book.rb +3 -0
  46. data/spec/support/v5.1/app/models/subject.rb +5 -0
  47. data/spec/support/v5.1/app/models/wizard.rb +6 -1
  48. data/spec/support/v5.1/db/migrate/20190620000010_add_subject.rb +8 -0
  49. data/spec/support/v5.1/db/migrate/20190620000011_add_subjects_wizards.rb +8 -0
  50. data/spec/support/v5.1/db/migrate/20190620000012_add_spell.rb +8 -0
  51. data/spec/support/v5.1/db/migrate/20190620000013_add_spells_spell_books.rb +8 -0
  52. data/spec/support/v5.1/db/migrate/20190620000014_create_headmasters.rb +9 -0
  53. data/spec/support/v5.1/db/schema.rb +28 -1
  54. data/spec/support/v5.1/lib/mythical_rbi_plugin.rb +1 -1
  55. data/spec/support/v5.1/sorbet_test_cases.rb +146 -42
  56. data/spec/support/v5.2/Gemfile +1 -1
  57. data/spec/support/v5.2/Gemfile.lock +9 -9
  58. data/spec/support/v5.2/app/models/headmaster.rb +8 -0
  59. data/spec/support/v5.2/app/models/school.rb +2 -0
  60. data/spec/support/v5.2/app/models/spell.rb +5 -0
  61. data/spec/support/v5.2/app/models/spell_book.rb +3 -0
  62. data/spec/support/v5.2/app/models/subject.rb +5 -0
  63. data/spec/support/v5.2/app/models/wizard.rb +5 -0
  64. data/spec/support/v5.2/config/puma.rb +3 -0
  65. data/spec/support/v5.2/db/migrate/20190620000010_add_subject.rb +8 -0
  66. data/spec/support/v5.2/db/migrate/20190620000011_add_subjects_wizards.rb +8 -0
  67. data/spec/support/v5.2/db/migrate/20190620000012_add_spell.rb +8 -0
  68. data/spec/support/v5.2/db/migrate/20190620000013_add_spells_spell_books.rb +8 -0
  69. data/spec/support/v5.2/db/migrate/20190620000014_create_headmasters.rb +9 -0
  70. data/spec/support/v5.2/db/schema.rb +28 -1
  71. data/spec/support/v5.2/lib/mythical_rbi_plugin.rb +1 -1
  72. data/spec/support/v5.2/sorbet_test_cases.rb +146 -42
  73. data/spec/support/v6.0/Gemfile.lock +8 -8
  74. data/spec/support/v6.0/app/models/headmaster.rb +8 -0
  75. data/spec/support/v6.0/app/models/school.rb +2 -0
  76. data/spec/support/v6.0/app/models/spell.rb +5 -0
  77. data/spec/support/v6.0/app/models/spell_book.rb +3 -0
  78. data/spec/support/v6.0/app/models/subject.rb +5 -0
  79. data/spec/support/v6.0/app/models/wizard.rb +6 -1
  80. data/spec/support/v6.0/db/migrate/20190620000010_add_subject.rb +8 -0
  81. data/spec/support/v6.0/db/migrate/20190620000011_add_subjects_wizards.rb +8 -0
  82. data/spec/support/v6.0/db/migrate/20190620000012_add_spell.rb +8 -0
  83. data/spec/support/v6.0/db/migrate/20190620000013_add_spells_spell_books.rb +8 -0
  84. data/spec/support/v6.0/db/migrate/20190620000014_create_headmasters.rb +9 -0
  85. data/spec/support/v6.0/db/schema.rb +28 -1
  86. data/spec/support/v6.0/lib/mythical_rbi_plugin.rb +1 -1
  87. data/spec/support/v6.0/sorbet_test_cases.rb +146 -42
  88. data/spec/test_data/v5.0/expected_active_record_base.rbi +113 -0
  89. data/spec/test_data/v5.0/expected_active_record_relation.rbi +199 -0
  90. data/spec/test_data/v5.0/expected_habtm_subjects.rbi +660 -0
  91. data/spec/test_data/v5.0/expected_habtm_wizards.rbi +660 -0
  92. data/spec/test_data/v5.0/expected_headmaster.rbi +452 -0
  93. data/spec/test_data/v5.0/expected_internal_metadata.rbi +0 -217
  94. data/spec/test_data/v5.0/expected_potion.rbi +0 -217
  95. data/spec/test_data/v5.0/expected_robe.rbi +0 -217
  96. data/spec/test_data/v5.0/expected_schema_migration.rbi +0 -217
  97. data/spec/test_data/v5.0/expected_school.rbi +11 -217
  98. data/spec/test_data/v5.0/expected_spell.rbi +440 -0
  99. data/spec/test_data/v5.0/expected_spell/habtm_spell_books.rbi +443 -0
  100. data/spec/test_data/v5.0/expected_spell_book.rbi +14 -222
  101. data/spec/test_data/v5.0/expected_spell_book/habtm_spell_books.rbi +637 -0
  102. data/spec/test_data/v5.0/expected_spell_book/habtm_spells.rbi +443 -0
  103. data/spec/test_data/v5.0/expected_squib.rbi +14 -219
  104. data/spec/test_data/v5.0/expected_subject.rbi +440 -0
  105. data/spec/test_data/v5.0/expected_subject/habtm_wizards.rbi +443 -0
  106. data/spec/test_data/v5.0/expected_wand.rbi +4 -221
  107. data/spec/test_data/v5.0/expected_wizard.rbi +36 -240
  108. data/spec/test_data/v5.0/expected_wizard/habtm_subjects.rbi +443 -0
  109. data/spec/test_data/v5.0/expected_wizard_wo_spellbook.rbi +30 -240
  110. data/spec/test_data/v5.1/expected_active_record_base.rbi +113 -0
  111. data/spec/test_data/v5.1/expected_active_record_relation.rbi +178 -0
  112. data/spec/test_data/v5.1/expected_habtm_subjects.rbi +672 -0
  113. data/spec/test_data/v5.1/expected_habtm_wizards.rbi +672 -0
  114. data/spec/test_data/v5.1/expected_headmaster.rbi +464 -0
  115. data/spec/test_data/v5.1/expected_internal_metadata.rbi +0 -217
  116. data/spec/test_data/v5.1/expected_potion.rbi +0 -217
  117. data/spec/test_data/v5.1/expected_robe.rbi +0 -217
  118. data/spec/test_data/v5.1/expected_schema_migration.rbi +0 -217
  119. data/spec/test_data/v5.1/expected_school.rbi +11 -217
  120. data/spec/test_data/v5.1/expected_spell.rbi +452 -0
  121. data/spec/test_data/v5.1/expected_spell/habtm_spell_books.rbi +455 -0
  122. data/spec/test_data/v5.1/expected_spell_book.rbi +14 -222
  123. data/spec/test_data/v5.1/expected_spell_book/habtm_spell_books.rbi +649 -0
  124. data/spec/test_data/v5.1/expected_spell_book/habtm_spells.rbi +455 -0
  125. data/spec/test_data/v5.1/expected_squib.rbi +14 -219
  126. data/spec/test_data/v5.1/expected_subject.rbi +452 -0
  127. data/spec/test_data/v5.1/expected_subject/habtm_wizards.rbi +455 -0
  128. data/spec/test_data/v5.1/expected_wand.rbi +4 -221
  129. data/spec/test_data/v5.1/expected_wizard.rbi +36 -240
  130. data/spec/test_data/v5.1/expected_wizard/habtm_subjects.rbi +455 -0
  131. data/spec/test_data/v5.1/expected_wizard_wo_spellbook.rbi +30 -240
  132. data/spec/test_data/v5.2/expected_active_record_base.rbi +113 -0
  133. data/spec/test_data/v5.2/expected_active_record_relation.rbi +175 -0
  134. data/spec/test_data/v5.2/expected_attachment.rbi +0 -217
  135. data/spec/test_data/v5.2/expected_blob.rbi +3 -217
  136. data/spec/test_data/v5.2/expected_habtm_subjects.rbi +672 -0
  137. data/spec/test_data/v5.2/expected_habtm_wizards.rbi +672 -0
  138. data/spec/test_data/v5.2/expected_headmaster.rbi +464 -0
  139. data/spec/test_data/v5.2/expected_internal_metadata.rbi +0 -217
  140. data/spec/test_data/v5.2/expected_potion.rbi +0 -217
  141. data/spec/test_data/v5.2/expected_robe.rbi +0 -217
  142. data/spec/test_data/v5.2/expected_schema_migration.rbi +0 -217
  143. data/spec/test_data/v5.2/expected_school.rbi +11 -217
  144. data/spec/test_data/v5.2/expected_spell.rbi +452 -0
  145. data/spec/test_data/v5.2/expected_spell/habtm_spell_books.rbi +455 -0
  146. data/spec/test_data/v5.2/expected_spell_book.rbi +14 -222
  147. data/spec/test_data/v5.2/expected_spell_book/habtm_spell_books.rbi +649 -0
  148. data/spec/test_data/v5.2/expected_spell_book/habtm_spells.rbi +455 -0
  149. data/spec/test_data/v5.2/expected_squib.rbi +20 -219
  150. data/spec/test_data/v5.2/expected_subject.rbi +452 -0
  151. data/spec/test_data/v5.2/expected_subject/habtm_wizards.rbi +455 -0
  152. data/spec/test_data/v5.2/expected_wand.rbi +4 -221
  153. data/spec/test_data/v5.2/expected_wizard.rbi +42 -240
  154. data/spec/test_data/v5.2/expected_wizard/habtm_subjects.rbi +455 -0
  155. data/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi +36 -240
  156. data/spec/test_data/v6.0/expected_active_record_base.rbi +113 -0
  157. data/spec/test_data/v6.0/expected_active_record_relation.rbi +175 -0
  158. data/spec/test_data/v6.0/expected_attachment.rbi +0 -217
  159. data/spec/test_data/v6.0/expected_blob.rbi +3 -217
  160. data/spec/test_data/v6.0/expected_habtm_subjects.rbi +720 -0
  161. data/spec/test_data/v6.0/expected_habtm_wizards.rbi +720 -0
  162. data/spec/test_data/v6.0/expected_headmaster.rbi +512 -0
  163. data/spec/test_data/v6.0/expected_internal_metadata.rbi +0 -217
  164. data/spec/test_data/v6.0/expected_potion.rbi +0 -217
  165. data/spec/test_data/v6.0/expected_robe.rbi +0 -217
  166. data/spec/test_data/v6.0/expected_schema_migration.rbi +0 -217
  167. data/spec/test_data/v6.0/expected_school.rbi +11 -217
  168. data/spec/test_data/v6.0/expected_spell.rbi +500 -0
  169. data/spec/test_data/v6.0/expected_spell/habtm_spell_books.rbi +503 -0
  170. data/spec/test_data/v6.0/expected_spell_book.rbi +14 -222
  171. data/spec/test_data/v6.0/expected_spell_book/habtm_spell_books.rbi +697 -0
  172. data/spec/test_data/v6.0/expected_spell_book/habtm_spells.rbi +503 -0
  173. data/spec/test_data/v6.0/expected_squib.rbi +20 -219
  174. data/spec/test_data/v6.0/expected_subject.rbi +500 -0
  175. data/spec/test_data/v6.0/expected_subject/habtm_wizards.rbi +503 -0
  176. data/spec/test_data/v6.0/expected_wand.rbi +4 -221
  177. data/spec/test_data/v6.0/expected_wizard.rbi +42 -240
  178. data/spec/test_data/v6.0/expected_wizard/habtm_subjects.rbi +503 -0
  179. data/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi +36 -240
  180. metadata +169 -14
  181. data/lib/bundled_rbi/active_record_base.rbi +0 -83
  182. data/lib/bundled_rbi/active_record_relation.rbi +0 -122
  183. data/lib/sorbet-rails/model_plugins/active_record_finder_methods.rb +0 -131
  184. data/spec/support/v5.0/typed-override.yaml +0 -2
  185. data/spec/support/v5.1/typed-override.yaml +0 -2
  186. data/spec/support/v5.2/typed-override.yaml +0 -2
  187. data/spec/support/v6.0/typed-override.yaml +0 -2
@@ -1,4 +1,4 @@
1
- # typed: false
1
+ # typed: true
2
2
  require 'sorbet-runtime'
3
3
 
4
4
  wand = Wand.first!
@@ -27,6 +27,7 @@ T.assert_type!(T.must(wizard.wand).wizard, Wizard)
27
27
  # T.assert_type!(wizard.spell_books, SpellBook::ActiveRecord_Relation)
28
28
  # T.assert_type!(wizard.spell_books, SpellBook::ActiveRecord_AssociationRelation)
29
29
  T.assert_type!(wizard.spell_books, SpellBook::ActiveRecord_Associations_CollectionProxy)
30
+ T.assert_type!(wizard.spell_book_ids, T::Array[Integer])
30
31
 
31
32
  # -- model relation
32
33
  # default
@@ -53,6 +54,14 @@ T.assert_type!(Wizard.exists?(name: 'Test'), T::Boolean)
53
54
  T.assert_type!(Wizard.find(wizard.id), Wizard)
54
55
  T.assert_type!(Wizard.first!, Wizard)
55
56
  T.assert_type!(Wizard.first, T.nilable(Wizard))
57
+ T.assert_type!(Wizard.second!, Wizard)
58
+ T.assert_type!(Wizard.second, T.nilable(Wizard))
59
+ T.assert_type!(Wizard.third!, Wizard)
60
+ T.assert_type!(Wizard.third, T.nilable(Wizard))
61
+ T.assert_type!(Wizard.third_to_last!, Wizard)
62
+ T.assert_type!(Wizard.third_to_last, T.nilable(Wizard))
63
+ T.assert_type!(Wizard.second_to_last!, Wizard)
64
+ T.assert_type!(Wizard.second_to_last, T.nilable(Wizard))
56
65
  T.assert_type!(Wizard.last!, Wizard)
57
66
  T.assert_type!(Wizard.last, T.nilable(Wizard))
58
67
  T.assert_type!(Wizard.first_n(5), T::Array[Wizard])
@@ -61,12 +70,40 @@ T.assert_type!(Wizard.find_by(name: 'Harry Potter'), T.nilable(Wizard))
61
70
  T.assert_type!(Wizard.find_by!(name: 'Harry Potter'), Wizard)
62
71
  T.assert_type!(Wizard.find_by_id(wizard.id), T.nilable(Wizard))
63
72
  T.assert_type!(Wizard.find_by_id!(wizard.id), Wizard)
73
+ T.assert_type!(Wizard.find_or_initialize_by(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
74
+ T.assert_type!(Wizard.find_or_create_by(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
75
+ T.assert_type!(Wizard.find_or_create_by!(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
76
+ T.assert_type!(Wizard.new { |w| T.assert_type!(w, Wizard) }, Wizard)
77
+ T.assert_type!(Wizard.create(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
78
+ T.assert_type!(Wizard.create!(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
79
+ T.assert_type!(Wizard.first_or_create(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
80
+ T.assert_type!(Wizard.first_or_create!(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
81
+ T.assert_type!(Wizard.first_or_initialize { |w| T.assert_type!(w, Wizard) }, Wizard)
82
+ Wizard.find_each { |w| T.assert_type!(w, Wizard) }
83
+ T.assert_type!(Wizard.find_each, T::Enumerator[Wizard])
84
+ Wizard.find_in_batches { |w| T.assert_type!(w, T::Array[Wizard]) }
85
+ T.assert_type!(Wizard.find_in_batches, T::Enumerator[T::Array[Wizard]])
86
+ # T.assert_type!(Wizard.destroy_all, T::Array[Wizard]) # Ignored until we add support
87
+ T.assert_type!(Wizard.any?, T::Boolean)
88
+ T.assert_type!(Wizard.many?, T::Boolean)
89
+ T.assert_type!(Wizard.none?, T::Boolean)
90
+ T.assert_type!(Wizard.one?, T::Boolean)
91
+ # T.assert_type!(Wizard.update_all(name: 'Harry Potter'), Integer) # Ignored until we add support
92
+ # T.assert_type!(Wizard.delete_all, Integer) # Ignored until we add support
64
93
 
65
94
  # Finder methods -- ActiveRecord::Relation
66
95
  T.assert_type!(Wizard.all.exists?(name: 'Harry Potter'), T::Boolean)
67
96
  T.assert_type!(Wizard.all.find(wizard.id), Wizard)
68
97
  T.assert_type!(Wizard.all.first!, Wizard)
69
98
  T.assert_type!(Wizard.all.first, T.nilable(Wizard))
99
+ T.assert_type!(Wizard.all.second!, Wizard)
100
+ T.assert_type!(Wizard.all.second, T.nilable(Wizard))
101
+ T.assert_type!(Wizard.all.third!, Wizard)
102
+ T.assert_type!(Wizard.all.third, T.nilable(Wizard))
103
+ T.assert_type!(Wizard.all.third_to_last!, Wizard)
104
+ T.assert_type!(Wizard.all.third_to_last, T.nilable(Wizard))
105
+ T.assert_type!(Wizard.all.second_to_last!, Wizard)
106
+ T.assert_type!(Wizard.all.second_to_last, T.nilable(Wizard))
70
107
  T.assert_type!(Wizard.all.last!, Wizard)
71
108
  T.assert_type!(Wizard.all.last, T.nilable(Wizard))
72
109
  T.assert_type!(Wizard.all.first_n(5), T::Array[Wizard])
@@ -75,6 +112,32 @@ T.assert_type!(Wizard.all.find_by(name: 'Harry Potter'), T.nilable(Wizard))
75
112
  T.assert_type!(Wizard.all.find_by!(name: 'Harry Potter'), Wizard)
76
113
  T.assert_type!(Wizard.all.find_by_id(wizard.id), T.nilable(Wizard))
77
114
  T.assert_type!(Wizard.all.find_by_id!(wizard.id), Wizard)
115
+ T.assert_type!(Wizard.all.find_or_initialize_by(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
116
+ T.assert_type!(Wizard.all.find_or_create_by(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
117
+ T.assert_type!(Wizard.all.find_or_create_by!(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
118
+ T.assert_type!(Wizard.all.new { |w| T.assert_type!(w, Wizard) }, Wizard)
119
+ T.assert_type!(Wizard.all.build { |w| T.assert_type!(w, Wizard) }, Wizard)
120
+ T.assert_type!(Wizard.all.create(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
121
+ T.assert_type!(Wizard.all.create!(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
122
+ T.assert_type!(Wizard.all.first_or_create(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
123
+ T.assert_type!(Wizard.all.first_or_create!(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
124
+ T.assert_type!(Wizard.all.first_or_initialize { |w| T.assert_type!(w, Wizard) }, Wizard)
125
+ Wizard.all.find_each { |w| T.assert_type!(w, Wizard) }
126
+ T.assert_type!(Wizard.all.find_each, T::Enumerator[Wizard])
127
+ Wizard.all.find_in_batches { |w| T.assert_type!(w, T::Array[Wizard]) }
128
+ T.assert_type!(Wizard.all.find_in_batches, T::Enumerator[T::Array[Wizard]])
129
+ # T.assert_type!(Wizard.all.destroy_all, T::Array[Wizard]) # Ignored until we add support
130
+ T.assert_type!(Wizard.all.any?, T::Boolean)
131
+ T.assert_type!(Wizard.all.many?, T::Boolean)
132
+ T.assert_type!(Wizard.all.none?, T::Boolean)
133
+ T.assert_type!(Wizard.all.one?, T::Boolean)
134
+ # T.assert_type!(Wizard.all.update_all(name: 'Harry Potter'), Integer) # Ignored until we add support
135
+ # T.assert_type!(Wizard.all.delete_all, Integer) # Ignored until we add support
136
+ # Enumerable methods
137
+ Wizard.all.each { |w| T.assert_type!(w, Wizard) }
138
+ Wizard.all.map { |w| T.assert_type!(w, Wizard) }
139
+ T.assert_type!(Wizard.all.to_a, T::Array[Wizard])
140
+ T.assert_type!(Wizard.all.empty?, T::Boolean)
78
141
 
79
142
  # Finder methods -- CollectionProxy
80
143
  spell_book = wizard.spell_books.first!
@@ -82,15 +145,44 @@ spell_books = wizard.spell_books
82
145
  T.assert_type!(spell_books.exists?(name: 'Fantastic Beasts'), T::Boolean)
83
146
  T.assert_type!(spell_books.find(spell_book.id), SpellBook)
84
147
  T.assert_type!(spell_books.first!, SpellBook)
85
- # T.assert_type!(spell_books.first, T.nilable(SpellBook)) # TODO fix sig for 5.0
148
+ T.assert_type!(spell_books.first, T.nilable(SpellBook))
149
+ T.assert_type!(spell_books.second!, SpellBook)
150
+ T.assert_type!(spell_books.second, T.nilable(SpellBook))
151
+ T.assert_type!(spell_books.third!, SpellBook)
152
+ T.assert_type!(spell_books.third, T.nilable(SpellBook))
153
+ T.assert_type!(spell_books.third_to_last!, SpellBook)
154
+ T.assert_type!(spell_books.third_to_last, T.nilable(SpellBook))
155
+ T.assert_type!(spell_books.second_to_last!, SpellBook)
156
+ T.assert_type!(spell_books.second_to_last, T.nilable(SpellBook))
86
157
  T.assert_type!(spell_books.last!, SpellBook)
87
- # T.assert_type!(spell_books.last, T.nilable(SpellBook)) # TODO fix sig for 5.0
158
+ T.assert_type!(spell_books.last, T.nilable(SpellBook))
88
159
  T.assert_type!(spell_books.first_n(5), T::Array[SpellBook])
89
160
  T.assert_type!(spell_books.last_n(5), T::Array[SpellBook])
90
161
  T.assert_type!(spell_books.find_by(name: 'Fantastic Beasts'), T.nilable(SpellBook))
91
162
  T.assert_type!(spell_books.find_by!(name: 'Fantastic Beasts'), SpellBook)
92
163
  T.assert_type!(spell_books.find_by_id(spell_book.id), T.nilable(SpellBook))
93
164
  T.assert_type!(spell_books.find_by_id!(spell_book.id), SpellBook)
165
+ T.assert_type!(spell_books.find_or_initialize_by(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
166
+ T.assert_type!(spell_books.find_or_create_by(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
167
+ T.assert_type!(spell_books.find_or_create_by!(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
168
+ T.assert_type!(spell_books.new { |s| T.assert_type!(s, SpellBook) }, SpellBook)
169
+ T.assert_type!(spell_books.build { |s| T.assert_type!(s, SpellBook) }, SpellBook)
170
+ T.assert_type!(spell_books.create(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
171
+ T.assert_type!(spell_books.create!(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
172
+ T.assert_type!(spell_books.first_or_create(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
173
+ T.assert_type!(spell_books.first_or_create!(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
174
+ T.assert_type!(spell_books.first_or_initialize { |s| T.assert_type!(s, SpellBook) }, SpellBook)
175
+ # spell_books.find_each { |s| T.assert_type!(s, SpellBook) } # TODO: Handle for Rails 6
176
+ # T.assert_type!(spell_books.find_each, T::Enumerator[SpellBook]) # TODO: Handle for Rails 6
177
+ # spell_books.find_in_batches { |s| T.assert_type!(s, T::Array[SpellBook]) } # TODO: Handle for Rails 6
178
+ # T.assert_type!(spell_books.find_in_batches, T::Enumerator[T::Array[SpellBook]]) # TODO: Handle for Rails 6
179
+ # T.assert_type!(spell_books.destroy_all, T::Array[SpellBook]) # Ignored until we add support
180
+ T.assert_type!(spell_books.any?, T::Boolean)
181
+ T.assert_type!(spell_books.many?, T::Boolean)
182
+ T.assert_type!(spell_books.none?, T::Boolean)
183
+ T.assert_type!(spell_books.one?, T::Boolean)
184
+ # T.assert_type!(spell_books.update_all(name: 'Fantastic Beasts'), Integer) # Ignored until we add support
185
+ # T.assert_type!(spell_books.delete_all, Integer) # Ignored until we add support
94
186
  # CollectionProxy query also typed correctly!
95
187
  T.assert_type!(spell_books.where(id: 1), SpellBook::ActiveRecord_AssociationRelation)
96
188
  T.assert_type!(spell_books.preload(:wizard), SpellBook::ActiveRecord_AssociationRelation)
@@ -98,63 +190,75 @@ T.assert_type!(spell_books.eager_load(:wizard), SpellBook::ActiveRecord_Associat
98
190
  T.assert_type!(spell_books.order(:id), SpellBook::ActiveRecord_AssociationRelation)
99
191
  T.assert_type!(spell_books.where.not(id: 1), SpellBook::ActiveRecord_AssociationRelation)
100
192
  T.assert_type!(spell_books.biology, SpellBook::ActiveRecord_AssociationRelation)
193
+ # Enumerable methods
194
+ spell_books.each { |s| T.assert_type!(s, SpellBook) }
195
+ spell_books.map { |s| T.assert_type!(s, SpellBook) }
196
+ T.assert_type!(spell_books.to_a, T::Array[SpellBook])
197
+ T.assert_type!(spell_books.empty?, T::Boolean)
198
+ # Push methods
199
+ T.assert_type!(spell_books << spell_book, SpellBook::ActiveRecord_Associations_CollectionProxy)
200
+ T.assert_type!(spell_books << [spell_book], SpellBook::ActiveRecord_Associations_CollectionProxy)
201
+ T.assert_type!(spell_books.append(spell_book), SpellBook::ActiveRecord_Associations_CollectionProxy)
202
+ T.assert_type!(spell_books.append([spell_book]), SpellBook::ActiveRecord_Associations_CollectionProxy)
203
+ T.assert_type!(spell_books.push(spell_book), SpellBook::ActiveRecord_Associations_CollectionProxy)
204
+ T.assert_type!(spell_books.push([spell_book]), SpellBook::ActiveRecord_Associations_CollectionProxy)
205
+ # T.assert_type!(spell_books.concat(spell_book), SpellBook::ActiveRecord_Associations_CollectionProxy) # TODO: In Rails 5.0 and 5.1 this actually returns T::Array
206
+ # T.assert_type!(spell_books.concat([spell_book]), SpellBook::ActiveRecord_Associations_CollectionProxy) # TODO: In Rails 5.0 and 5.1 this actually returns T::Array
101
207
 
102
208
  # finder methods -- AssociationRelation
103
- spell_books_query = spell_books.where(id: 1)
209
+ spell_books_query = spell_books.where(wizard_id: wizard.id)
104
210
  T.assert_type!(spell_books_query.exists?(name: 'Fantastic Beasts'), T::Boolean)
105
211
  T.assert_type!(spell_books_query.find(spell_book.id), SpellBook)
106
212
  T.assert_type!(spell_books_query.first!, SpellBook)
107
- # T.assert_type!(spell_books_query.first, T.nilable(SpellBook)) # TODO fix sig for 5.0
213
+ T.assert_type!(spell_books_query.first, T.nilable(SpellBook))
214
+ T.assert_type!(spell_books_query.second!, SpellBook)
215
+ T.assert_type!(spell_books_query.second, T.nilable(SpellBook))
216
+ T.assert_type!(spell_books_query.third!, SpellBook)
217
+ T.assert_type!(spell_books_query.third, T.nilable(SpellBook))
218
+ T.assert_type!(spell_books_query.third_to_last!, SpellBook)
219
+ T.assert_type!(spell_books_query.third_to_last, T.nilable(SpellBook))
220
+ T.assert_type!(spell_books_query.second_to_last!, SpellBook)
221
+ T.assert_type!(spell_books_query.second_to_last, T.nilable(SpellBook))
108
222
  T.assert_type!(spell_books_query.last!, SpellBook)
109
- # T.assert_type!(spell_books_query.last, T.nilable(SpellBook)) # TODO fix sig for 5.0
223
+ T.assert_type!(spell_books_query.last, T.nilable(SpellBook))
110
224
  T.assert_type!(spell_books_query.first_n(5), T::Array[SpellBook])
111
225
  T.assert_type!(spell_books_query.last_n(5), T::Array[SpellBook])
112
226
  T.assert_type!(spell_books_query.find_by(name: 'Fantastic Beasts'), T.nilable(SpellBook))
113
227
  T.assert_type!(spell_books_query.find_by!(name: 'Fantastic Beasts'), SpellBook)
114
228
  T.assert_type!(spell_books_query.find_by_id(spell_book.id), T.nilable(SpellBook))
115
229
  T.assert_type!(spell_books_query.find_by_id!(spell_book.id), SpellBook)
230
+ T.assert_type!(spell_books_query.find_or_initialize_by(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
231
+ T.assert_type!(spell_books_query.find_or_create_by(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
232
+ T.assert_type!(spell_books_query.find_or_create_by!(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
233
+ T.assert_type!(spell_books_query.new { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support
234
+ T.assert_type!(spell_books_query.build { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support # Ignored until we add support
235
+ T.assert_type!(spell_books_query.create(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support
236
+ T.assert_type!(spell_books_query.create!(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support
237
+ T.assert_type!(spell_books_query.first_or_create(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support
238
+ T.assert_type!(spell_books_query.first_or_create!(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support
239
+ T.assert_type!(spell_books_query.first_or_initialize { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support
240
+ # spell_books_query.find_each { |s| T.assert_type!(s, SpellBook) } # TODO: Handle for Rails 6
241
+ # T.assert_type!(spell_books_query.find_each, T::Enumerator[SpellBook]) # TODO: Handle for Rails 6
242
+ # spell_books_query.find_in_batches { |s| T.assert_type!(s, T::Array[SpellBook]) } # TODO: Handle for Rails 6
243
+ # T.assert_type!(spell_books_query.find_in_batches, T::Enumerator[T::Array[SpellBook]]) # TODO: Handle for Rails 6
244
+ # T.assert_type!(spell_books_query.destroy_all, T::Array[SpellBook]) # Ignored until we add support
245
+ T.assert_type!(spell_books_query.any?, T::Boolean)
246
+ T.assert_type!(spell_books_query.many?, T::Boolean)
247
+ T.assert_type!(spell_books_query.none?, T::Boolean)
248
+ T.assert_type!(spell_books_query.one?, T::Boolean)
249
+ # T.assert_type!(spell_books_query.update_all(name: 'Fantastic Beasts'), Integer) # Ignored until we add support
250
+ # T.assert_type!(spell_books_query.delete_all, Integer) # Ignored until we add support
116
251
  # Query chaining
117
252
  T.assert_type!(spell_books_query.preload(:wizard), SpellBook::ActiveRecord_AssociationRelation)
118
253
  T.assert_type!(spell_books_query.eager_load(:wizard), SpellBook::ActiveRecord_AssociationRelation)
119
254
  T.assert_type!(spell_books_query.order(:id), SpellBook::ActiveRecord_AssociationRelation)
120
255
  T.assert_type!(spell_books_query.where.not(id: 1), SpellBook::ActiveRecord_AssociationRelation)
121
256
  T.assert_type!(spell_books_query.biology, SpellBook::ActiveRecord_AssociationRelation)
122
-
123
- # Enumerable on activerecord relation
124
- T.assert_type!(Wizard.all.to_a, T::Array[Wizard])
125
- Wizard.all.each do |w|
126
- T.assert_type!(w, Wizard)
127
- end
128
- Wizard.all.map do |w|
129
- T.assert_type!(w, Wizard)
130
- end
131
- Wizard.all.to_a.map do |w|
132
- T.assert_type!(w, Wizard)
133
- end
134
-
135
- # enum on association collection proxy
136
- T.assert_type!(wizard.spell_books.to_a, T::Array[SpellBook])
137
- wizard.spell_books.each do |sp|
138
- T.assert_type!(sp, SpellBook)
139
- end
140
- wizard.spell_books.map do |sp|
141
- T.assert_type!(sp, SpellBook)
142
- end
143
- wizard.spell_books.to_a.map do |sp|
144
- T.assert_type!(sp, SpellBook)
145
- end
146
-
147
- # enum on association relation
148
- T.assert_type!(wizard.spell_books.where(id: 1).to_a, T::Array[SpellBook])
149
- wizard.spell_books.where(id: 1).each do |sp|
150
- T.assert_type!(sp, SpellBook)
151
- end
152
- wizard.spell_books.where(id: 1).map do |sp|
153
- T.assert_type!(sp, SpellBook)
154
- end
155
- wizard.spell_books.where(id: 1).to_a.map do |sp|
156
- T.assert_type!(sp, SpellBook)
157
- end
257
+ # Enumerable methods
258
+ spell_books_query.each { |s| T.assert_type!(s, SpellBook) }
259
+ spell_books_query.map { |s| T.assert_type!(s, SpellBook) }
260
+ T.assert_type!(spell_books_query.to_a, T::Array[SpellBook])
261
+ T.assert_type!(spell_books_query.empty?, T::Boolean)
158
262
 
159
263
  # Model columns
160
264
  T.assert_type!(wizard.id, Integer)
@@ -15,7 +15,7 @@ RSpec.describe SorbetRails::ModelRbiFormatter do
15
15
  end
16
16
 
17
17
  it 'generates correct rbi file for Wizard' do
18
- class_set = Set.new(['Wizard', 'Wand', 'SpellBook', 'School'])
18
+ class_set = Set.new(['Wizard', 'Wand', 'SpellBook', 'School', 'Subject'])
19
19
  if Object.const_defined?('ActiveStorage::Attachment')
20
20
  class_set << 'ActiveStorage::Attachment'
21
21
  end
@@ -67,8 +67,21 @@ def expect_match_file(content, file_path)
67
67
  expect(content).to eql(expected_value)
68
68
  end
69
69
 
70
+ # File uses File::SEPARATOR by default but will also use File::ALT_SEPARATOR if it's not nil
71
+ FILE_SEPARATOR_RE = Regexp.union(*[File::SEPARATOR, File::ALT_SEPARATOR].compact).freeze
72
+
70
73
  def expect_files(base_dir:, files:)
71
- rbi_files = Dir[File.join(base_dir, "*.rbi")]
74
+ dirs = Set.new([base_dir])
75
+ # if any files contain file separators then include those paths in our globbing as well
76
+ files.each do |f|
77
+ next unless f.match?(FILE_SEPARATOR_RE)
78
+ dirs << File.join(base_dir, File.dirname(f))
79
+ end
80
+
81
+ # glob all of our dirs
82
+ rbi_files = dirs.reduce([]) do |memo, dir|
83
+ memo += Dir[File.join(dir, "*.rbi")]
84
+ end
72
85
 
73
86
  # smoke test
74
87
  # expect(rbi_files.size).to eql(files.size)
@@ -0,0 +1,21 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe 'rake rails_rbi:active_record', type: :task do
4
+ let!(:generated_dir_path) { Rails.root.join("sorbet", "rails-rbi") }
5
+
6
+ it "preloads the Rails environment" do
7
+ expect(task.prerequisites).to include("environment")
8
+ end
9
+
10
+ it "generates rbi correctly" do
11
+ task.invoke
12
+
13
+ expect_files(
14
+ base_dir: generated_dir_path,
15
+ files: [
16
+ "active_record_base.rbi",
17
+ "active_record_relation.rbi",
18
+ ],
19
+ )
20
+ end
21
+ end
@@ -12,13 +12,20 @@ RSpec.describe 'rake rails_rbi:models', type: :task do
12
12
  expect_files(
13
13
  base_dir: generated_dir_path,
14
14
  files: [
15
+ 'headmaster.rbi',
15
16
  'potion.rbi',
16
17
  'robe.rbi',
17
18
  'school.rbi',
19
+ 'spell.rbi',
20
+ 'spell/habtm_spell_books.rbi',
18
21
  'spell_book.rbi',
22
+ 'spell_book/habtm_spells.rbi',
19
23
  'squib.rbi',
24
+ 'subject.rbi',
25
+ 'subject/habtm_wizards.rbi',
20
26
  'wand.rbi',
21
27
  'wizard.rbi',
28
+ 'wizard/habtm_subjects.rbi',
22
29
  ]
23
30
  )
24
31
  if Object.const_defined?('ActiveStorage')
@@ -10,6 +10,9 @@ RSpec.describe 'sorbet' do
10
10
  quidditch_position: :seeker,
11
11
  )
12
12
  end
13
+ # Needed for `second!` and `third!`
14
+ let!(:other_wizards) { 2.times { |i| Wizard.create!(name: "Wizard #{i}") } }
15
+
13
16
  let!(:book) do
14
17
  SpellBook.create!(
15
18
  name: 'Fantastic Beasts',
@@ -17,6 +20,9 @@ RSpec.describe 'sorbet' do
17
20
  book_type: :biology,
18
21
  )
19
22
  end
23
+ # Needed for `second!` and `third!`
24
+ let!(:other_books) { 2.times { |i| SpellBook.create!(name: "SpellBook #{i}", wizard: harry) } }
25
+
20
26
  let!(:wand) do
21
27
  Wand.create!(
22
28
  wizard: harry,
@@ -49,6 +55,11 @@ RSpec.describe 'sorbet' do
49
55
  puts "================================="
50
56
  end
51
57
 
58
+ # Ensure sorbet_test_cases.rb is set to `typed: true` since srb init may
59
+ # set it to false.
60
+ sorbet_test_cases_path = Rails.root.join('sorbet_test_cases.rb')
61
+ File.write(sorbet_test_cases_path, File.read(sorbet_test_cases_path).gsub(/^# typed: \w+$/, "# typed: true"))
62
+
52
63
  # run sorbet-rails rake tasks
53
64
  Rake::Task['rails_rbi:all'].invoke
54
65
 
@@ -68,7 +79,7 @@ RSpec.describe 'sorbet' do
68
79
 
69
80
  it 'returns expected sorbet tc result' do
70
81
  stdout, stderr, status = Open3.capture3(
71
- 'bundle', 'exec', 'srb', 'tc', '--typed-override=typed-override.yaml',
82
+ 'bundle', 'exec', 'srb', 'tc',
72
83
  chdir: Rails.root.to_path,
73
84
  )
74
85
  expected_file_path = 'expected_srb_tc_output.txt'
@@ -1,11 +1,11 @@
1
1
  PATH
2
2
  remote: ../../..
3
3
  specs:
4
- sorbet-rails (0.6.2)
4
+ sorbet-rails (0.6.3)
5
5
  method_source (>= 0.9.2)
6
6
  parlour (~> 2.0)
7
7
  parser (>= 2.7)
8
- sorbet-coerce (>= 0.2.4)
8
+ sorbet-coerce (>= 0.2.6)
9
9
  sorbet-runtime (>= 0.5)
10
10
 
11
11
  GEM
@@ -81,7 +81,7 @@ GEM
81
81
  parser
82
82
  rainbow (~> 3.0)
83
83
  sorbet-runtime (>= 0.5)
84
- parser (2.7.0.5)
84
+ parser (2.7.1.1)
85
85
  ast (~> 2.4.0)
86
86
  polyfill (1.8.0)
87
87
  puma (3.12.4)
@@ -114,15 +114,15 @@ GEM
114
114
  rainbow (3.0.0)
115
115
  rake (13.0.1)
116
116
  safe_type (1.1.1)
117
- sorbet (0.5.5472)
118
- sorbet-static (= 0.5.5472)
119
- sorbet-coerce (0.2.4)
117
+ sorbet (0.5.5480)
118
+ sorbet-static (= 0.5.5480)
119
+ sorbet-coerce (0.2.6)
120
120
  polyfill (~> 1.8)
121
121
  safe_type (~> 1.1, >= 1.1.1)
122
122
  sorbet (>= 0.4.4704)
123
123
  sorbet-runtime (>= 0.4.4704)
124
- sorbet-runtime (0.5.5472)
125
- sorbet-static (0.5.5472-universal-darwin-14)
124
+ sorbet-runtime (0.5.5480)
125
+ sorbet-static (0.5.5480-universal-darwin-14)
126
126
  sprockets (4.0.0)
127
127
  concurrent-ruby (~> 1.0)
128
128
  rack (> 1, < 3)
@@ -0,0 +1,8 @@
1
+ # typed: strong
2
+ class Headmaster < ApplicationRecord
3
+ belongs_to :school, required: false
4
+ belongs_to :wizard, optional: true
5
+
6
+ validates :school, presence: true
7
+ validates :wizard_id, presence: true
8
+ end
@@ -1,3 +1,5 @@
1
1
  # typed: strong
2
2
  class School < ApplicationRecord
3
+ has_one :headmaster
4
+ validates :headmaster, presence: true
3
5
  end
@@ -0,0 +1,5 @@
1
+ # typed: strong
2
+ class Spell < ApplicationRecord
3
+ # habtm enforced at the DB level
4
+ has_and_belongs_to_many :spell_books
5
+ end
@@ -5,6 +5,9 @@ class SpellBook < ApplicationRecord
5
5
  # simulate when belongs_to is optional by default, but it is enforced at the DB level
6
6
  belongs_to :wizard, optional: true
7
7
 
8
+ # habtm enforced at the DB level
9
+ has_and_belongs_to_many :spells
10
+
8
11
  enum book_type: {
9
12
  unclassified: 0,
10
13
  biology: 1,