sorbet-rails 0.5.4 → 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/README.md +48 -17
  4. data/lib/bundled_rbi/parameters.rbi +50 -0
  5. data/lib/sorbet-rails.rb +1 -0
  6. data/lib/sorbet-rails/gem_plugins/friendly_id_plugin.rb +1 -1
  7. data/lib/sorbet-rails/gem_plugins/kaminari_plugin.rb +1 -1
  8. data/lib/sorbet-rails/gem_plugins/pg_search_plugin.rb +1 -1
  9. data/lib/sorbet-rails/mailer_rbi_formatter.rb +2 -2
  10. data/lib/sorbet-rails/model_plugins/active_record_assoc.rb +1 -1
  11. data/lib/sorbet-rails/model_plugins/active_record_attribute.rb +1 -1
  12. data/lib/sorbet-rails/model_plugins/active_record_enum.rb +1 -1
  13. data/lib/sorbet-rails/model_plugins/active_record_finder_methods.rb +1 -1
  14. data/lib/sorbet-rails/model_plugins/active_record_named_scope.rb +1 -1
  15. data/lib/sorbet-rails/model_plugins/active_record_querying.rb +1 -1
  16. data/lib/sorbet-rails/model_plugins/active_relation_where_not.rb +1 -1
  17. data/lib/sorbet-rails/model_plugins/active_storage_methods.rb +1 -1
  18. data/lib/sorbet-rails/model_plugins/base.rb +1 -1
  19. data/lib/sorbet-rails/model_plugins/custom_finder_methods.rb +1 -1
  20. data/lib/sorbet-rails/model_plugins/enumerable_collections.rb +1 -1
  21. data/lib/sorbet-rails/model_plugins/plugins.rb +0 -1
  22. data/lib/sorbet-rails/model_rbi_formatter.rb +5 -3
  23. data/lib/sorbet-rails/{model_plugins → rails_mixins}/active_record_overrides.rb +0 -0
  24. data/lib/sorbet-rails/{custom_finder_methods.rb → rails_mixins/custom_finder_methods.rb} +1 -1
  25. data/lib/sorbet-rails/rails_mixins/custom_params_methods.rb +46 -0
  26. data/lib/sorbet-rails/railtie.rb +8 -1
  27. data/lib/sorbet-rails/routes_rbi_formatter.rb +1 -2
  28. data/lib/sorbet-rails/tasks/rails_rbi.rake +22 -0
  29. data/lib/sorbet-rails/type_assert/type_assert.rb +18 -0
  30. data/lib/sorbet-rails/type_assert/type_assert_impl.rb +26 -0
  31. data/lib/sorbet-rails/type_assert/type_assert_interface.rb +16 -0
  32. data/sorbet-rails.gemspec +2 -2
  33. data/spec/custom_finder_methods_spec.rb +5 -0
  34. data/spec/custom_params_methods_spec.rb +138 -0
  35. data/spec/generators/sorbet_test_cases.rb +49 -0
  36. data/spec/model_rbi_formatter_spec.rb +10 -3
  37. data/spec/sorbet_spec.rb +1 -5
  38. data/spec/support/v4.2/Gemfile.lock +3 -3
  39. data/spec/support/v4.2/sorbet_test_cases.rb +49 -0
  40. data/spec/support/v5.0/Gemfile.lock +3 -3
  41. data/spec/support/v5.0/sorbet_test_cases.rb +49 -0
  42. data/spec/support/v5.1/Gemfile.lock +3 -3
  43. data/spec/support/v5.1/sorbet_test_cases.rb +49 -0
  44. data/spec/support/v5.2/Gemfile.lock +3 -3
  45. data/spec/support/v5.2/sorbet_test_cases.rb +49 -0
  46. data/spec/support/v6.0/Gemfile.lock +3 -3
  47. data/spec/support/v6.0/sorbet_test_cases.rb +49 -0
  48. data/spec/test_data/v4.2/expected_helpers.rbi +1 -1
  49. data/spec/test_data/v4.2/expected_helpers_with_application_and_devise_helpers.rbi +1 -1
  50. data/spec/test_data/v4.2/expected_potion.rbi +3 -3
  51. data/spec/test_data/v4.2/expected_spell_book.rbi +3 -3
  52. data/spec/test_data/v4.2/expected_wand.rbi +3 -3
  53. data/spec/test_data/v4.2/expected_wizard.rbi +3 -3
  54. data/spec/test_data/v4.2/expected_wizard_wo_spellbook.rbi +3 -3
  55. data/spec/test_data/v5.0/expected_helpers.rbi +1 -1
  56. data/spec/test_data/v5.0/expected_helpers_with_application_and_devise_helpers.rbi +1 -1
  57. data/spec/test_data/v5.0/expected_internal_metadata.rbi +3 -3
  58. data/spec/test_data/v5.0/expected_potion.rbi +3 -3
  59. data/spec/test_data/v5.0/expected_schema_migration.rbi +3 -3
  60. data/spec/test_data/v5.0/expected_spell_book.rbi +3 -3
  61. data/spec/test_data/v5.0/expected_wand.rbi +3 -3
  62. data/spec/test_data/v5.0/expected_wizard.rbi +3 -3
  63. data/spec/test_data/v5.0/expected_wizard_wo_spellbook.rbi +3 -3
  64. data/spec/test_data/v5.1/expected_helpers.rbi +1 -1
  65. data/spec/test_data/v5.1/expected_helpers_with_application_and_devise_helpers.rbi +1 -1
  66. data/spec/test_data/v5.1/expected_internal_metadata.rbi +3 -3
  67. data/spec/test_data/v5.1/expected_potion.rbi +3 -3
  68. data/spec/test_data/v5.1/expected_schema_migration.rbi +3 -3
  69. data/spec/test_data/v5.1/expected_spell_book.rbi +3 -3
  70. data/spec/test_data/v5.1/expected_wand.rbi +3 -3
  71. data/spec/test_data/v5.1/expected_wizard.rbi +3 -3
  72. data/spec/test_data/v5.1/expected_wizard_wo_spellbook.rbi +3 -3
  73. data/spec/test_data/v5.2/expected_attachment.rbi +3 -3
  74. data/spec/test_data/v5.2/expected_blob.rbi +3 -3
  75. data/spec/test_data/v5.2/expected_helpers.rbi +1 -1
  76. data/spec/test_data/v5.2/expected_helpers_with_application_and_devise_helpers.rbi +1 -1
  77. data/spec/test_data/v5.2/expected_internal_metadata.rbi +3 -3
  78. data/spec/test_data/v5.2/expected_potion.rbi +3 -3
  79. data/spec/test_data/v5.2/expected_schema_migration.rbi +3 -3
  80. data/spec/test_data/v5.2/expected_spell_book.rbi +3 -3
  81. data/spec/test_data/v5.2/expected_wand.rbi +3 -3
  82. data/spec/test_data/v5.2/expected_wizard.rbi +3 -3
  83. data/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi +3 -3
  84. data/spec/test_data/v6.0/expected_attachment.rbi +3 -3
  85. data/spec/test_data/v6.0/expected_blob.rbi +3 -3
  86. data/spec/test_data/v6.0/expected_helpers.rbi +1 -1
  87. data/spec/test_data/v6.0/expected_helpers_with_application_and_devise_helpers.rbi +1 -1
  88. data/spec/test_data/v6.0/expected_internal_metadata.rbi +3 -3
  89. data/spec/test_data/v6.0/expected_potion.rbi +3 -3
  90. data/spec/test_data/v6.0/expected_schema_migration.rbi +3 -3
  91. data/spec/test_data/v6.0/expected_spell_book.rbi +3 -3
  92. data/spec/test_data/v6.0/expected_wand.rbi +3 -3
  93. data/spec/test_data/v6.0/expected_wizard.rbi +3 -3
  94. data/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi +3 -3
  95. metadata +12 -33
  96. data/spec/test_data/v5.2-no-sorbet/expected_attachment.rbi +0 -725
  97. data/spec/test_data/v5.2-no-sorbet/expected_blob.rbi +0 -755
  98. data/spec/test_data/v5.2-no-sorbet/expected_helpers.rbi +0 -22
  99. data/spec/test_data/v5.2-no-sorbet/expected_helpers_with_application_and_devise_helpers.rbi +0 -29
  100. data/spec/test_data/v5.2-no-sorbet/expected_internal_metadata.rbi +0 -749
  101. data/spec/test_data/v5.2-no-sorbet/expected_no_routes.rbi +0 -4
  102. data/spec/test_data/v5.2-no-sorbet/expected_potion.rbi +0 -708
  103. data/spec/test_data/v5.2-no-sorbet/expected_routes.rbi +0 -54
  104. data/spec/test_data/v5.2-no-sorbet/expected_schema_migration.rbi +0 -722
  105. data/spec/test_data/v5.2-no-sorbet/expected_spell_book.rbi +0 -822
  106. data/spec/test_data/v5.2-no-sorbet/expected_srb_tc_output.txt +0 -1
  107. data/spec/test_data/v5.2-no-sorbet/expected_wand.rbi +0 -933
  108. data/spec/test_data/v5.2-no-sorbet/expected_wizard.rbi +0 -885
  109. data/spec/test_data/v5.2-no-sorbet/expected_wizard_wo_spellbook.rbi +0 -885
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6b43d7a27b379e20892375b314afd08e4897ad6e0b20167b1a366de3121d0470
4
- data.tar.gz: f6817dea5503132acc030da42ce68149675192c98536b8c795d8705a0e42649d
3
+ metadata.gz: 4532cfd7b6aa106f5b870cd2b6013acd7d72644985a29cb398f0b25959b2d4b0
4
+ data.tar.gz: 39329d64e2eaee0afd14a180404897c1ec0b1601a8b33bdedb6e3d3e9f12695e
5
5
  SHA512:
