sorbet-rails 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/README.md +3 -3
  4. data/lib/bundled_rbi/typed_enum.rbi +7 -0
  5. data/lib/sorbet-rails.rb +0 -2
  6. data/lib/sorbet-rails/active_record_rbi_formatter.rb +301 -0
  7. data/lib/sorbet-rails/config.rb +0 -1
  8. data/lib/sorbet-rails/dependent_gem_rbis/activerecord.rbi +11 -0
  9. data/lib/sorbet-rails/deprecation.rb +5 -0
  10. data/lib/sorbet-rails/gem_plugins/active_flag_plugin.rb +0 -1
  11. data/lib/sorbet-rails/gem_plugins/paperclip_plugin.rb +0 -1
  12. data/lib/sorbet-rails/model_plugins/active_record_assoc.rb +36 -8
  13. data/lib/sorbet-rails/model_plugins/active_record_attribute.rb +20 -9
  14. data/lib/sorbet-rails/model_plugins/active_record_enum.rb +0 -1
  15. data/lib/sorbet-rails/model_plugins/active_record_named_scope.rb +15 -6
  16. data/lib/sorbet-rails/model_plugins/active_record_querying.rb +34 -3
  17. data/lib/sorbet-rails/model_plugins/active_storage_methods.rb +1 -1
  18. data/lib/sorbet-rails/model_plugins/base.rb +10 -0
  19. data/lib/sorbet-rails/model_plugins/enumerable_collections.rb +0 -50
  20. data/lib/sorbet-rails/model_plugins/plugins.rb +0 -3
  21. data/lib/sorbet-rails/model_rbi_formatter.rb +6 -10
  22. data/lib/sorbet-rails/model_utils.rb +83 -36
  23. data/lib/sorbet-rails/rails_mixins/generated_url_helpers.rb +2 -3
  24. data/lib/sorbet-rails/railtie.rb +0 -2
  25. data/lib/sorbet-rails/tasks/rails_rbi.rake +32 -24
  26. data/sorbet-rails.gemspec +2 -2
  27. data/spec/active_record_rbi_formatter_spec.rb +24 -0
  28. data/spec/generators/rails-template.rb +90 -6
  29. data/spec/generators/sorbet_test_cases.rb +204 -122
  30. data/spec/model_rbi_formatter_spec.rb +1 -1
  31. data/spec/rails_helper.rb +14 -1
  32. data/spec/rake_rails_rbi_active_record_spec.rb +21 -0
  33. data/spec/rake_rails_rbi_models_spec.rb +7 -0
  34. data/spec/sorbet_spec.rb +12 -1
  35. data/spec/support/v5.0/Gemfile.lock +8 -8
  36. data/spec/support/v5.0/app/models/headmaster.rb +8 -0
  37. data/spec/support/v5.0/app/models/school.rb +2 -0
  38. data/spec/support/v5.0/app/models/spell.rb +5 -0
  39. data/spec/support/v5.0/app/models/spell_book.rb +5 -0
  40. data/spec/support/v5.0/app/models/subject.rb +5 -0
  41. data/spec/support/v5.0/app/models/wizard.rb +6 -1
  42. data/spec/support/v5.0/db/migrate/20190620000010_add_subject.rb +8 -0
  43. data/spec/support/v5.0/db/migrate/20190620000011_add_subjects_wizards.rb +8 -0
  44. data/spec/support/v5.0/db/migrate/20190620000012_add_spell.rb +8 -0
  45. data/spec/support/v5.0/db/migrate/20190620000013_add_spells_spell_books.rb +8 -0
  46. data/spec/support/v5.0/db/migrate/20190620000014_create_headmasters.rb +9 -0
  47. data/spec/support/v5.0/db/schema.rb +28 -1
  48. data/spec/support/v5.0/lib/mythical_rbi_plugin.rb +1 -1
  49. data/spec/support/v5.0/sorbet_test_cases.rb +204 -122
  50. data/spec/support/v5.1/Gemfile.lock +8 -8
  51. data/spec/support/v5.1/app/models/headmaster.rb +8 -0
  52. data/spec/support/v5.1/app/models/school.rb +2 -0
  53. data/spec/support/v5.1/app/models/spell.rb +5 -0
  54. data/spec/support/v5.1/app/models/spell_book.rb +5 -0
  55. data/spec/support/v5.1/app/models/subject.rb +5 -0
  56. data/spec/support/v5.1/app/models/wizard.rb +6 -1
  57. data/spec/support/v5.1/db/migrate/20190620000010_add_subject.rb +8 -0
  58. data/spec/support/v5.1/db/migrate/20190620000011_add_subjects_wizards.rb +8 -0
  59. data/spec/support/v5.1/db/migrate/20190620000012_add_spell.rb +8 -0
  60. data/spec/support/v5.1/db/migrate/20190620000013_add_spells_spell_books.rb +8 -0
  61. data/spec/support/v5.1/db/migrate/20190620000014_create_headmasters.rb +9 -0
  62. data/spec/support/v5.1/db/schema.rb +28 -1
  63. data/spec/support/v5.1/lib/mythical_rbi_plugin.rb +1 -1
  64. data/spec/support/v5.1/sorbet_test_cases.rb +204 -122
  65. data/spec/support/v5.2/Gemfile +1 -1
  66. data/spec/support/v5.2/Gemfile.lock +9 -9
  67. data/spec/support/v5.2/app/models/headmaster.rb +8 -0
  68. data/spec/support/v5.2/app/models/school.rb +2 -0
  69. data/spec/support/v5.2/app/models/spell.rb +5 -0
  70. data/spec/support/v5.2/app/models/spell_book.rb +5 -0
  71. data/spec/support/v5.2/app/models/subject.rb +5 -0
  72. data/spec/support/v5.2/app/models/wizard.rb +5 -0
  73. data/spec/support/v5.2/config/puma.rb +3 -0
  74. data/spec/support/v5.2/db/migrate/20190620000010_add_subject.rb +8 -0
  75. data/spec/support/v5.2/db/migrate/20190620000011_add_subjects_wizards.rb +8 -0
  76. data/spec/support/v5.2/db/migrate/20190620000012_add_spell.rb +8 -0
  77. data/spec/support/v5.2/db/migrate/20190620000013_add_spells_spell_books.rb +8 -0
  78. data/spec/support/v5.2/db/migrate/20190620000014_create_headmasters.rb +9 -0
  79. data/spec/support/v5.2/db/schema.rb +28 -1
  80. data/spec/support/v5.2/lib/mythical_rbi_plugin.rb +1 -1
  81. data/spec/support/v5.2/sorbet_test_cases.rb +204 -122
  82. data/spec/support/v6.0/Gemfile.lock +8 -8
  83. data/spec/support/v6.0/app/models/headmaster.rb +8 -0
  84. data/spec/support/v6.0/app/models/school.rb +2 -0
  85. data/spec/support/v6.0/app/models/spell.rb +5 -0
  86. data/spec/support/v6.0/app/models/spell_book.rb +5 -0
  87. data/spec/support/v6.0/app/models/subject.rb +5 -0
  88. data/spec/support/v6.0/app/models/wizard.rb +6 -1
  89. data/spec/support/v6.0/db/migrate/20190620000010_add_subject.rb +8 -0
  90. data/spec/support/v6.0/db/migrate/20190620000011_add_subjects_wizards.rb +8 -0
  91. data/spec/support/v6.0/db/migrate/20190620000012_add_spell.rb +8 -0
  92. data/spec/support/v6.0/db/migrate/20190620000013_add_spells_spell_books.rb +8 -0
  93. data/spec/support/v6.0/db/migrate/20190620000014_create_headmasters.rb +9 -0
  94. data/spec/support/v6.0/db/schema.rb +28 -1
  95. data/spec/support/v6.0/lib/mythical_rbi_plugin.rb +1 -1
  96. data/spec/support/v6.0/sorbet_test_cases.rb +204 -122
  97. data/spec/test_data/v5.0/expected_active_record_base.rbi +113 -0
  98. data/spec/test_data/v5.0/expected_active_record_relation.rbi +199 -0
  99. data/spec/test_data/v5.0/expected_habtm_subjects.rbi +660 -0
  100. data/spec/test_data/v5.0/expected_habtm_wizards.rbi +660 -0
  101. data/spec/test_data/v5.0/expected_headmaster.rbi +304 -0
  102. data/spec/test_data/v5.0/expected_internal_metadata.rbi +38 -401
  103. data/spec/test_data/v5.0/expected_potion.rbi +38 -401
  104. data/spec/test_data/v5.0/expected_robe.rbi +38 -403
  105. data/spec/test_data/v5.0/expected_schema_migration.rbi +38 -401
  106. data/spec/test_data/v5.0/expected_school.rbi +47 -401
  107. data/spec/test_data/v5.0/expected_spell.rbi +292 -0
  108. data/spec/test_data/v5.0/expected_spell/habtm_spell_books.rbi +295 -0
  109. data/spec/test_data/v5.0/expected_spell_book.rbi +86 -432
  110. data/spec/test_data/v5.0/expected_spell_book/habtm_spell_books.rbi +637 -0
  111. data/spec/test_data/v5.0/expected_spell_book/habtm_spells.rbi +295 -0
  112. data/spec/test_data/v5.0/expected_squib.rbi +122 -477
  113. data/spec/test_data/v5.0/expected_subject.rbi +292 -0
  114. data/spec/test_data/v5.0/expected_subject/habtm_wizards.rbi +295 -0
  115. data/spec/test_data/v5.0/expected_wand.rbi +75 -442
  116. data/spec/test_data/v5.0/expected_wizard.rbi +144 -498
  117. data/spec/test_data/v5.0/expected_wizard/habtm_subjects.rbi +295 -0
  118. data/spec/test_data/v5.0/expected_wizard_wo_spellbook.rbi +138 -498
  119. data/spec/test_data/v5.1/expected_active_record_base.rbi +113 -0
  120. data/spec/test_data/v5.1/expected_active_record_relation.rbi +178 -0
  121. data/spec/test_data/v5.1/expected_habtm_subjects.rbi +672 -0
  122. data/spec/test_data/v5.1/expected_habtm_wizards.rbi +672 -0
  123. data/spec/test_data/v5.1/expected_headmaster.rbi +310 -0
  124. data/spec/test_data/v5.1/expected_internal_metadata.rbi +38 -407
  125. data/spec/test_data/v5.1/expected_potion.rbi +38 -407
  126. data/spec/test_data/v5.1/expected_robe.rbi +38 -409
  127. data/spec/test_data/v5.1/expected_schema_migration.rbi +38 -407
  128. data/spec/test_data/v5.1/expected_school.rbi +47 -407
  129. data/spec/test_data/v5.1/expected_spell.rbi +298 -0
  130. data/spec/test_data/v5.1/expected_spell/habtm_spell_books.rbi +301 -0
  131. data/spec/test_data/v5.1/expected_spell_book.rbi +86 -438
  132. data/spec/test_data/v5.1/expected_spell_book/habtm_spell_books.rbi +649 -0
  133. data/spec/test_data/v5.1/expected_spell_book/habtm_spells.rbi +301 -0
  134. data/spec/test_data/v5.1/expected_squib.rbi +123 -484
  135. data/spec/test_data/v5.1/expected_subject.rbi +298 -0
  136. data/spec/test_data/v5.1/expected_subject/habtm_wizards.rbi +301 -0
  137. data/spec/test_data/v5.1/expected_wand.rbi +75 -448
  138. data/spec/test_data/v5.1/expected_wizard.rbi +145 -505
  139. data/spec/test_data/v5.1/expected_wizard/habtm_subjects.rbi +301 -0
  140. data/spec/test_data/v5.1/expected_wizard_wo_spellbook.rbi +139 -505
  141. data/spec/test_data/v5.2/expected_active_record_base.rbi +113 -0
  142. data/spec/test_data/v5.2/expected_active_record_relation.rbi +175 -0
  143. data/spec/test_data/v5.2/expected_attachment.rbi +38 -407
  144. data/spec/test_data/v5.2/expected_blob.rbi +60 -426
  145. data/spec/test_data/v5.2/expected_habtm_subjects.rbi +672 -0
  146. data/spec/test_data/v5.2/expected_habtm_wizards.rbi +672 -0
  147. data/spec/test_data/v5.2/expected_headmaster.rbi +310 -0
  148. data/spec/test_data/v5.2/expected_internal_metadata.rbi +38 -407
  149. data/spec/test_data/v5.2/expected_potion.rbi +38 -407
  150. data/spec/test_data/v5.2/expected_robe.rbi +38 -409
  151. data/spec/test_data/v5.2/expected_schema_migration.rbi +38 -407
  152. data/spec/test_data/v5.2/expected_school.rbi +47 -407
  153. data/spec/test_data/v5.2/expected_spell.rbi +298 -0
  154. data/spec/test_data/v5.2/expected_spell/habtm_spell_books.rbi +301 -0
  155. data/spec/test_data/v5.2/expected_spell_book.rbi +86 -438
  156. data/spec/test_data/v5.2/expected_spell_book/habtm_spell_books.rbi +649 -0
  157. data/spec/test_data/v5.2/expected_spell_book/habtm_spells.rbi +301 -0
  158. data/spec/test_data/v5.2/expected_squib.rbi +133 -488
  159. data/spec/test_data/v5.2/expected_subject.rbi +298 -0
  160. data/spec/test_data/v5.2/expected_subject/habtm_wizards.rbi +301 -0
  161. data/spec/test_data/v5.2/expected_wand.rbi +75 -448
  162. data/spec/test_data/v5.2/expected_wizard.rbi +155 -509
  163. data/spec/test_data/v5.2/expected_wizard/habtm_subjects.rbi +301 -0
  164. data/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi +149 -509
  165. data/spec/test_data/v6.0/expected_active_record_base.rbi +113 -0
  166. data/spec/test_data/v6.0/expected_active_record_relation.rbi +175 -0
  167. data/spec/test_data/v6.0/expected_attachment.rbi +38 -431
  168. data/spec/test_data/v6.0/expected_blob.rbi +60 -450
  169. data/spec/test_data/v6.0/expected_habtm_subjects.rbi +720 -0
  170. data/spec/test_data/v6.0/expected_habtm_wizards.rbi +720 -0
  171. data/spec/test_data/v6.0/expected_headmaster.rbi +334 -0
  172. data/spec/test_data/v6.0/expected_internal_metadata.rbi +38 -431
  173. data/spec/test_data/v6.0/expected_potion.rbi +38 -431
  174. data/spec/test_data/v6.0/expected_robe.rbi +38 -433
  175. data/spec/test_data/v6.0/expected_routes.rbi +14 -7
  176. data/spec/test_data/v6.0/expected_schema_migration.rbi +38 -431
  177. data/spec/test_data/v6.0/expected_school.rbi +47 -431
  178. data/spec/test_data/v6.0/expected_spell.rbi +322 -0
  179. data/spec/test_data/v6.0/expected_spell/habtm_spell_books.rbi +325 -0
  180. data/spec/test_data/v6.0/expected_spell_book.rbi +98 -474
  181. data/spec/test_data/v6.0/expected_spell_book/habtm_spell_books.rbi +697 -0
  182. data/spec/test_data/v6.0/expected_spell_book/habtm_spells.rbi +325 -0
  183. data/spec/test_data/v6.0/expected_squib.rbi +162 -541
  184. data/spec/test_data/v6.0/expected_subject.rbi +322 -0
  185. data/spec/test_data/v6.0/expected_subject/habtm_wizards.rbi +325 -0
  186. data/spec/test_data/v6.0/expected_wand.rbi +91 -488
  187. data/spec/test_data/v6.0/expected_wizard.rbi +184 -562
  188. data/spec/test_data/v6.0/expected_wizard/habtm_subjects.rbi +325 -0
  189. data/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi +178 -562
  190. metadata +170 -24
  191. data/lib/bundled_rbi/active_record_base.rbi +0 -83
  192. data/lib/bundled_rbi/active_record_relation.rbi +0 -122
  193. data/lib/bundled_rbi/parameters.rbi +0 -28
  194. data/lib/sorbet-rails/custom_types/boolean_string.rb +0 -32
  195. data/lib/sorbet-rails/custom_types/integer_string.rb +0 -35
  196. data/lib/sorbet-rails/model_plugins/active_record_finder_methods.rb +0 -131
  197. data/lib/sorbet-rails/rails_mixins/custom_params_methods.rb +0 -46
  198. data/spec/boolean_string_spec.rb +0 -59
  199. data/spec/custom_params_methods_spec.rb +0 -138
  200. data/spec/integer_string_spec.rb +0 -46
  201. data/spec/support/v5.0/typed-override.yaml +0 -2
  202. data/spec/support/v5.1/typed-override.yaml +0 -2
  203. data/spec/support/v5.2/typed-override.yaml +0 -2
  204. data/spec/support/v6.0/typed-override.yaml +0 -2
