sorbet-rails 0.5.9.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitattributes +4 -0
- data/.travis.yml +3 -3
- data/README.md +129 -52
- data/lib/bundled_rbi/active_record_base.rbi +83 -0
- data/lib/bundled_rbi/active_record_relation.rbi +43 -0
- data/lib/bundled_rbi/pluck_to_tstruct.rbi +0 -1
- data/lib/bundled_rbi/typed_params.rbi +9 -0
- data/lib/sorbet-rails.rb +1 -0
- data/lib/sorbet-rails/config.rb +0 -1
- data/lib/sorbet-rails/gem_plugins/elastic_search_plugin.rb +1 -1
- data/lib/sorbet-rails/gem_plugins/friendly_id_plugin.rb +1 -1
- data/lib/sorbet-rails/model_plugins/active_record_assoc.rb +3 -3
- data/lib/sorbet-rails/model_plugins/active_record_attribute.rb +85 -17
- data/lib/sorbet-rails/model_plugins/active_record_enum.rb +0 -2
- data/lib/sorbet-rails/model_plugins/active_record_finder_methods.rb +49 -12
- data/lib/sorbet-rails/model_plugins/active_record_querying.rb +1 -1
- data/lib/sorbet-rails/model_plugins/active_storage_methods.rb +1 -1
- data/lib/sorbet-rails/model_plugins/plugins.rb +0 -3
- data/lib/sorbet-rails/rails_mixins/active_record_overrides.rb +156 -5
- data/lib/sorbet-rails/rails_mixins/generated_url_helpers.rb +16 -0
- data/lib/sorbet-rails/railtie.rb +2 -1
- data/lib/sorbet-rails/tasks/rails_rbi.rake +2 -0
- data/lib/sorbet-rails/type_assert/actionpack.rbi +4 -0
- data/lib/sorbet-rails/type_assert/type_assert.rb +1 -1
- data/lib/sorbet-rails/typed_params.rb +22 -0
- data/lib/sorbet-rails/utils.rb +5 -0
- data/sorbet-rails.gemspec +5 -3
- data/spec/generators/rails-template.rb +7 -3
- data/spec/generators/sorbet_test_cases.rb +46 -1
- data/spec/sorbet_spec.rb +3 -1
- data/spec/support/v5.0/Gemfile.lock +36 -23
- data/spec/support/v5.0/app/models/wizard.rb +6 -3
- data/spec/support/v5.0/db/migrate/20190620000001_create_wizards.rb +1 -0
- data/spec/support/v5.0/db/schema.rb +1 -0
- data/spec/support/v5.0/sorbet_test_cases.rb +46 -1
- data/spec/support/v5.1/Gemfile.lock +37 -24
- data/spec/support/v5.1/app/models/wizard.rb +6 -3
- data/spec/support/v5.1/db/migrate/20190620000001_create_wizards.rb +1 -0
- data/spec/support/v5.1/db/schema.rb +1 -0
- data/spec/support/v5.1/sorbet_test_cases.rb +46 -1
- data/spec/support/v5.2/Gemfile.lock +75 -62
- data/spec/support/v5.2/app/models/wizard.rb +6 -3
- data/spec/support/v5.2/db/migrate/20190620000001_create_wizards.rb +1 -0
- data/spec/support/v5.2/db/schema.rb +1 -0
- data/spec/support/v5.2/sorbet_test_cases.rb +46 -1
- data/spec/support/v6.0/Gemfile.lock +89 -76
- data/spec/support/v6.0/app/models/wizard.rb +6 -3
- data/spec/support/v6.0/db/migrate/20190620000001_create_wizards.rb +1 -0
- data/spec/support/v6.0/db/schema.rb +1 -0
- data/spec/support/v6.0/sorbet_test_cases.rb +46 -1
- data/spec/test_data/v5.0/expected_internal_metadata.rbi +33 -54
- data/spec/test_data/v5.0/expected_potion.rbi +33 -54
- data/spec/test_data/v5.0/expected_robe.rbi +33 -54
- data/spec/test_data/v5.0/expected_schema_migration.rbi +33 -54
- data/spec/test_data/v5.0/expected_school.rbi +33 -54
- data/spec/test_data/v5.0/expected_spell_book.rbi +46 -52
- data/spec/test_data/v5.0/expected_squib.rbi +42 -54
- data/spec/test_data/v5.0/expected_wand.rbi +47 -52
- data/spec/test_data/v5.0/expected_wizard.rbi +119 -56
- data/spec/test_data/v5.0/expected_wizard_wo_spellbook.rbi +119 -56
- data/spec/test_data/v5.1/expected_internal_metadata.rbi +33 -54
- data/spec/test_data/v5.1/expected_potion.rbi +33 -54
- data/spec/test_data/v5.1/expected_robe.rbi +33 -54
- data/spec/test_data/v5.1/expected_schema_migration.rbi +33 -54
- data/spec/test_data/v5.1/expected_school.rbi +33 -54
- data/spec/test_data/v5.1/expected_spell_book.rbi +46 -52
- data/spec/test_data/v5.1/expected_squib.rbi +42 -54
- data/spec/test_data/v5.1/expected_wand.rbi +47 -52
- data/spec/test_data/v5.1/expected_wizard.rbi +119 -56
- data/spec/test_data/v5.1/expected_wizard_wo_spellbook.rbi +119 -56
- data/spec/test_data/v5.2/expected_attachment.rbi +33 -54
- data/spec/test_data/v5.2/expected_blob.rbi +33 -54
- data/spec/test_data/v5.2/expected_internal_metadata.rbi +33 -54
- data/spec/test_data/v5.2/expected_potion.rbi +33 -54
- data/spec/test_data/v5.2/expected_robe.rbi +33 -54
- data/spec/test_data/v5.2/expected_schema_migration.rbi +33 -54
- data/spec/test_data/v5.2/expected_school.rbi +33 -54
- data/spec/test_data/v5.2/expected_spell_book.rbi +46 -52
- data/spec/test_data/v5.2/expected_squib.rbi +42 -54
- data/spec/test_data/v5.2/expected_wand.rbi +47 -52
- data/spec/test_data/v5.2/expected_wizard.rbi +119 -56
- data/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi +119 -56
- data/spec/test_data/v6.0/expected_attachment.rbi +33 -54
- data/spec/test_data/v6.0/expected_blob.rbi +33 -54
- data/spec/test_data/v6.0/expected_internal_metadata.rbi +33 -54
- data/spec/test_data/v6.0/expected_potion.rbi +33 -54
- data/spec/test_data/v6.0/expected_robe.rbi +33 -54
- data/spec/test_data/v6.0/expected_schema_migration.rbi +33 -54
- data/spec/test_data/v6.0/expected_school.rbi +33 -54
- data/spec/test_data/v6.0/expected_spell_book.rbi +46 -52
- data/spec/test_data/v6.0/expected_squib.rbi +42 -54
- data/spec/test_data/v6.0/expected_wand.rbi +47 -52
- data/spec/test_data/v6.0/expected_wizard.rbi +119 -56
- data/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi +119 -56
- data/spec/typed_enum_spec.rb +55 -0
- data/spec/typed_params_spec.rb +91 -0
- metadata +41 -4
- data/lib/sorbet-rails/model_plugins/active_record_factory_methods.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58c588bf2eb9eb09d2c4322d54436840452bb5a026e6ca4132df8e651aa26968
|
4
|
+
data.tar.gz: 11b54b70f6c86f5d97152fc5a7c9f0b48b021b8be03472fcb83014557353dc4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b88d51c0fae405a9249974746b250ad6ad2ce8ca09a5620c385105bffd0617dd2fbf5584a07a35abb35104c8242a1954156be9f98ddc456554803ad3b2a92ac
|
7
|
+
data.tar.gz: 98c2836dcbbb20798d0b57579eb7c3a07175bf8e5c58ed062cb652d2c7826bf62c1586cc4a9a5337702e88151862c8caf4cda81a21765f583a3c85caefc3d659
|
data/.gitattributes
ADDED
data/.travis.yml
CHANGED
@@ -8,15 +8,15 @@ env:
|
|
8
8
|
global:
|
9
9
|
secure: S3rpBSDgDQjhA11/80dZ4RUlBP3XLJWOgvcl1eySFdXqHCZGS5p8Fa97yEvZHWiPInUTNhdvyQ5LHlgzu1CCZ9+MOykpEgYo+1yIueriv9Ia5PUNFbwhRp2eBkluSUMPNPOxf15mUlgAGdScnssRL9zftYel29dw4yg+BQnnkLOqpnLO7wHTjouEmp7M8Y/1j0ScIZ0tZL1ovDq70Lst+TJKHm4jdBbwoNmILIwNBgnzZT1LdAuaXVHEmwLvy0GLvClewuSmToJ4jyjuJorCjyMhyoBLrutSuN4KaJcSlP/LVtH4ZCFkFDayDMiVcSyUE3asSnL3yxGL0K99lgwNk4D58WWic7N+0UKnGoiMQOHC9EIsQKaxfXMOpO+Cq5wYhgmFzPGF4iL6ZBNCehcc+ToBojprmJw/0Ev71OS2YGvu5SZpYco5AvJeR73IUA2K0rjUEeY3gXm60aIac09kQuuminN3hUkJ894YoA35B8IEU0uW2uL5n/vX2Y8SD6RV8csbKlhpJmphYYWQQOYjHuFoW4MVnnrFHq6YIUDQpi6/We3I4xH3kvfjIpSemrYOmfF4PPXCarWA7ryI9ytR7BloQ0NQH7hqp1hbKN86LAy8zanW08xNOrxI7VDdbtV1k6mf+wiV1W2Vo54HYEDIw0+jwmW/uKWatTyRo5AUsMc=
|
10
10
|
rvm:
|
11
|
-
- 2.3
|
12
11
|
- 2.4
|
13
12
|
- 2.5
|
14
13
|
- 2.6
|
14
|
+
- 2.7
|
15
15
|
- ruby-head
|
16
16
|
matrix:
|
17
17
|
include:
|
18
18
|
- rvm: 2.5
|
19
|
-
env: RAILS_VERSION=5.2 SORBET_VERSION=0.
|
19
|
+
env: RAILS_VERSION=5.2 SORBET_VERSION=0.5.5400
|
20
20
|
exclude:
|
21
21
|
- rvm: 2.3
|
22
22
|
env: RAILS_VERSION=6.0
|
@@ -28,7 +28,7 @@ before_install:
|
|
28
28
|
- gem install bundler -v 2.0.1 --no-doc
|
29
29
|
- gem install bundler -v 1.17.3 --no-doc
|
30
30
|
script:
|
31
|
-
-
|
31
|
+
- bundle exec srb tc
|
32
32
|
- "./spec/bin/run_spec.sh"
|
33
33
|
deploy:
|
34
34
|
provider: rubygems
|
data/README.md
CHANGED
@@ -7,9 +7,9 @@ A set of tools to make the [Sorbet](https://sorbet.org) typechecker work with Ru
|
|
7
7
|
|
8
8
|
This gem adds a few Rake tasks to generate Ruby Interface (RBI) files for dynamic methods generated by Rails. It also includes signatures for related Rails classes. The RBI files are added to a `sorbet/rails-rbi/` folder.
|
9
9
|
|
10
|
-
`sorbet-rails` supports Rails
|
10
|
+
`sorbet-rails` supports Rails 5+ or later.
|
11
11
|
|
12
|
-
**Notice**:
|
12
|
+
**Notice**: we no longer supports Rails 4.2. [Version 0.5.6](https://github.com/chanzuckerberg/sorbet-rails/releases/tag/v0.5.6) is the last version supporting Rails 4.2.
|
13
13
|
|
14
14
|
## Initial Setup
|
15
15
|
|
@@ -72,44 +72,120 @@ It is possible to add custom RBI generation logic for your custom module or gems
|
|
72
72
|
We also add following methods to make type-checking more easily:
|
73
73
|
- [`find_n`, `first_n`, `last_n`](https://github.com/chanzuckerberg/sorbet-rails#find-first-and-last)
|
74
74
|
- [`pluck_to_tstruct`](#pluck_to_tstruct-instead-of-pluck)
|
75
|
+
- [`typed_enum`](#enums)
|
75
76
|
|
76
|
-
|
77
|
-
|
78
|
-
|
77
|
+
#### `pluck_to_tstruct` instead of `pluck`
|
78
|
+
|
79
|
+
The [`pluck` method](https://apidock.com/rails/ActiveRecord/Calculations/pluck) in Rails is a performant way to query value without instantiating ActiveRecord objects. However, it doesn't have any type information: it doesn't have type information (or name) of the attribute plucked. Sorbet-rails provides `pluck_to_tstruct` method as a replacement that returns an array of `T::Struct` instead. The attributes plucked is based on props defined in the `T::Struct`
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
# -- API
|
83
|
+
Arel.pluck_to_tstruct(TA[ <TStructSubClass> ].new)
|
84
|
+
|
85
|
+
# -- example
|
86
|
+
class WizardStruct < T::Struct
|
87
|
+
const :name, String
|
88
|
+
const :house, T.nilable(String)
|
89
|
+
end
|
90
|
+
|
91
|
+
Wizard.pluck_to_tstruct(TA[WizardStruct].new) # T::Array[WizardStruct]
|
92
|
+
Wizard.all.pluck_to_tstruct(TA[WizardStruct].new) # T::Array[WizardStruct]
|
93
|
+
```
|
94
|
+
|
95
|
+
This method is based on [pluck_to_hash](https://github.com/girishso/pluck_to_hash) gem.
|
96
|
+
|
97
|
+
#### Enums
|
98
|
+
|
99
|
+
If you use [Rails `enum`](https://guides.rubyonrails.org/active_record_querying.html#enums), `sorbet-rails` will generate a corresponding `T::Enum`. It will also include getters, setters, and scope methods in the rbi file it generates.
|
100
|
+
|
101
|
+
ie.
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
enum house: {
|
105
|
+
Gryffindor: 0,
|
106
|
+
Hufflepuff: 1,
|
107
|
+
Ravenclaw: 2,
|
108
|
+
Slytherin: 3,
|
109
|
+
}
|
110
|
+
```
|
111
|
+
|
112
|
+
Will generate this enum:
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
class Wizard::House < T::Enum
|
116
|
+
enums do
|
117
|
+
Gryffindor = new('Gryffindor')
|
118
|
+
Hufflepuff = new('Hufflepuff')
|
119
|
+
Ravenclaw = new('Ravenclaw')
|
120
|
+
Slytherin = new('Slytherin')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
And these methods:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
sig { returns(T.nilable(String)) }
|
129
|
+
def house; end
|
130
|
+
|
131
|
+
sig { params(value: T.nilable(T.any(Integer, String, Symbol))).void }
|
132
|
+
def house=(value); end
|
133
|
+
|
134
|
+
sig { returns(T.nilable(Wizard::House)) }
|
135
|
+
def typed_house; end
|
136
|
+
|
137
|
+
sig { params(value: T.nilable(Wizard::House)).void }
|
138
|
+
def typed_house=(value); end
|
79
139
|
```
|
80
140
|
|
81
|
-
|
141
|
+
Alternatively, you can replace your call to `enum` with `typed_enum`. This will hide the Rails methods (`house`) from Sorbet static-check (they are still usable in un-checked files).
|
82
142
|
|
83
|
-
This is the conversion in essence:
|
84
143
|
```ruby
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
144
|
+
typed_enum house: {
|
145
|
+
Gryffindor: 0,
|
146
|
+
Hufflepuff: 1,
|
147
|
+
Ravenclaw: 2,
|
148
|
+
Slytherin: 3,
|
149
|
+
}
|
89
150
|
```
|
90
151
|
|
91
|
-
|
152
|
+
Generates only typed enum setter & getter:
|
153
|
+
|
92
154
|
```ruby
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
# fetch_typed
|
104
|
-
key = params.fetch_typed(:key, TA[T.nilable(String)].new) # raises error if params doesn't have :key
|
105
|
-
T.reveal_type(key) # T.nilable(String)
|
106
|
-
|
107
|
-
key = params.fetch_typed(:key, TA[T.nilable(String)].new, nil) # returns nil when key doesn't have :key
|
108
|
-
T.reveal_type(key) # T.nilable(String)
|
155
|
+
sig { returns(T.nilable(Wizard::House)) }
|
156
|
+
def typed_house; end
|
157
|
+
|
158
|
+
sig { params(value: T.nilable(Wizard::House)).void }
|
159
|
+
def typed_house=(value); end
|
160
|
+
```
|
161
|
+
|
162
|
+
### Controllers
|
163
|
+
```sh
|
164
|
+
❯ rake rails_rbi:custom
|
109
165
|
```
|
110
|
-
The parameters are type-checked both statically and at runtime.
|
111
166
|
|
112
|
-
|
167
|
+
`sorbet-rails` adds `TypedParams` to extact typed controller parameters.
|
168
|
+
|
169
|
+
TypedParams takes a parameter definition, which is a subclass of `T::Struct` and coerces the `params` object into an instance of that subclass using [sorbet-coerce](https://github.com/chanzuckerberg/sorbet-coerce):
|
170
|
+
```ruby
|
171
|
+
class MyCoolController < ApplicationController
|
172
|
+
class MyActionParams < T::Struct
|
173
|
+
const :id, T.nilable(Integer)
|
174
|
+
const :show, T.nilable(T::Boolean)
|
175
|
+
const :wands, T::Array[Integer]
|
176
|
+
end
|
177
|
+
sig { void }
|
178
|
+
def my_action
|
179
|
+
typed_params = TypedParams[MyActionParams].new.extract!(params)
|
180
|
+
# T.reveal_type(typed_params) => MyActionParams
|
181
|
+
# T.reveal_type(typed_params.show) => T.nilable(T::Boolean)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
```
|
185
|
+
If it fails to coerce the params into the right type, an `ActionController::BadRequest` exception will be raised with the coercion context for debugging.
|
186
|
+
|
187
|
+
Note: The API `TypedParams[...].new.extract!` may seem verbose, but necessary to support this feature. Ideally, the API can be simply `TypedParams.extract!(...)`. 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. If this feature is supported by `sorbet` in the future, it will be easy to codemod to be `TypedParams.extract(...)!` part from your code.
|
188
|
+
Note: [`require_typed` and `fetch_typed`](https://github.com/chanzuckerberg/sorbet-rails/blob/v0.5.9.1/README.md) are deprecated in favor of `TypedParams`.
|
113
189
|
|
114
190
|
### Routes
|
115
191
|
|
@@ -157,8 +233,11 @@ specific environment group (eg. `development` only).
|
|
157
233
|
|
158
234
|
- Relation class: Making the relations available at runtime (they are normally private constants, the gem makes them public)
|
159
235
|
- Examples: `User::ActiveRecord_Relation`, `User::ActiveRecord_AssociationRelation`
|
160
|
-
- Model:
|
161
|
-
-
|
236
|
+
- Model:
|
237
|
+
- `find_n`, `first_n`, `last_n`
|
238
|
+
- `pluck_to_tstruct`
|
239
|
+
- `typed_enum`
|
240
|
+
- Controller: using `TypedParams`
|
162
241
|
|
163
242
|
In addition to `require`ing `sorbet-rails`, you must also run
|
164
243
|
`rake rails_rbi:custom`, which will produce the RBI for these runtime features.
|
@@ -188,6 +267,22 @@ class ModelName
|
|
188
267
|
end
|
189
268
|
```
|
190
269
|
|
270
|
+
### Replace `Rails.application.routes.url_helpers`
|
271
|
+
|
272
|
+
When using url helpers like _url or _path methods outside of a controller,
|
273
|
+
we usually have to add `include Rails.application.routes.url_helpers` in the class.
|
274
|
+
However, Sorbet does not allow code that
|
275
|
+
[includes dynamic module](https://sorbet.org/docs/error-reference#4002).
|
276
|
+
Sorbet Rails provides a drop-in replacement module for the dynamic url_helpers module, called `GeneratedUrlHelpers`.
|
277
|
+
Following code change should resolve the sorbet type-check error:
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
class MyClass
|
281
|
+
- include Rails.application.routes.url_helpers
|
282
|
+
+ include GeneratedUrlHelpers
|
283
|
+
end
|
284
|
+
```
|
285
|
+
|
191
286
|
### `find`, `first` and `last`
|
192
287
|
|
193
288
|
These 3 methods can either return a single nilable record or an array of records. Sorbet does not allow us to define multiple signatures for a function ([except stdlib](https://github.com/chanzuckerberg/sorbet-rails/issues/18)). It doesn't support defining one function signature that has varying returning value depending on the input parameter type. We opt to define the most commonly used signature for these methods, and monkey-patch new functions for the secondary use case.
|
@@ -204,7 +299,9 @@ Following are the list of attribute dynamic methods and their static counterpart
|
|
204
299
|
- `find_by_<attributes>` -> `find_by(<attributes>)`
|
205
300
|
- `find_by_<attributes>!` -> `find_by!(<attributes>)`
|
206
301
|
- `<attribute>_changed?` -> `attribute_changed?(<attribute>)`
|
302
|
+
- `<attribute>_was` -> `attribute_was(<attribute>)`
|
207
303
|
- `saved_change_to_<attribute>?` -> `saved_change_to_attribute?(<attribute>)`
|
304
|
+
- `<attribute>_before_type_cast` -> `read_attribute_before_type_cast(<attribute>)`
|
208
305
|
|
209
306
|
### `after_commit` and other callbacks
|
210
307
|
|
@@ -259,26 +356,6 @@ Model.unscoped.scoping do … end
|
|
259
356
|
|
260
357
|
The [`select` method](https://apidock.com/rails/v4.0.2/ActiveRecord/QueryMethods/select) in Rails has two modes: it can be given a list of symbols, in which case rails will only return the given columns from the database, or it can be given a block, in which case it acts like [`Enumerable.select`](https://ruby-doc.org/core-2.6.4/Enumerable.html) and returns an array. We have chosen to support the first use case. If you want to pass a block to `select`, you can simply call `to_a` before you do. Note that this would be done within the `select` call anyway, so the performance penalty will be minimal.
|
261
358
|
|
262
|
-
### `pluck_to_tstruct` instead of `pluck`
|
263
|
-
|
264
|
-
The [`pluck` method](https://apidock.com/rails/ActiveRecord/Calculations/pluck) in Rails is a performant way to query value without instantiating ActiveRecord objects. However, it doesn't have any type information: it doesn't have type information (or name) of the attribute plucked. Sorbet-rails provides `pluck_to_tstruct` method as a replacement that does the same thing, but creates `T::Struct` object instead, and returns an array of `T::Struct`. The attributes plucked is based on props defined in the `T::Struct`
|
265
|
-
|
266
|
-
```ruby
|
267
|
-
# -- API
|
268
|
-
Arel.pluck_to_tstruct(TA[ <TStructSubClass> ].new)
|
269
|
-
|
270
|
-
# -- example
|
271
|
-
class WizardStruct < T::Struct
|
272
|
-
const :name, String
|
273
|
-
const :house, T.nilable(String)
|
274
|
-
end
|
275
|
-
|
276
|
-
Wizard.pluck_to_tstruct(TA[WizardStruct].new) # T::Array[WizardStruct]
|
277
|
-
Wizard.all.pluck_to_tstruct(TA[WizardStruct].new) # T::Array[WizardStruct]
|
278
|
-
```
|
279
|
-
|
280
|
-
This method is based on [pluck_to_hash](https://github.com/girishso/pluck_to_hash) gem.
|
281
|
-
|
282
359
|
## Extending Model Generation Task with Custom Plugins
|
283
360
|
|
284
361
|
`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.
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# typed: strong
|
2
|
+
class ActiveRecord::Base
|
3
|
+
sig { params(args: T.untyped).returns(T.attached_class) }
|
4
|
+
def self.find(*args); end
|
5
|
+
|
6
|
+
sig { params(args: T.untyped).returns(T.nilable(T.attached_class)) }
|
7
|
+
def self.find_by(*args); end
|
8
|
+
|
9
|
+
sig { params(args: T.untyped).returns(T.attached_class) }
|
10
|
+
def self.find_by!(*args); end
|
11
|
+
|
12
|
+
sig {
|
13
|
+
params(
|
14
|
+
attributes: T.untyped,
|
15
|
+
block: T.nilable(T.proc.params(object: T.attached_class).void),
|
16
|
+
).
|
17
|
+
returns(T.attached_class)
|
18
|
+
}
|
19
|
+
def self.find_or_initialize_by(attributes, &block); end
|
20
|
+
|
21
|
+
sig {
|
22
|
+
params(
|
23
|
+
attributes: T.untyped,
|
24
|
+
block: T.nilable(T.proc.params(object: T.attached_class).void),
|
25
|
+
).
|
26
|
+
returns(T.attached_class)
|
27
|
+
}
|
28
|
+
def self.find_or_create_by(attributes, &block); end
|
29
|
+
|
30
|
+
sig {
|
31
|
+
params(
|
32
|
+
attributes: T.untyped,
|
33
|
+
block: T.nilable(T.proc.params(object: T.attached_class).void),
|
34
|
+
).
|
35
|
+
returns(T.attached_class)
|
36
|
+
}
|
37
|
+
def self.find_or_create_by!(attributes, &block); end
|
38
|
+
|
39
|
+
sig { returns(T.nilable(T.attached_class)) }
|
40
|
+
def self.first; end
|
41
|
+
|
42
|
+
sig { returns(T.attached_class) }
|
43
|
+
def self.first!; end
|
44
|
+
|
45
|
+
sig { returns(T.nilable(T.attached_class)) }
|
46
|
+
def self.second; end
|
47
|
+
|
48
|
+
sig { returns(T.attached_class) }
|
49
|
+
def self.second!; end
|
50
|
+
|
51
|
+
sig { returns(T.nilable(T.attached_class)) }
|
52
|
+
def self.third; end
|
53
|
+
|
54
|
+
sig { returns(T.attached_class) }
|
55
|
+
def self.third!; end
|
56
|
+
|
57
|
+
sig { returns(T.nilable(T.attached_class)) }
|
58
|
+
def self.third_to_last; end
|
59
|
+
|
60
|
+
sig { returns(T.attached_class) }
|
61
|
+
def self.third_to_last!; end
|
62
|
+
|
63
|
+
sig { returns(T.nilable(T.attached_class)) }
|
64
|
+
def self.second_to_last; end
|
65
|
+
|
66
|
+
sig { returns(T.attached_class) }
|
67
|
+
def self.second_to_last!; end
|
68
|
+
|
69
|
+
sig { returns(T.nilable(T.attached_class)) }
|
70
|
+
def self.last; end
|
71
|
+
|
72
|
+
sig { returns(T.attached_class) }
|
73
|
+
def self.last!; end
|
74
|
+
|
75
|
+
sig { params(attributes: T.untyped, block: T.untyped).returns(T.attached_class) }
|
76
|
+
def self.create(attributes = nil, &block); end
|
77
|
+
|
78
|
+
sig { params(attributes: T.untyped, block: T.untyped).returns(T.attached_class) }
|
79
|
+
def self.create!(attributes = nil, &block); end
|
80
|
+
|
81
|
+
sig { params(attributes: T.untyped, block: T.untyped).returns(T.attached_class) }
|
82
|
+
def self.new(attributes = nil, &block); end
|
83
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# typed: strong
|
2
2
|
class ActiveRecord::Relation
|
3
|
+
Elem = type_member(fixed: T.untyped)
|
4
|
+
|
3
5
|
sig { params(args: T.untyped).returns(Elem) }
|
4
6
|
def find(*args); end
|
5
7
|
|
@@ -9,6 +11,33 @@ class ActiveRecord::Relation
|
|
9
11
|
sig { params(args: T.untyped).returns(Elem) }
|
10
12
|
def find_by!(*args); end
|
11
13
|
|
14
|
+
sig {
|
15
|
+
params(
|
16
|
+
attributes: T.untyped,
|
17
|
+
block: T.nilable(T.proc.params(object: Elem).void)
|
18
|
+
).
|
19
|
+
returns(Elem)
|
20
|
+
}
|
21
|
+
def find_or_initialize_by(attributes, &block); end
|
22
|
+
|
23
|
+
sig {
|
24
|
+
params(
|
25
|
+
attributes: T.untyped,
|
26
|
+
block: T.nilable(T.proc.params(object: Elem).void)
|
27
|
+
).
|
28
|
+
returns(Elem)
|
29
|
+
}
|
30
|
+
def find_or_create_by(attributes, &block); end
|
31
|
+
|
32
|
+
sig {
|
33
|
+
params(
|
34
|
+
attributes: T.untyped,
|
35
|
+
block: T.nilable(T.proc.params(object: Elem).void)
|
36
|
+
).
|
37
|
+
returns(Elem)
|
38
|
+
}
|
39
|
+
def find_or_create_by!(attributes, &block); end
|
40
|
+
|
12
41
|
sig { returns(T.nilable(Elem)) }
|
13
42
|
def first; end
|
14
43
|
|
@@ -45,6 +74,17 @@ class ActiveRecord::Relation
|
|
45
74
|
sig { returns(Elem) }
|
46
75
|
def last!; end
|
47
76
|
|
77
|
+
sig do
|
78
|
+
override.params(
|
79
|
+
start: T.nilable(Integer),
|
80
|
+
finish: T.nilable(Integer),
|
81
|
+
batch_size: T.nilable(Integer),
|
82
|
+
error_on_ignore: T.nilable(T::Boolean),
|
83
|
+
block: T.nilable(T.proc.params(e: Elem).void) # block is optional, eg. you can do Klass.find_each.map
|
84
|
+
).returns(T::Array[Elem])
|
85
|
+
end
|
86
|
+
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, &block); end
|
87
|
+
|
48
88
|
sig { override.params(block: T.proc.params(e: Elem).void).returns(T::Array[Elem]) }
|
49
89
|
def each(&block); end
|
50
90
|
|
@@ -68,6 +108,9 @@ class ActiveRecord::Relation
|
|
68
108
|
sig { returns(T::Boolean) }
|
69
109
|
def any?; end
|
70
110
|
|
111
|
+
sig { returns(T::Boolean) }
|
112
|
+
def empty?; end
|
113
|
+
|
71
114
|
sig { returns(T::Boolean) }
|
72
115
|
def many?; end
|
73
116
|
|