6
- metadata.gz: 15251522124262b9c7aab57915d2cc5bc18e0807ccf27e2ea47e0d17173473a5d8a5a09ac4ea41e899de47a7972456ae060ef981e811e5f22095309c79d89b27
7
- data.tar.gz: 7178e09505141a408617d2513f9da84ee8868edf5c808c3bca0ba293dbec4bb3cbbbe1362ad8b0af2f75f20862de4f95b67ddf6b1365a6d10111598bd9779b75
6
+ metadata.gz: 693c741863b4edf77cbb843b9cf030e91f098ad6291be63d2a365e845c99701b32f14a1c35658a0375aeeec25f9fcff702d0045fc36904704c3f49dd9640fca9
7
+ data.tar.gz: 9985e82caf4debbbac6512698190c2f787d0e8bb51ae2853bf17a3828ee4f1921330ad86829615f3f4e503d992617f43c5b6bd1c11d32f62cb75f1d03fd267e9
@@ -17,7 +17,7 @@ rvm:
17
17
  matrix:
18
18
  include:
19
19
  - rvm: 2.5
20
- env: RAILS_VERSION=5.2 SORBET_VERSION=0.4.4602
20
+ env: RAILS_VERSION=5.2 SORBET_VERSION=0.4.4755
21
21
  exclude:
22
22
  - rvm: 2.3
23
23
  env: RAILS_VERSION=6.0
data/README.md CHANGED
@@ -25,12 +25,13 @@ gem 'sorbet-rails'
25
25
  ❯ bundle install
26
26
  ```
27
27
 
28
- 3. Generate RBI files for your routes, models, and helpers:
28
+ 3. Generate RBI files for your routes, models, etc
29
29
  ```sh
30
30
  ❯ rake rails_rbi:routes
31
31
  ❯ rake rails_rbi:models
32
32
  ❯ rake rails_rbi:helpers
33
33
  ❯ rake rails_rbi:mailers
34
+ ❯ rake rails_rbi:params
34
35
 
35
36
  # or run them all at once
36
37
  ❯ rake rails_rbi:all
@@ -43,18 +44,8 @@ gem 'sorbet-rails'
43
44
  ```
44
45
  Because we've generated RBI files for routes, models, and helpers, a lot more files should be typecheckable now. Many methods in `hidden.rbi` may be removed because they are now typed.
45
46
 
46
- ## RBI Files
47
+ ## Type-checking Rails code
47
48
 
48
- ### ActiveRecord
49
-
50
- There is an ActiveRecord RBI file that we vendor with this gem. Sorbet picks up these vendored RBI files automatically. (Please make sure you are running the latest version.)
51
-
52
- ### Routes
53
-
54
- This Rake task generates an RBI file defining `_path` and `_url` methods for all named routes in `routes.rb`:
55
- ```sh
56
- ❯ rake rails_rbi:routes
57
- ```
58
49
  ### Models
59
50
 
60
51
  This Rake task generates RBI files for all models in the Rails application (all descendants of `ActiveRecord::Base`):
@@ -75,6 +66,45 @@ The generation task currently creates the following signatures:
75
66
 
76
67
  It is possible to add custom RBI generation logic for your custom module or gems via the plugin system. Check out the [plugins section](#extending-model-generation-task-with-custom-plugins) below if you are interested.
77
68
 
69
+ ### Controllers
70
+ ```sh
71
+ ❯ rake rails_rbi:params
72
+ ```
73
+
74
+ `sorbet-rails` adds methods to extract typed parameters from `params`, namely `require_typed` and `fetch_typed`. They are direct replacement of `require` and `fetch` that return typed object. They have the same API their counterpart, with an addition of the parameter's type, which can be any type understood by `sorbet`
75
+
76
+ This is the conversion in essence:
77
+ ```
78
+ params.require(:key) -> params.require_typed(:key, TA[Type].new)
79
+ params.fetch(:key) -> params.fetch_typed(:key, TA[Type].new)
80
+ params.fetch(:key, default_value) -> params.fetch_typed(:key, TA[Type].new, default_value)
81
+ params[:key] -> params.fetch_typed(:key, TA[T.nilable(Type)].new, nil)
82
+ ```
83
+
84
+ For example:
85
+ ```
86
+ # require_typed
87
+ key = params.require_typed(:key, TA[String].new)
88
+ T.reveal_type(key) # String
89
+
90
+ # fetch_typed
91
+ key = params.fetch_typed(:key, TA[T.nilable(String)].new) # raises error if params doesn't have :key
92
+ T.reveal_type(key) # T.nilable(String)
93
+
94
+ key = params.fetch_typed(:key, TA[T.nilable(String)].new, nil) # returns nil when key doesn't have :key
95
+ T.reveal_type(key) # T.nilable(String)
96
+ ```
97
+ The parameters are type-checked both statically and at runtime.
98
+
99
+ Note: The API `TA[...].new` may seems verbose, but necessary to support this feature. Ideally, the API can be simply `require_typed(:key, Type)`. However, `sorbet` [doesn't support](http://github.com/sorbet/sorbet/issues/62) defining a method that accept a type and return an instance of the type. The library provides a wrapper `TA` (stands for TypeAssert) in order to achieve the behavior. If it is by `sorbet` in the future, it will be easy to codemod to remove the `TA[...].new` part from your code.
100
+
101
+ ### Routes
102
+
103
+ This Rake task generates an RBI file defining `_path` and `_url` methods for all named routes in `routes.rb`:
104
+ ```sh
105
+ ❯ rake rails_rbi:routes
106
+ ```
107
+
78
108
  ### Helpers
79
109
 
80
110
  This Rake task generates a `helpers.rbi` file that includes a basic module definition which includes the `Kernel` module and `ActionView::Helpers`, to allow for some basic Ruby methods to be used in helpers without Sorbet complaining.
@@ -90,6 +120,7 @@ If you have additional modules that are included in all your helpers and you wan
90
120
  SorbetRails.configure do |config|
91
121
  config.extra_helper_includes = ['ApplicationHelper', 'Devise::Controllers::Helpers']
92
122
  end
123
+ ```
93
124
 