@@ -11,6 +11,5 @@
11
11
  # + include GeneratedUrlHelpers
12
12
  # end
13
13
  #
14
- module GeneratedUrlHelpers
15
- include Rails.application.routes.url_helpers
16
- end
14
+ # Reference: https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/routing/route_set.rb
15
+ GeneratedUrlHelpers = Rails.application.routes.url_helpers
@@ -50,9 +50,7 @@ class SorbetRails::Railtie < Rails::Railtie
50
50
  end
51
51
 
52
52
  ActiveSupport.on_load(:action_controller) do
53
- require "sorbet-rails/rails_mixins/custom_params_methods"
54
53
  require "sorbet-rails/rails_mixins/generated_url_helpers"
55
- ActionController::Parameters.include SorbetRails::CustomParamsMethods
56
54
  end
57
55
 
58
56
  SorbetRails.register_configured_plugins
@@ -1,3 +1,4 @@
1
+ require("sorbet-rails/active_record_rbi_formatter")
1
2
  require("sorbet-rails/model_rbi_formatter")
2
3
  require("sorbet-rails/routes_rbi_formatter")
3
4
  require("sorbet-rails/helper_rbi_formatter")
@@ -34,14 +35,28 @@ namespace :rails_rbi do
34
35
  File.write(file_path, inspector.format(SorbetRails::RoutesRbiFormatter.new))
