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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/README.md +48 -17
- data/lib/bundled_rbi/parameters.rbi +50 -0
- data/lib/sorbet-rails.rb +1 -0
- data/lib/sorbet-rails/gem_plugins/friendly_id_plugin.rb +1 -1
- data/lib/sorbet-rails/gem_plugins/kaminari_plugin.rb +1 -1
- data/lib/sorbet-rails/gem_plugins/pg_search_plugin.rb +1 -1
- data/lib/sorbet-rails/mailer_rbi_formatter.rb +2 -2
- data/lib/sorbet-rails/model_plugins/active_record_assoc.rb +1 -1
- data/lib/sorbet-rails/model_plugins/active_record_attribute.rb +1 -1
- data/lib/sorbet-rails/model_plugins/active_record_enum.rb +1 -1
- data/lib/sorbet-rails/model_plugins/active_record_finder_methods.rb +1 -1
- data/lib/sorbet-rails/model_plugins/active_record_named_scope.rb +1 -1
- data/lib/sorbet-rails/model_plugins/active_record_querying.rb +1 -1
- data/lib/sorbet-rails/model_plugins/active_relation_where_not.rb +1 -1
- data/lib/sorbet-rails/model_plugins/active_storage_methods.rb +1 -1
- data/lib/sorbet-rails/model_plugins/base.rb +1 -1
- data/lib/sorbet-rails/model_plugins/custom_finder_methods.rb +1 -1
- data/lib/sorbet-rails/model_plugins/enumerable_collections.rb +1 -1
- data/lib/sorbet-rails/model_plugins/plugins.rb +0 -1
- data/lib/sorbet-rails/model_rbi_formatter.rb +5 -3
- data/lib/sorbet-rails/{model_plugins → rails_mixins}/active_record_overrides.rb +0 -0
- data/lib/sorbet-rails/{custom_finder_methods.rb → rails_mixins/custom_finder_methods.rb} +1 -1
- data/lib/sorbet-rails/rails_mixins/custom_params_methods.rb +46 -0
- data/lib/sorbet-rails/railtie.rb +8 -1
- data/lib/sorbet-rails/routes_rbi_formatter.rb +1 -2
- data/lib/sorbet-rails/tasks/rails_rbi.rake +22 -0
- data/lib/sorbet-rails/type_assert/type_assert.rb +18 -0
- data/lib/sorbet-rails/type_assert/type_assert_impl.rb +26 -0
- data/lib/sorbet-rails/type_assert/type_assert_interface.rb +16 -0
- data/sorbet-rails.gemspec +2 -2
- data/spec/custom_finder_methods_spec.rb +5 -0
- data/spec/custom_params_methods_spec.rb +138 -0
- data/spec/generators/sorbet_test_cases.rb +49 -0
- data/spec/model_rbi_formatter_spec.rb +10 -3
- data/spec/sorbet_spec.rb +1 -5
- data/spec/support/v4.2/Gemfile.lock +3 -3
- data/spec/support/v4.2/sorbet_test_cases.rb +49 -0
- data/spec/support/v5.0/Gemfile.lock +3 -3
- data/spec/support/v5.0/sorbet_test_cases.rb +49 -0
- data/spec/support/v5.1/Gemfile.lock +3 -3
- data/spec/support/v5.1/sorbet_test_cases.rb +49 -0
- data/spec/support/v5.2/Gemfile.lock +3 -3
- data/spec/support/v5.2/sorbet_test_cases.rb +49 -0
- data/spec/support/v6.0/Gemfile.lock +3 -3
- data/spec/support/v6.0/sorbet_test_cases.rb +49 -0
- data/spec/test_data/v4.2/expected_helpers.rbi +1 -1
- data/spec/test_data/v4.2/expected_helpers_with_application_and_devise_helpers.rbi +1 -1
- data/spec/test_data/v4.2/expected_potion.rbi +3 -3
- data/spec/test_data/v4.2/expected_spell_book.rbi +3 -3
- data/spec/test_data/v4.2/expected_wand.rbi +3 -3
- data/spec/test_data/v4.2/expected_wizard.rbi +3 -3
- data/spec/test_data/v4.2/expected_wizard_wo_spellbook.rbi +3 -3
- data/spec/test_data/v5.0/expected_helpers.rbi +1 -1
- data/spec/test_data/v5.0/expected_helpers_with_application_and_devise_helpers.rbi +1 -1
- data/spec/test_data/v5.0/expected_internal_metadata.rbi +3 -3
- data/spec/test_data/v5.0/expected_potion.rbi +3 -3
- data/spec/test_data/v5.0/expected_schema_migration.rbi +3 -3
- data/spec/test_data/v5.0/expected_spell_book.rbi +3 -3
- data/spec/test_data/v5.0/expected_wand.rbi +3 -3
- data/spec/test_data/v5.0/expected_wizard.rbi +3 -3
- data/spec/test_data/v5.0/expected_wizard_wo_spellbook.rbi +3 -3
- data/spec/test_data/v5.1/expected_helpers.rbi +1 -1
- data/spec/test_data/v5.1/expected_helpers_with_application_and_devise_helpers.rbi +1 -1
- data/spec/test_data/v5.1/expected_internal_metadata.rbi +3 -3
- data/spec/test_data/v5.1/expected_potion.rbi +3 -3
- data/spec/test_data/v5.1/expected_schema_migration.rbi +3 -3
- data/spec/test_data/v5.1/expected_spell_book.rbi +3 -3
- data/spec/test_data/v5.1/expected_wand.rbi +3 -3
- data/spec/test_data/v5.1/expected_wizard.rbi +3 -3
- data/spec/test_data/v5.1/expected_wizard_wo_spellbook.rbi +3 -3
- data/spec/test_data/v5.2/expected_attachment.rbi +3 -3
- data/spec/test_data/v5.2/expected_blob.rbi +3 -3
- data/spec/test_data/v5.2/expected_helpers.rbi +1 -1
- data/spec/test_data/v5.2/expected_helpers_with_application_and_devise_helpers.rbi +1 -1
- data/spec/test_data/v5.2/expected_internal_metadata.rbi +3 -3
- data/spec/test_data/v5.2/expected_potion.rbi +3 -3
- data/spec/test_data/v5.2/expected_schema_migration.rbi +3 -3
- data/spec/test_data/v5.2/expected_spell_book.rbi +3 -3
- data/spec/test_data/v5.2/expected_wand.rbi +3 -3
- data/spec/test_data/v5.2/expected_wizard.rbi +3 -3
- data/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi +3 -3
- data/spec/test_data/v6.0/expected_attachment.rbi +3 -3
- data/spec/test_data/v6.0/expected_blob.rbi +3 -3
- data/spec/test_data/v6.0/expected_helpers.rbi +1 -1
- data/spec/test_data/v6.0/expected_helpers_with_application_and_devise_helpers.rbi +1 -1
- data/spec/test_data/v6.0/expected_internal_metadata.rbi +3 -3
- data/spec/test_data/v6.0/expected_potion.rbi +3 -3
- data/spec/test_data/v6.0/expected_schema_migration.rbi +3 -3
- data/spec/test_data/v6.0/expected_spell_book.rbi +3 -3
- data/spec/test_data/v6.0/expected_wand.rbi +3 -3
- data/spec/test_data/v6.0/expected_wizard.rbi +3 -3
- data/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi +3 -3
- metadata +12 -33
- data/spec/test_data/v5.2-no-sorbet/expected_attachment.rbi +0 -725
- data/spec/test_data/v5.2-no-sorbet/expected_blob.rbi +0 -755
- data/spec/test_data/v5.2-no-sorbet/expected_helpers.rbi +0 -22
- data/spec/test_data/v5.2-no-sorbet/expected_helpers_with_application_and_devise_helpers.rbi +0 -29
- data/spec/test_data/v5.2-no-sorbet/expected_internal_metadata.rbi +0 -749
- data/spec/test_data/v5.2-no-sorbet/expected_no_routes.rbi +0 -4
- data/spec/test_data/v5.2-no-sorbet/expected_potion.rbi +0 -708
- data/spec/test_data/v5.2-no-sorbet/expected_routes.rbi +0 -54
- data/spec/test_data/v5.2-no-sorbet/expected_schema_migration.rbi +0 -722
- data/spec/test_data/v5.2-no-sorbet/expected_spell_book.rbi +0 -822
- data/spec/test_data/v5.2-no-sorbet/expected_srb_tc_output.txt +0 -1
- data/spec/test_data/v5.2-no-sorbet/expected_wand.rbi +0 -933
- data/spec/test_data/v5.2-no-sorbet/expected_wizard.rbi +0 -885
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4532cfd7b6aa106f5b870cd2b6013acd7d72644985a29cb398f0b25959b2d4b0
|
4
|
+
data.tar.gz: 39329d64e2eaee0afd14a180404897c1ec0b1601a8b33bdedb6e3d3e9f12695e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 693c741863b4edf77cbb843b9cf030e91f098ad6291be63d2a365e845c99701b32f14a1c35658a0375aeeec25f9fcff702d0045fc36904704c3f49dd9640fca9
|
7
|
+
data.tar.gz: 9985e82caf4debbbac6512698190c2f787d0e8bb51ae2853bf17a3828ee4f1921330ad86829615f3f4e503d992617f43c5b6bd1c11d32f62cb75f1d03fd267e9
|
data/.travis.yml
CHANGED
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,
|
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
|
-
##
|
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 {
|
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
|
data/lib/sorbet-rails.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
class FriendlyIdPlugin < SorbetRails::ModelPlugins::Base
|
3
|
-
sig {
|
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 {
|
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 {
|
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
|
|
@@ -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 {
|
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 {
|
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 {
|
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 {
|
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 {
|
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 {
|
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 {
|
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 {
|
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 {
|
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 {
|
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 {
|
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 {
|
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 }
|
File without changes
|
@@ -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
|