94
125
  ### Mailers
95
126
 
@@ -195,7 +226,7 @@ Model.unscoped.scoping do … end
195
226
 
196
227
  `sorbet-rails` support a customizable plugin system that you can use to generate additional RBI for each model. This will be useful to generate RBI for methods dynamically added by gems or private concerns. If you write plugins for public gems, please feel free to contribute it to this repo.
197
228
 
198
- ### Defining a Custom `ModelPlugin`
229
+ ### Defining a Custom `ModelPlugin`
199
230
 
200
231
  A custom plugin should be a subclass of `SorbetRails::ModelPlugins::Base`. Each plugin would implement a `generate(root)` method that generate additional rbi for the model.
201
232
 
@@ -203,7 +234,7 @@ At a high level, here is the structure of a plugin:
203
234
  ```ruby
204
235
  # -- lib/my_custom_plugin.rb
205
236
  class MyCustomPlugin < SorbetRails::ModelPlugins::Base
206
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
237
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
207
238
  def generate(root)
208
239
  # TODO: implement the generation logic
209
240
  # You can use @model_class and @available_classes here
@@ -226,17 +257,17 @@ At a high level, you'd usually want to create a model-scoped module for your met
226
257
  # here we re-create the model class!
227
258
  model_class_rbi = root.create_class(self.model_class_name)
228
259
  model_class_rbi.create_extend(custom_module_name)
229
-
260
+
230
261
  # then create custom methods, constants, etc. for this module.
231
262
  custom_module_rbi.create_method(...)
232
-
263
+
233
264
  # this is allowed but not recommended, because it limit the ability to override the method.
234
265
  model_class_rbi.create_method(...)
235
266
  end
236
267
  ```