35
36
  end
36
37
 
37
- desc "Copy custom rbis for ActionController::Parameters, pluck_to_struct, etc."
38
+ desc "Copy custom rbis for typed_params, pluck_to_struct, etc."
38
39
  task custom: :environment do
39
40
  copy_bundled_rbi('type_assert.rbi')
40
- copy_bundled_rbi('parameters.rbi')
41
41
  copy_bundled_rbi('pluck_to_tstruct.rbi')
42
- copy_bundled_rbi('active_record_relation.rbi')
43
- copy_bundled_rbi('active_record_base.rbi')
44
42
  copy_bundled_rbi('typed_params.rbi')
43
+ copy_bundled_rbi('typed_enum.rbi')
44
+
45
+ # These files were previously bundled_rbi but are now generated so this
46
+ # is needed for backwards compatibility with anyone using `rails_rbi:custom`
47
+ Rake::Task['rails_rbi:active_record'].invoke
48
+ end
49
+
50
+ desc "Generate rbis for rails mailers"
51
+ task :active_record, [:root_dir] => :environment do |t, args|
52
+ formatter = SorbetRails::ActiveRecordRbiFormatter.new
53
+ FileUtils.mkdir_p(Rails.root.join("sorbet", "rails-rbi"))
54
+
55
+ file_path = Rails.root.join("sorbet", "rails-rbi", "active_record_base.rbi")
56
+ File.write(file_path, formatter.generate_active_record_base_rbi)
57
+
58
+ file_path = Rails.root.join("sorbet", "rails-rbi", "active_record_relation.rbi")
59
+ File.write(file_path, formatter.generate_active_record_relation_rbi)
45
60
  end
46
61
 
47
62
  desc "Generate rbis for rails models. Pass models name to regenerate rbi for only the given models."
@@ -62,11 +77,19 @@ namespace :rails_rbi do
62
77
  models_to_generate = models_to_generate - blacklisted_models
63
78
  end
64
79
 
65
- generated_rbis = generate_rbis_for_models(models_to_generate, all_models)
66
- generated_rbis.each do |model_name, contents|
67
- file_path = Rails.root.join("sorbet", "rails-rbi", "models", "#{model_name.underscore}.rbi")
68
- FileUtils.mkdir_p(File.dirname(file_path))
69
- File.write(file_path, contents)
80
+ available_class_names = Set.new(all_models.map { |c| c.name })
81
+ models_to_generate.each do |model_class|
82
+ model_class_name = model_class.to_s
83
+ begin
84
+ formatter = SorbetRails::ModelRbiFormatter.new(model_class, available_class_names)
85
+ file_path = Rails.root.join("sorbet", "rails-rbi", "models", "#{model_class_name.underscore}.rbi")
86
+ FileUtils.mkdir_p(File.dirname(file_path))
87
+ File.write(file_path, formatter.generate_rbi)
88
+ rescue StandardError, NotImplementedError => ex
89
+ puts "---"
90
+ puts "Error when handling model #{model_class_name}: #{ex}"
91
+ nil
92
+ end
70
93
  end
71
94
  end
72
95
 
@@ -130,21 +153,6 @@ namespace :rails_rbi do
130
153
  end
131
154
  end
132
155
 
133
- def generate_rbis_for_models(model_classes, available_classes)
134
- available_class_names = Set.new(available_classes.map { |c| c.name })
135
- formatted = model_classes.map do |model_class|
136
- begin
137
- formatter = SorbetRails::ModelRbiFormatter.new(model_class, available_class_names)
138
- [model_class.name, formatter.generate_rbi]
139
- rescue StandardError, NotImplementedError => ex
140
- puts "---"
141
- puts "Error when handling model #{model_class.name}: #{ex}"
142
- nil
143
- end
144
- end
145
- Hash[formatted.compact] # remove models with errors
146
- end
147
-
148
156
  def blacklisted_models
149
157
  blacklisted_models = []
150
158
  blacklisted_models << ApplicationRecord if defined?(ApplicationRecord)
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = %q{sorbet-rails}
3
- s.version = "0.6.2"
3
+ s.version = "0.7.0"
4
4
  s.date = %q{2019-04-18}
5
5
  s.summary = %q{Set of tools to make Sorbet work with Rails seamlessly.}
6
6
  s.authors = ["Chan Zuckerberg Initiative"]
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
17
17
 
18
18
  s.add_dependency 'parlour', '~> 2.0'
19
19
  s.add_dependency 'sorbet-runtime', '>= 0.5'
20
- s.add_dependency 'sorbet-coerce', '>= 0.2.4'
20
+ s.add_dependency 'sorbet-coerce', '>= 0.2.6'
21
21
  s.add_dependency 'method_source', '>= 0.9.2'
22
22
  s.add_dependency 'parser', '>= 2.7'
23
23
 
@@ -0,0 +1,24 @@
1
+ require 'rails_helper'
2
+ require 'sorbet-rails/active_record_rbi_formatter'
3
+
4
+ RSpec.describe SorbetRails::ActiveRecordRbiFormatter do
5
+ describe 'generate_active_record_base_rbi' do
6
+ it 'returns the expected rbi' do
7
+ formatter = SorbetRails::ActiveRecordRbiFormatter.new
8
+ expect_match_file(
9
+ formatter.generate_active_record_base_rbi,
10
+ 'expected_active_record_base.rbi'
11
+ )
12
+ end
13
+ end
14
+
15
+ describe 'generate_active_record_relation_rbi' do
16
+ it 'returns the expected rbi' do
17
+ formatter = SorbetRails::ActiveRecordRbiFormatter.new
18
+ expect_match_file(
19
+ formatter.generate_active_record_relation_rbi,
20
+ 'expected_active_record_relation.rbi'
21
+ )
22
+ end
23
+ end
24
+ end
@@ -51,7 +51,7 @@ def create_lib
51
51
  model_class_rbi.create_method(
52
52
  'mythicals',
53
53
  class_method: true,
54
- return_type: "T::Array[#{@model_class.name}]",
54
+ return_type: "T::Array[#{model_class_name}]",
55
55
  )
56
56
  end
57
57
  end
@@ -83,11 +83,16 @@ def create_models
83
83
  # simulate when belongs_to is optional by default, but it is enforced at the DB level
84
84
  belongs_to :wizard, optional: true
85
85
 
86
+ # habtm enforced at the DB level
87
+ has_and_belongs_to_many :spells
88
+
86
89
  enum book_type: {
87
90
  unclassified: 0,
88
91
  biology: 1,
89
92
  dark_art: 999,
90
93
  }
94
+
95
+ scope :recent, -> { where('created_at > ?', 1.month.ago) }
91
96
  end
92
97
  RUBY
93
98
 
@@ -129,6 +134,8 @@ def create_models
129
134
  file "app/models/wizard.rb", <<~RUBY
130
135
  class Wizard < ApplicationRecord
131
136
  validates :name, length: { minimum: 5 }, presence: true
137
+ # simulate conditional validation
138
+ validates :parent_email, presence: true, if: :Slytherin?
132
139
 
133
140
  typed_enum house: {
134
141
  Gryffindor: 0,
@@ -146,6 +153,7 @@ def create_models
146
153
  "Pomona Sprout": 2,
147
154
  "Filius Flitwick": 3,
148
155
  "Hagrid": 4,
156
+ "Alastor 'Mad-Eye' Moody": 5,
149
157
  }
150
158
 