237
268
  Notice that we re-create `model_class_rbi` here. Parlour's [ConflictResolver](https://github.com/AaronC81/parlour/wiki/Internals#overall-flow) will merge the classes or modules with the same name together to generate 1 beautiful RBI file. It'll also flag and skip if any method is created multiple times with conflict signatures. Check-out useful predefined module names & helper methods in [model_utils](https://github.com/chanzuckerberg/sorbet-rails/blob/master/lib/sorbet-rails/model_utils.rb).
238
269
 
239
- It is also allowed to put methods into a model class directly. However, it is not recommended because it'll be harder to override the method. `sorbet` will enforce that the overriding method match the signature generated. It also makes the generated RBI file less modularized.
270
+ It is also allowed to put methods into a model class directly. However, it is not recommended because it'll be harder to override the method. `sorbet` will enforce that the overriding method match the signature generated. It also makes the generated RBI file less modularized.
240
271
 
241
272
  However, sometimes this is required to make `sorbet` recognize the signature. This is the case for class methods added by `ActiveRecord::Concerns`. Because `ActiveSupport::Concern` class methods will be inserted to the class directly, you need to also put the sig in the model class rbi directly.
242
273
 
@@ -0,0 +1,50 @@
1
+ # typed: strong
2
+
3
+ module ITypeAssert
4
+ extend T::Sig
5
+ extend T::Generic
6
+
7
+ Elem = type_member(:out)
8
+
9
+ abstract!
10
+
11
+ sig { abstract.params(val: T.untyped).returns(Elem) }
12
+ def assert(val); end
13
+ end
14
+
15
+ module TypeAssertImpl; end
16
+
17
+ class TA
18
+ extend T::Sig
19
+ extend T::Generic
20
+ include ITypeAssert
21
+ extend TypeAssertImpl
22
+
23
+ Elem = type_member
24
+
25
+ sig { override.params(val: T.untyped).returns(Elem) }
26
+ def assert(val); end
27
+ end
28
+
29
+ module SorbetRails::CustomParamsMethods
30
+ extend T::Sig
31
+
32
+ sig {
33
+ type_parameters(:U).
34
+ params(key: Symbol, ta: ITypeAssert[T.type_parameter(:U)]).
35
+ returns(T.type_parameter(:U))
36
+ }
37
+ def require_typed(key, ta); end
38
+
39
+ # Note: when default value is a hash, it'll be converted into an ActionController::Parameters
40
+ sig {
41
+ type_parameters(:U).
42
+ params(
43
+ key: Symbol,
44
+ ta: ITypeAssert[T.type_parameter(:U)],
45
+ args: T.untyped,
46
+ ).
47
+ returns(T.type_parameter(:U))
48
+ }
49
+ def fetch_typed(key, ta, *args); end
50
+ end
@@ -3,5 +3,6 @@ module SorbetRails
3
3
  if defined?(Rails)
4
4
  require 'sorbet-rails/railtie'
5
5
  require 'sorbet-rails/model_rbi_formatter'
6
+ require 'sorbet-rails/type_assert/type_assert'
6
7
  end
7
8
  end
@@ -1,6 +1,6 @@
1
1
  # typed: strict
2
2
  class FriendlyIdPlugin < SorbetRails::ModelPlugins::Base
3
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
3
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
4
4
  def generate(root)
5
5
  return unless @model_class.singleton_class.included_modules.include?(::FriendlyId)
6
6
 
@@ -2,7 +2,7 @@
2
2
  class KaminariPlugin < SorbetRails::ModelPlugins::Base
3
3
  # Kaminari generates a dynamic `page` method on ActiveRecord relations.
4
4
  # https://github.com/kaminari/kaminari/blob/c5186f5d9b7f23299d115408e62047447fd3189d/kaminari-activerecord/lib/kaminari/activerecord/active_record_model_extension.rb#L15
5
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
5
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
6
6
  def generate(root)
7
7
  return unless @model_class.include?(::Kaminari::ActiveRecordModelExtension)
8
8
 
@@ -2,7 +2,7 @@
2
2
  class PgSearchPlugin < SorbetRails::ModelPlugins::Base
3
3
  # If you include PgSearch::Model, the class implicitly gets methods from
4
4
  # PgSearch::Model::ClassMethods.
5
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
5
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
6
6
  def generate(root)
7
7
  return unless @model_class.include?(::PgSearch::Model)
8
8
 
@@ -33,6 +33,6 @@ class SorbetRails::MailerRbiFormatter
33
33
  end
34
34
  end
35
35
 
36
- @parlour.rbi + "\n"
36
+ @parlour.rbi
37
37
  end
38
- end
38
+ end
@@ -7,7 +7,7 @@ class SorbetRails::ModelPlugins::ActiveRecordAssoc < SorbetRails::ModelPlugins::
7
7
  @columns_hash = @model_class.table_exists? ? @model_class.columns_hash : {}
8
8
  end
9
9
 
10
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
10
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
11
11
  def generate(root)
12
12
  return unless @model_class.reflections.length > 0
13
13
 
@@ -2,7 +2,7 @@
2
2
  require ('sorbet-rails/model_plugins/base')
3
3
  class SorbetRails::ModelPlugins::ActiveRecordAttribute < SorbetRails::ModelPlugins::Base
4
4
 
5
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
5
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
6
6
  def generate(root)
7
7
  columns_hash = @model_class.table_exists? ? @model_class.columns_hash : {}
8
8
  return unless columns_hash.size > 0
@@ -3,7 +3,7 @@ require ('sorbet-rails/model_plugins/base')
3
3
  require("sorbet-rails/utils")
4
4
  class SorbetRails::ModelPlugins::ActiveRecordEnum < SorbetRails::ModelPlugins::Base
5
5
 
6
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
6
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
7
7
  def generate(root)
8
8
  return unless model_class.defined_enums.size > 0
9
9
 
@@ -2,7 +2,7 @@
2
2
  require ('sorbet-rails/model_plugins/base')
3
3
  class SorbetRails::ModelPlugins::ActiveRecordFinderMethods < SorbetRails::ModelPlugins::Base
4
4
 
5
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
5
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
6
6
  def generate(root)
7
7
  model_class_rbi = root.create_class(self.model_class_name)
8
8
  create_finder_methods_for(model_class_rbi, class_method: true)
@@ -3,7 +3,7 @@ require ('sorbet-rails/model_plugins/base')
3
3
  require("sorbet-rails/utils")
4
4
  class SorbetRails::ModelPlugins::ActiveRecordNamedScope < SorbetRails::ModelPlugins::Base
5
5
 
6
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
6
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
7
7
  def generate(root)
8
8
  model_class_rbi = root.create_class(self.model_class_name)
9
9
 
@@ -2,7 +2,7 @@
2
2
  require ('sorbet-rails/model_plugins/base')
3
3
  class SorbetRails::ModelPlugins::ActiveRecordQuerying < SorbetRails::ModelPlugins::Base
4
4
 
5
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
5
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
6
6
  def generate(root)
7
7
  # All is a named scope that most method from ActiveRecord::Querying delegate to
8
8
  # rails/activerecord/lib/active_record/querying.rb:21
@@ -2,7 +2,7 @@
2
2
  require ('sorbet-rails/model_plugins/base')
3
3
  class SorbetRails::ModelPlugins::ActiveRelationWhereNot < SorbetRails::ModelPlugins::Base
4
4
 
5
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
5
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
6
6
  def generate(root)
7
7
  where_not_module_name = self.model_module_name("ActiveRelation_WhereNot")
8
8
  where_not_module_rbi = root.create_module(where_not_module_name)
@@ -6,7 +6,7 @@ class SorbetRails::ModelPlugins::ActiveStorageMethods < SorbetRails::ModelPlugin
6
6
  super
7
7
  end
8
8
 
9
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
9
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
10
10
  def generate(root)
11
11
  # Check that ActiveStorage the attachment_reflections method exists
12
12
  # It was added in 6.0, so it isn't available for 5.2.
@@ -12,7 +12,7 @@ module SorbetRails::ModelPlugins
12
12
  # convenient rename
13
13
  Parameter = ::Parlour::RbiGenerator::Parameter
14
14
 
15
- sig { implementation.returns(T.class_of(ActiveRecord::Base)) }
15
+ sig { override.returns(T.class_of(ActiveRecord::Base)) }
16
16
  attr_reader :model_class
17
17
 
18
18
  sig { returns(T::Set[String]) }
@@ -2,7 +2,7 @@
2
2
  require ('sorbet-rails/model_plugins/base')
3
3
  class SorbetRails::ModelPlugins::CustomFinderMethods < SorbetRails::ModelPlugins::Base
4
4
 
5
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
5
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
6
6
  def generate(root)
7
7
  model_class_rbi = root.create_class(self.model_class_name)
8
8
  model_relation_class_rbi = root.create_class(self.model_relation_class_name)
@@ -2,7 +2,7 @@
2
2
  require ('sorbet-rails/model_plugins/base')
3
3
  class SorbetRails::ModelPlugins::EnumerableCollections < SorbetRails::ModelPlugins::Base
4
4
 
5
- sig { implementation.params(root: Parlour::RbiGenerator::Namespace).void }
5
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
6
6
  def generate(root)
7
7
  # model relation & association proxy are enumerable
8
8
  # we need to implement "each" in these methods so that they work
@@ -9,7 +9,6 @@ require('sorbet-rails/model_plugins/active_record_assoc')
9
9
  require('sorbet-rails/model_plugins/active_record_finder_methods')
10
10
  require('sorbet-rails/model_plugins/custom_finder_methods')
11
11
  require('sorbet-rails/model_plugins/enumerable_collections')
12
- require('sorbet-rails/model_plugins/active_record_overrides')
13
12
  require('sorbet-rails/model_plugins/active_storage_methods')
14
13
 
15
14
  module SorbetRails::ModelPlugins
@@ -8,7 +8,7 @@ class SorbetRails::ModelRbiFormatter
8
8
  extend SorbetRails::ModelPlugins
9
9
  include SorbetRails::ModelUtils
10
10
 
11
- sig { implementation.returns(T.class_of(ActiveRecord::Base)) }
11
+ sig { override.returns(T.class_of(ActiveRecord::Base)) }
12
12
  attr_reader :model_class
13
13
 
14
14
  sig { returns(T::Set[String]) }
@@ -56,12 +56,14 @@ class SorbetRails::ModelRbiFormatter
56
56
  nil
57
57
  end
58
58
 
59
- <<~MESSAGE
59
+ rbi = <<~MESSAGE
60
60
  # This is an autogenerated file for dynamic methods in #{self.model_class_name}
61
61
  # Please rerun rake rails_rbi:models[#{self.model_class_name}] to regenerate.
62
62
 
63
- #{generator.rbi}
64
63
  MESSAGE
64
+
65
+ rbi += generator.rbi
66
+ return rbi
65
67
  end
66
68
 
67
69
  sig { params(root: Parlour::RbiGenerator::Namespace).void }
@@ -2,7 +2,7 @@
2
2
  module SorbetRails
3
3
  module CustomFinderMethods
4
4
  def find_n(*ids)
5
- find(ids)
5
+ find(*ids)
6
6
  end
7
7
 
8
8
  def first_n(n)
@@ -0,0 +1,46 @@
1
+ # typed: false
2
+ require 'sorbet-runtime'
3
+
4
+ module SorbetRails::CustomParamsMethods
5
+ include Kernel
6
+ extend T::Sig
7
+ extend T::Helpers
8
+
9
+ # methods exists on ActionController::Parameter
10
+ # def require(key); super; end
11
+ # def fetch(key, *args); super; end
12
+
13
+ sig {
14
+ type_parameters(:U).
15
+ params(key: Symbol, ta: ITypeAssert[T.type_parameter(:U)]).
16
+ returns(T.type_parameter(:U))
17
+ }
18
+ def require_typed(key, ta)
19
+ val = require(key)
20
+ ta.assert(val)
21
+ rescue TypeError
22
+ raise ActionController::BadRequest.new(
23
+ "Expected parameter #{key} to be an instance of type #{ta.get_type}, got `#{val}`"
24
+ )
25
+ end
26
+
27
+ # Note: when default value is a hash, it'll be converted into an ActionController::Parameters
28
+ sig {
29
+ type_parameters(:U).
30
+ params(
31
+ key: Symbol,
32
+ ta: ITypeAssert[T.type_parameter(:U)],
33
+ args: T.untyped,
34
+ ).
35
+ returns(T.type_parameter(:U))
36
+ }
37
+ def fetch_typed(key, ta, *args)
38
+ val = fetch(key, *args)
39
+ ta.assert(val)
40
+ rescue TypeError
41
+ raise ActionController::BadRequest.new(
42
+ "Expected parameter #{key} to be an instance of type T.nilable(#{ta.get_type}),
43
+ got `#{val}`".squish!
44
+ )
45
+ end
46
+ end