151
159
  typed_enum broom: {
@@ -174,6 +182,8 @@ def create_models
174
182
 
175
183
  has_one :wand
176
184
  has_many :spell_books
185
+ # habtm which is optional at the db level
186
+ has_and_belongs_to_many :subjects
177
187
 
178
188
  # simulate when belongs_to is optional by default
179
189
  belongs_to :school, optional: true
@@ -212,8 +222,35 @@ def create_models
212
222
 
213
223
  file "app/models/school.rb", <<~RUBY
214
224
  class School < ApplicationRecord
225
+ has_one :headmaster
226
+ validates :headmaster, presence: true
215
227
  end
216
228
  RUBY
229
+
230
+ file "app/models/subject.rb", <<~RUBY
231
+ class Subject < ApplicationRecord
232
+ # habtm which is optional at the db level
233
+ has_and_belongs_to_many :wizards
234
+ end
235
+ RUBY
236
+
237
+ file "app/models/spell.rb", <<~RUBY
238
+ class Spell < ApplicationRecord
239
+ # habtm enforced at the DB level
240
+ has_and_belongs_to_many :spell_books
241
+ end
242
+ RUBY
243
+
244
+ file "app/models/headmaster.rb", <<~RUBY
245
+ class Headmaster < ApplicationRecord
246
+ belongs_to :school, required: false
247
+ belongs_to :wizard, optional: true
248
+
249
+ validates :school, presence: true
250
+ validates :wizard_id, presence: true
251
+ end
252
+ RUBY
253
+
217
254
  end
218
255
 
219
256
  def create_migrations
@@ -328,6 +365,58 @@ def create_migrations
328
365
  end
329
366
  end
330
367
  RUBY
368
+
369
+ file "db/migrate/20190620000010_add_subject.rb", <<~RUBY
370
+ class AddSubject < #{migration_superclass}
371
+ def change
372
+ create_table :subjects do |t|
373
+ t.string :name
374
+ end
375
+ end
376
+ end
377
+ RUBY
378
+
379
+ file "db/migrate/20190620000011_add_subjects_wizards.rb", <<~RUBY
380
+ class AddSubjectsWizards < #{migration_superclass}
381
+ def change
382
+ create_join_table :subjects, :wizards, column_options: { null: true } do |t|
383
+ t.index [:subject_id, :wizard_id]
384
+ end
385
+ end
386
+ end
387
+ RUBY
388
+
389
+ file "db/migrate/20190620000012_add_spell.rb", <<~RUBY
390
+ class AddSpell < #{migration_superclass}
391
+ def change
392
+ create_table :spells do |t|
393
+ t.string :name
394
+ end
395
+ end
396
+ end
397
+ RUBY
398
+
399
+ file "db/migrate/20190620000013_add_spells_spell_books.rb", <<~RUBY
400
+ class AddSpellsSpellBooks < #{migration_superclass}
401
+ def change
402
+ create_join_table :spells, :spell_books do |t|
403
+ t.index [:spell_id, :spell_book_id]
404
+ end
405
+ end
406
+ end
407
+ RUBY
408
+
409
+ file "db/migrate/20190620000014_create_headmasters.rb", <<~RUBY
410
+ class CreateHeadmasters < #{migration_superclass}
411
+ def change
412
+ create_table :headmasters do |t|
413
+ t.references :school
414
+ t.references :wizard
415
+ end
416
+ end
417
+ end
418
+ RUBY
419
+
331
420
  end
332
421
 
333
422
  def create_mailers
@@ -391,11 +480,6 @@ def create_jobs
391
480
  end
392
481
 
393
482
  def add_sorbet_test_files
394
- file "typed-override.yaml", <<~YAML
395
- true:
396
- - ./sorbet_test_cases.rb
397
- YAML
398
-
399
483
  copy_file "./sorbet_test_cases.rb", "sorbet_test_cases.rb"
400
484
  end
401
485
 
@@ -1,4 +1,4 @@
1
- # typed: false
1
+ # typed: true
2
2
  require 'sorbet-runtime'
3
3
 
4
4
  wand = Wand.first!
@@ -27,32 +27,21 @@ 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
-
31
- # -- model relation
32
- # default
33
- T.assert_type!(Wizard.all, Wizard::ActiveRecord_Relation)
34
-
35
- # custom scope
36
- T.assert_type!(Wizard.recent, Wizard::ActiveRecord_Relation)
37
-
38
- # enum scope
39
- T.assert_type!(Wizard.Gryffindor, Wizard::ActiveRecord_Relation)
40
-
41
- # ActiveRecord Querying
42
- T.assert_type!(Wizard.Gryffindor.recent, Wizard::ActiveRecord_Relation)
43
- T.assert_type!(Wizard.Gryffindor.recent.unscoped, Wizard::ActiveRecord_Relation)
44
- T.assert_type!(Wizard.where(id: 1), Wizard::ActiveRecord_Relation)
45
- T.assert_type!(Wizard.where(id: 1).recent, Wizard::ActiveRecord_Relation)
46
- T.assert_type!(Wizard.where.not(id: 1), Wizard::ActiveRecord_Relation)
47
- T.assert_type!(Wizard.preload(:spell_books), Wizard::ActiveRecord_Relation)
48
- T.assert_type!(Wizard.eager_load(:spell_books), Wizard::ActiveRecord_Relation)
49
- T.assert_type!(Wizard.order(:id), Wizard::ActiveRecord_Relation)
30
+ T.assert_type!(wizard.spell_book_ids, T::Array[Integer])
50
31
 
51
32
  # Finder methods -- Model
52
33
  T.assert_type!(Wizard.exists?(name: 'Test'), T::Boolean)
53
34
  T.assert_type!(Wizard.find(wizard.id), Wizard)
54
35
  T.assert_type!(Wizard.first!, Wizard)
55
36
  T.assert_type!(Wizard.first, T.nilable(Wizard))
37
+ T.assert_type!(Wizard.second!, Wizard)
38
+ T.assert_type!(Wizard.second, T.nilable(Wizard))
39
+ T.assert_type!(Wizard.third!, Wizard)
40
+ T.assert_type!(Wizard.third, T.nilable(Wizard))
41
+ T.assert_type!(Wizard.third_to_last!, Wizard)
42
+ T.assert_type!(Wizard.third_to_last, T.nilable(Wizard))
43
+ T.assert_type!(Wizard.second_to_last!, Wizard)
44
+ T.assert_type!(Wizard.second_to_last, T.nilable(Wizard))
56
45
  T.assert_type!(Wizard.last!, Wizard)
57
46
  T.assert_type!(Wizard.last, T.nilable(Wizard))
58
47
  T.assert_type!(Wizard.first_n(5), T::Array[Wizard])
@@ -61,12 +50,54 @@ T.assert_type!(Wizard.find_by(name: 'Harry Potter'), T.nilable(Wizard))
61
50
  T.assert_type!(Wizard.find_by!(name: 'Harry Potter'), Wizard)
62
51
  T.assert_type!(Wizard.find_by_id(wizard.id), T.nilable(Wizard))
63
52
  T.assert_type!(Wizard.find_by_id!(wizard.id), Wizard)
53
+ T.assert_type!(Wizard.find_or_initialize_by(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
54
+ T.assert_type!(Wizard.find_or_create_by(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
55
+ T.assert_type!(Wizard.find_or_create_by!(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
56
+ T.assert_type!(Wizard.new { |w| T.assert_type!(w, Wizard) }, Wizard)
57
+ T.assert_type!(Wizard.create(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
58
+ T.assert_type!(Wizard.create!(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
59
+ T.assert_type!(Wizard.first_or_create(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
60
+ T.assert_type!(Wizard.first_or_create!(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
61
+ T.assert_type!(Wizard.first_or_initialize { |w| T.assert_type!(w, Wizard) }, Wizard)
62
+ Wizard.find_each { |w| T.assert_type!(w, Wizard) }
63
+ T.assert_type!(Wizard.find_each, T::Enumerator[Wizard])
64
+ Wizard.find_in_batches { |w| T.assert_type!(w, T::Array[Wizard]) }
65
+ T.assert_type!(Wizard.find_in_batches, T::Enumerator[T::Array[Wizard]])
66
+ Wizard.in_batches { |w| T.assert_type!(w, Wizard::ActiveRecord_Relation) }
67
+ T.assert_type!(Wizard.in_batches, ActiveRecord::Batches::BatchEnumerator)
68
+ # T.assert_type!(Wizard.destroy_all, T::Array[Wizard]) # Ignored until we add support
69
+ T.assert_type!(Wizard.any?, T::Boolean)
70
+ T.assert_type!(Wizard.many?, T::Boolean)
71
+ T.assert_type!(Wizard.none?, T::Boolean)
72
+ T.assert_type!(Wizard.one?, T::Boolean)
73
+ # T.assert_type!(Wizard.update_all(name: 'Harry Potter'), Integer) # Ignored until we add support
74
+ # T.assert_type!(Wizard.delete_all, Integer) # Ignored until we add support
75
+ # Query methods
76
+ T.assert_type!(Wizard.all, Wizard::ActiveRecord_Relation)
77
+ T.assert_type!(Wizard.recent, Wizard::ActiveRecord_Relation) # Named scope
78
+ T.assert_type!(Wizard.Gryffindor, Wizard::ActiveRecord_Relation) # Enum scope
79
+ T.assert_type!(Wizard.Gryffindor.recent, Wizard::ActiveRecord_Relation)
80
+ T.assert_type!(Wizard.Gryffindor.recent.unscoped, Wizard::ActiveRecord_Relation)
81
+ T.assert_type!(Wizard.where(id: 1), Wizard::ActiveRecord_Relation)
82
+ T.assert_type!(Wizard.where(id: 1).recent, Wizard::ActiveRecord_Relation)
83
+ T.assert_type!(Wizard.where.not(id: 1), Wizard::ActiveRecord_Relation)
84
+ T.assert_type!(Wizard.preload(:spell_books), Wizard::ActiveRecord_Relation)
85
+ T.assert_type!(Wizard.eager_load(:spell_books), Wizard::ActiveRecord_Relation)
86
+ T.assert_type!(Wizard.order(:id), Wizard::ActiveRecord_Relation)
64
87
 
65
88
  # Finder methods -- ActiveRecord::Relation
66
89
  T.assert_type!(Wizard.all.exists?(name: 'Harry Potter'), T::Boolean)
67
90
  T.assert_type!(Wizard.all.find(wizard.id), Wizard)
68
91
  T.assert_type!(Wizard.all.first!, Wizard)
69
92
  T.assert_type!(Wizard.all.first, T.nilable(Wizard))
93
+ T.assert_type!(Wizard.all.second!, Wizard)
94
+ T.assert_type!(Wizard.all.second, T.nilable(Wizard))
95
+ T.assert_type!(Wizard.all.third!, Wizard)
96
+ T.assert_type!(Wizard.all.third, T.nilable(Wizard))
97
+ T.assert_type!(Wizard.all.third_to_last!, Wizard)
98
+ T.assert_type!(Wizard.all.third_to_last, T.nilable(Wizard))
99
+ T.assert_type!(Wizard.all.second_to_last!, Wizard)
100
+ T.assert_type!(Wizard.all.second_to_last, T.nilable(Wizard))
70
101
  T.assert_type!(Wizard.all.last!, Wizard)
71
102
  T.assert_type!(Wizard.all.last, T.nilable(Wizard))
72
103
  T.assert_type!(Wizard.all.first_n(5), T::Array[Wizard])
@@ -75,6 +106,46 @@ T.assert_type!(Wizard.all.find_by(name: 'Harry Potter'), T.nilable(Wizard))
75
106
  T.assert_type!(Wizard.all.find_by!(name: 'Harry Potter'), Wizard)
76
107
  T.assert_type!(Wizard.all.find_by_id(wizard.id), T.nilable(Wizard))
77
108
  T.assert_type!(Wizard.all.find_by_id!(wizard.id), Wizard)
109
+ T.assert_type!(Wizard.all.find_or_initialize_by(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
110
+ T.assert_type!(Wizard.all.find_or_create_by(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
111
+ T.assert_type!(Wizard.all.find_or_create_by!(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
112
+ T.assert_type!(Wizard.all.new { |w| T.assert_type!(w, Wizard) }, Wizard)
113
+ T.assert_type!(Wizard.all.build { |w| T.assert_type!(w, Wizard) }, Wizard)
114
+ T.assert_type!(Wizard.all.create(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
115
+ T.assert_type!(Wizard.all.create!(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
116
+ T.assert_type!(Wizard.all.first_or_create(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
117
+ T.assert_type!(Wizard.all.first_or_create!(name: 'Harry Potter') { |w| T.assert_type!(w, Wizard) }, Wizard)
118
+ T.assert_type!(Wizard.all.first_or_initialize { |w| T.assert_type!(w, Wizard) }, Wizard)
119
+ Wizard.all.find_each { |w| T.assert_type!(w, Wizard) }
120
+ T.assert_type!(Wizard.all.find_each, T::Enumerator[Wizard])
121
+ Wizard.all.find_in_batches { |w| T.assert_type!(w, T::Array[Wizard]) }
122
+ T.assert_type!(Wizard.all.find_in_batches, T::Enumerator[T::Array[Wizard]])
123
+ Wizard.all.in_batches { |w| T.assert_type!(w, Wizard::ActiveRecord_Relation) }
124
+ T.assert_type!(Wizard.all.in_batches, T::Enumerable[Wizard::ActiveRecord_Relation])
125
+ # T.assert_type!(Wizard.all.destroy_all, T::Array[Wizard]) # Ignored until we add support
126
+ T.assert_type!(Wizard.all.any?, T::Boolean)
127
+ T.assert_type!(Wizard.all.many?, T::Boolean)
128
+ T.assert_type!(Wizard.all.none?, T::Boolean)
129
+ T.assert_type!(Wizard.all.one?, T::Boolean)
130
+ # T.assert_type!(Wizard.all.update_all(name: 'Harry Potter'), Integer) # Ignored until we add support
131
+ # T.assert_type!(Wizard.all.delete_all, Integer) # Ignored until we add support
132
+ # Query methods
133
+ T.assert_type!(Wizard.all.all, Wizard::ActiveRecord_Relation)
134
+ T.assert_type!(Wizard.all.recent, Wizard::ActiveRecord_Relation) # Named scope
135
+ T.assert_type!(Wizard.all.Gryffindor, Wizard::ActiveRecord_Relation) # Enum scope
136
+ T.assert_type!(Wizard.all.Gryffindor.recent, Wizard::ActiveRecord_Relation)
137
+ T.assert_type!(Wizard.all.Gryffindor.recent.unscoped, Wizard::ActiveRecord_Relation)
138
+ T.assert_type!(Wizard.all.where(id: 1), Wizard::ActiveRecord_Relation)
139
+ T.assert_type!(Wizard.all.where(id: 1).recent, Wizard::ActiveRecord_Relation)
140
+ T.assert_type!(Wizard.all.where.not(id: 1), Wizard::ActiveRecord_Relation)
141
+ T.assert_type!(Wizard.all.preload(:spell_books), Wizard::ActiveRecord_Relation)
142
+ T.assert_type!(Wizard.all.eager_load(:spell_books), Wizard::ActiveRecord_Relation)
143
+ T.assert_type!(Wizard.all.order(:id), Wizard::ActiveRecord_Relation)
144
+ # Enumerable methods
145
+ Wizard.all.each { |w| T.assert_type!(w, Wizard) }
146
+ Wizard.all.map { |w| T.assert_type!(w, Wizard) }
147
+ T.assert_type!(Wizard.all.to_a, T::Array[Wizard])
148
+ T.assert_type!(Wizard.all.empty?, T::Boolean)
78
149
 
79
150
  # Finder methods -- CollectionProxy
80
151
  spell_book = wizard.spell_books.first!
@@ -82,79 +153,135 @@ spell_books = wizard.spell_books
82
153
  T.assert_type!(spell_books.exists?(name: 'Fantastic Beasts'), T::Boolean)
83
154
  T.assert_type!(spell_books.find(spell_book.id), SpellBook)
84
155
  T.assert_type!(spell_books.first!, SpellBook)
85
- # T.assert_type!(spell_books.first, T.nilable(SpellBook)) # TODO fix sig for 5.0
156
+ T.assert_type!(spell_books.first, T.nilable(SpellBook))
157
+ T.assert_type!(spell_books.second!, SpellBook)
158
+ T.assert_type!(spell_books.second, T.nilable(SpellBook))
159
+ T.assert_type!(spell_books.third!, SpellBook)
160
+ T.assert_type!(spell_books.third, T.nilable(SpellBook))
161
+ T.assert_type!(spell_books.third_to_last!, SpellBook)
162
+ T.assert_type!(spell_books.third_to_last, T.nilable(SpellBook))
163
+ T.assert_type!(spell_books.second_to_last!, SpellBook)
164
+ T.assert_type!(spell_books.second_to_last, T.nilable(SpellBook))
86
165
  T.assert_type!(spell_books.last!, SpellBook)
87
- # T.assert_type!(spell_books.last, T.nilable(SpellBook)) # TODO fix sig for 5.0
166
+ T.assert_type!(spell_books.last, T.nilable(SpellBook))
88
167
  T.assert_type!(spell_books.first_n(5), T::Array[SpellBook])
89
168
  T.assert_type!(spell_books.last_n(5), T::Array[SpellBook])
90
169
  T.assert_type!(spell_books.find_by(name: 'Fantastic Beasts'), T.nilable(SpellBook))
91
170
  T.assert_type!(spell_books.find_by!(name: 'Fantastic Beasts'), SpellBook)
92
171
  T.assert_type!(spell_books.find_by_id(spell_book.id), T.nilable(SpellBook))
93
172
  T.assert_type!(spell_books.find_by_id!(spell_book.id), SpellBook)
94
- # CollectionProxy query also typed correctly!
173
+ T.assert_type!(spell_books.find_or_initialize_by(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
174
+ T.assert_type!(spell_books.find_or_create_by(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
175
+ T.assert_type!(spell_books.find_or_create_by!(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
176
+ T.assert_type!(spell_books.new { |s| T.assert_type!(s, SpellBook) }, SpellBook)
177
+ T.assert_type!(spell_books.build { |s| T.assert_type!(s, SpellBook) }, SpellBook)
178
+ T.assert_type!(spell_books.create(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
179
+ T.assert_type!(spell_books.create!(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
180
+ T.assert_type!(spell_books.first_or_create(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
181
+ T.assert_type!(spell_books.first_or_create!(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
182
+ T.assert_type!(spell_books.first_or_initialize { |s| T.assert_type!(s, SpellBook) }, SpellBook)
183
+ spell_books.find_each { |s| T.assert_type!(s, SpellBook) }
184
+ T.assert_type!(spell_books.find_each, T::Enumerator[SpellBook])
185
+ spell_books.find_in_batches { |s| T.assert_type!(s, T::Array[SpellBook]) }
186
+ T.assert_type!(spell_books.find_in_batches, T::Enumerator[T::Array[SpellBook]])
187
+ spell_books.in_batches { |s| T.assert_type!(s, SpellBook::ActiveRecord_AssociationRelation) }
188
+ T.assert_type!(spell_books.in_batches, T::Enumerable[SpellBook::ActiveRecord_AssociationRelation])
189
+ # T.assert_type!(spell_books.destroy_all, T::Array[SpellBook]) # Ignored until we add support
190
+ T.assert_type!(spell_books.any?, T::Boolean)
191
+ T.assert_type!(spell_books.many?, T::Boolean)
192
+ T.assert_type!(spell_books.none?, T::Boolean)
193
+ T.assert_type!(spell_books.one?, T::Boolean)
194
+ # T.assert_type!(spell_books.update_all(name: 'Fantastic Beasts'), Integer) # Ignored until we add support
195
+ # T.assert_type!(spell_books.delete_all, Integer) # Ignored until we add support
196
+ # Query methods
197
+ T.assert_type!(spell_books.all, SpellBook::ActiveRecord_AssociationRelation)
198
+ T.assert_type!(spell_books.recent, SpellBook::ActiveRecord_AssociationRelation) # Named scope
199
+ T.assert_type!(spell_books.unclassified, SpellBook::ActiveRecord_AssociationRelation) # Enum scope
200
+ T.assert_type!(spell_books.unclassified.recent, SpellBook::ActiveRecord_AssociationRelation)
201
+ T.assert_type!(spell_books.unclassified.recent.unscoped, SpellBook::ActiveRecord_Relation) # Turns back into relation
95
202
  T.assert_type!(spell_books.where(id: 1), SpellBook::ActiveRecord_AssociationRelation)
203
+ T.assert_type!(spell_books.where(id: 1).recent, SpellBook::ActiveRecord_AssociationRelation)
204
+ T.assert_type!(spell_books.where.not(id: 1), SpellBook::ActiveRecord_AssociationRelation)
96
205
  T.assert_type!(spell_books.preload(:wizard), SpellBook::ActiveRecord_AssociationRelation)
97
206
  T.assert_type!(spell_books.eager_load(:wizard), SpellBook::ActiveRecord_AssociationRelation)
98
207
  T.assert_type!(spell_books.order(:id), SpellBook::ActiveRecord_AssociationRelation)
99
- T.assert_type!(spell_books.where.not(id: 1), SpellBook::ActiveRecord_AssociationRelation)
100
- T.assert_type!(spell_books.biology, SpellBook::ActiveRecord_AssociationRelation)
208
+ # Enumerable methods
209
+ spell_books.each { |s| T.assert_type!(s, SpellBook) }
210
+ spell_books.map { |s| T.assert_type!(s, SpellBook) }
211
+ T.assert_type!(spell_books.to_a, T::Array[SpellBook])
212
+ T.assert_type!(spell_books.empty?, T::Boolean)
213
+ # Push methods
214
+ T.assert_type!(spell_books << spell_book, SpellBook::ActiveRecord_Associations_CollectionProxy)
215
+ T.assert_type!(spell_books << [spell_book], SpellBook::ActiveRecord_Associations_CollectionProxy)
216
+ T.assert_type!(spell_books.append(spell_book), SpellBook::ActiveRecord_Associations_CollectionProxy)
217
+ T.assert_type!(spell_books.append([spell_book]), SpellBook::ActiveRecord_Associations_CollectionProxy)
218
+ T.assert_type!(spell_books.push(spell_book), SpellBook::ActiveRecord_Associations_CollectionProxy)
219
+ T.assert_type!(spell_books.push([spell_book]), SpellBook::ActiveRecord_Associations_CollectionProxy)
220
+ # 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
221
+ # 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
222
 
102
223
  # finder methods -- AssociationRelation
103
- spell_books_query = spell_books.where(id: 1)
224
+ spell_books_query = spell_books.where(wizard_id: wizard.id)
104
225
  T.assert_type!(spell_books_query.exists?(name: 'Fantastic Beasts'), T::Boolean)
105
226
  T.assert_type!(spell_books_query.find(spell_book.id), SpellBook)
106
227
  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
228
+ T.assert_type!(spell_books_query.first, T.nilable(SpellBook))
229
+ T.assert_type!(spell_books_query.second!, SpellBook)
230
+ T.assert_type!(spell_books_query.second, T.nilable(SpellBook))
231
+ T.assert_type!(spell_books_query.third!, SpellBook)
232
+ T.assert_type!(spell_books_query.third, T.nilable(SpellBook))
233
+ T.assert_type!(spell_books_query.third_to_last!, SpellBook)
234
+ T.assert_type!(spell_books_query.third_to_last, T.nilable(SpellBook))
235
+ T.assert_type!(spell_books_query.second_to_last!, SpellBook)
236
+ T.assert_type!(spell_books_query.second_to_last, T.nilable(SpellBook))
108
237
  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
238
+ T.assert_type!(spell_books_query.last, T.nilable(SpellBook))
110
239
  T.assert_type!(spell_books_query.first_n(5), T::Array[SpellBook])
111
240
  T.assert_type!(spell_books_query.last_n(5), T::Array[SpellBook])
112
241
  T.assert_type!(spell_books_query.find_by(name: 'Fantastic Beasts'), T.nilable(SpellBook))
113
242
  T.assert_type!(spell_books_query.find_by!(name: 'Fantastic Beasts'), SpellBook)
114
243
  T.assert_type!(spell_books_query.find_by_id(spell_book.id), T.nilable(SpellBook))
115
244
  T.assert_type!(spell_books_query.find_by_id!(spell_book.id), SpellBook)
116
- # Query chaining
245
+ T.assert_type!(spell_books_query.find_or_initialize_by(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
246
+ T.assert_type!(spell_books_query.find_or_create_by(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
247
+ T.assert_type!(spell_books_query.find_or_create_by!(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook)
248
+ T.assert_type!(spell_books_query.new { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support
249
+ T.assert_type!(spell_books_query.build { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support # Ignored until we add support
250
+ T.assert_type!(spell_books_query.create(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support
251
+ T.assert_type!(spell_books_query.create!(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support
252
+ T.assert_type!(spell_books_query.first_or_create(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support
253
+ T.assert_type!(spell_books_query.first_or_create!(name: 'Fantastic Beasts') { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support
254
+ T.assert_type!(spell_books_query.first_or_initialize { |s| T.assert_type!(s, SpellBook) }, SpellBook) # Ignored until we add support
255
+ spell_books_query.find_each { |s| T.assert_type!(s, SpellBook) }
256
+ T.assert_type!(spell_books_query.find_each, T::Enumerator[SpellBook])
257
+ spell_books_query.find_in_batches { |s| T.assert_type!(s, T::Array[SpellBook]) }
258
+ T.assert_type!(spell_books_query.find_in_batches, T::Enumerator[T::Array[SpellBook]])
259
+ spell_books_query.in_batches { |s| T.assert_type!(s, SpellBook::ActiveRecord_AssociationRelation) }
260
+ T.assert_type!(spell_books_query.in_batches, T::Enumerable[SpellBook::ActiveRecord_AssociationRelation])
261
+ # T.assert_type!(spell_books_query.destroy_all, T::Array[SpellBook]) # Ignored until we add support
262
+ T.assert_type!(spell_books_query.any?, T::Boolean)
263
+ T.assert_type!(spell_books_query.many?, T::Boolean)
264
+ T.assert_type!(spell_books_query.none?, T::Boolean)
265
+ T.assert_type!(spell_books_query.one?, T::Boolean)
266
+ # T.assert_type!(spell_books_query.update_all(name: 'Fantastic Beasts'), Integer) # Ignored until we add support
267
+ # T.assert_type!(spell_books_query.delete_all, Integer) # Ignored until we add support
268
+ # Query methods
269
+ T.assert_type!(spell_books_query.all, SpellBook::ActiveRecord_AssociationRelation)
270
+ T.assert_type!(spell_books_query.recent, SpellBook::ActiveRecord_AssociationRelation) # Named scope
271
+ T.assert_type!(spell_books_query.unclassified, SpellBook::ActiveRecord_AssociationRelation) # Enum scope
272
+ T.assert_type!(spell_books_query.unclassified.recent, SpellBook::ActiveRecord_AssociationRelation)
273
+ T.assert_type!(spell_books_query.unclassified.recent.unscoped, SpellBook::ActiveRecord_Relation) # Turns back into relation
274
+ T.assert_type!(spell_books_query.where(id: 1), SpellBook::ActiveRecord_AssociationRelation)
275
+ T.assert_type!(spell_books_query.where(id: 1).recent, SpellBook::ActiveRecord_AssociationRelation)
276
+ T.assert_type!(spell_books_query.where.not(id: 1), SpellBook::ActiveRecord_AssociationRelation)
117
277
  T.assert_type!(spell_books_query.preload(:wizard), SpellBook::ActiveRecord_AssociationRelation)
118
278
  T.assert_type!(spell_books_query.eager_load(:wizard), SpellBook::ActiveRecord_AssociationRelation)
119
279
  T.assert_type!(spell_books_query.order(:id), SpellBook::ActiveRecord_AssociationRelation)
120
- T.assert_type!(spell_books_query.where.not(id: 1), SpellBook::ActiveRecord_AssociationRelation)
121
- 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
280
+ # Enumerable methods
281
+ spell_books_query.each { |s| T.assert_type!(s, SpellBook) }
282
+ spell_books_query.map { |s| T.assert_type!(s, SpellBook) }
283
+ T.assert_type!(spell_books_query.to_a, T::Array[SpellBook])
284
+ T.assert_type!(spell_books_query.empty?, T::Boolean)
158
285
 
159
286
  # Model columns
160
287
  T.assert_type!(wizard.id, Integer)
@@ -234,44 +361,6 @@ params = ActionController::Parameters.new({
234
361
  typed_params = TypedParams[MyActionParams].new.extract!(params)
235
362
  T.assert_type!(typed_params, MyActionParams)
236
363
 
237
- # -- require_typed
238
- T.assert_type!(
239
- params.require_typed(:age, TA[Integer].new),
240
- Integer,
241
- )
242
- T.assert_type!(
243
- params.require_typed(:name, TA[String].new),
244
- String,
245
- )
246
- info = params.require_typed(:info, TA[ActionController::Parameters].new)
247
- T.assert_type!(info, ActionController::Parameters)
248
- T.assert_type!(
249
- info.require_typed(:friends, TA[T::Array[String]].new),
250
- T::Array[String],
251
- )
252
- # -- fetch_typed
253
- T.assert_type!(
254
- params.fetch_typed(:age, TA[Integer].new),
255
- Integer,
256
- )
257
- T.assert_type!(
258
- params.fetch_typed(:name, TA[String].new),
259
- String,
260
- )
261
- T.assert_type!(
262
- params.fetch_typed(:nonexistence, TA[String].new, ''),
263
- String,
264
- )
265
- T.assert_type!(
266
- params.fetch_typed(:nonexistence, TA[T.nilable(String)].new, nil),
267
- T.nilable(String),
268
- )
269
- T.assert_type!(
270
- params.fetch_typed(:nonexistence, TA[T::Array[Integer]].new, []),
271
- T::Array[Integer],
272
- )
273
-
274
-
275
364
  # -- pluck to tstruct
276
365
  class WizardStruct < T::Struct
277
366
  const :name, String
@@ -288,23 +377,16 @@ Wizard.all.pluck_to_tstruct(TA[WizardStruct].new).each do |row|
288
377
  T.assert_type!(row, WizardStruct)
289
378
  end
290
379
 
291
-
292
380
  # -- GeneratedUrlHelpers
293
381
  class TestHelper
294
382
  include GeneratedUrlHelpers
295
-
296
- # need to implement this for the url
297
- def default_url_options
298
- {
299
- protocol: 'http',
300
- host: 'localhost',
301
- port: 3000,
302
- }
303
- end
304
-
305
- def test_url_helper
306
- T.assert_type!(test_index_path, String)
307
- T.assert_type!(test_index_url, String)
308
- end
309
383
  end
310
- TestHelper.new.test_url_helper
384
+
385
+ T.assert_type!(TestHelper.new.test_index_path, String)
386
+ # need to set this config for _url methods
387
+ Rails.application.routes.default_url_options = {
388
+ protocol: 'http',
389
+ host: 'localhost',
390
+ port: 3000,
391
+ }
392
+ T.assert_type!(TestHelper.new.test_index_url, String)