sorbet-rails 0.5.6 → 0.5.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +0 -2
  4. data/CONTRIBUTING.md +2 -4
  5. data/Gemfile +0 -4
  6. data/README.md +41 -7
  7. data/Rakefile +3 -14
  8. data/lib/bundled_rbi/parameters.rbi +4 -26
  9. data/lib/bundled_rbi/pluck_to_tstruct.rbi +22 -0
  10. data/lib/bundled_rbi/type_assert.rbi +27 -0
  11. data/lib/sorbet-rails/gem_plugins/elastic_search_plugin.rb +40 -0
  12. data/lib/sorbet-rails/gem_plugins/shrine_plugin.rb +76 -0
  13. data/lib/sorbet-rails/model_plugins/active_record_assoc.rb +2 -11
  14. data/lib/sorbet-rails/model_plugins/active_record_attribute.rb +3 -6
  15. data/lib/sorbet-rails/model_plugins/active_record_querying.rb +10 -2
  16. data/lib/sorbet-rails/model_plugins/plugins.rb +6 -0
  17. data/lib/sorbet-rails/rails_mixins/pluck_to_tstruct.rb +33 -0
  18. data/lib/sorbet-rails/railtie.rb +4 -0
  19. data/lib/sorbet-rails/sorbet_utils.rb +4 -1
  20. data/lib/sorbet-rails/tasks/rails_rbi.rake +16 -6
  21. data/sorbet-rails.gemspec +1 -1
  22. data/spec/bin/run_all_specs.sh +0 -1
  23. data/spec/bin/run_spec.sh +4 -6
  24. data/spec/generators/rails-template.rb +67 -124
  25. data/spec/generators/sorbet_test_cases.rb +26 -16
  26. data/spec/pluck_to_tstruct_spec.rb +79 -0
  27. data/spec/rails_helper.rb +0 -2
  28. data/spec/rake_rails_rbi_models_spec.rb +2 -0
  29. data/spec/sorbet_utils_spec.rb +37 -0
  30. data/spec/spec_helper.rb +1 -2
  31. data/spec/support/v5.0/Gemfile.lock +6 -6
  32. data/spec/support/v5.0/config/boot.rb +1 -1
  33. data/spec/support/v5.0/config/initializers/sorbet_rails.rb +1 -1
  34. data/spec/support/v5.0/db/migrate/20190620000004_add_more_column_types_to_wands.rb +1 -1
  35. data/spec/support/v5.0/sorbet_test_cases.rb +26 -16
  36. data/spec/support/v5.1/Gemfile.lock +6 -6
  37. data/spec/support/v5.1/config/boot.rb +1 -1
  38. data/spec/support/v5.1/config/initializers/sorbet_rails.rb +1 -1
  39. data/spec/support/v5.1/db/migrate/20190620000004_add_more_column_types_to_wands.rb +1 -1
  40. data/spec/support/v5.1/sorbet_test_cases.rb +26 -16
  41. data/spec/support/v5.2/Gemfile.lock +6 -6
  42. data/spec/support/v5.2/config/boot.rb +1 -1
  43. data/spec/support/v5.2/config/initializers/sorbet_rails.rb +1 -1
  44. data/spec/support/v5.2/db/migrate/20190620000004_add_more_column_types_to_wands.rb +1 -1
  45. data/spec/support/v5.2/sorbet_test_cases.rb +26 -16
  46. data/spec/support/v6.0/Gemfile.lock +6 -6
  47. data/spec/support/v6.0/config/boot.rb +1 -1
  48. data/spec/support/v6.0/config/initializers/sorbet_rails.rb +1 -1
  49. data/spec/support/v6.0/config/initializers/wrap_parameters.rb +1 -1
  50. data/spec/support/v6.0/db/migrate/20190620000004_add_more_column_types_to_wands.rb +1 -1
  51. data/spec/support/v6.0/sorbet_test_cases.rb +26 -16
  52. data/spec/test_data/v5.0/expected_internal_metadata.rbi +209 -197
  53. data/spec/test_data/v5.0/expected_potion.rbi +208 -196
  54. data/spec/test_data/v5.0/expected_schema_migration.rbi +209 -197
  55. data/spec/test_data/v5.0/expected_spell_book.rbi +208 -196
  56. data/spec/test_data/v5.0/expected_squib.rbi +209 -197
  57. data/spec/test_data/v5.0/expected_wand.rbi +208 -196
  58. data/spec/test_data/v5.0/expected_wizard.rbi +209 -197
  59. data/spec/test_data/v5.0/expected_wizard_wo_spellbook.rbi +209 -197
  60. data/spec/test_data/v5.1/expected_internal_metadata.rbi +213 -213
  61. data/spec/test_data/v5.1/expected_potion.rbi +212 -212
  62. data/spec/test_data/v5.1/expected_schema_migration.rbi +213 -213
  63. data/spec/test_data/v5.1/expected_spell_book.rbi +212 -212
  64. data/spec/test_data/v5.1/expected_squib.rbi +213 -213
  65. data/spec/test_data/v5.1/expected_wand.rbi +212 -212
  66. data/spec/test_data/v5.1/expected_wizard.rbi +213 -213
  67. data/spec/test_data/v5.1/expected_wizard_wo_spellbook.rbi +213 -213
  68. data/spec/test_data/v5.2/expected_attachment.rbi +212 -212
  69. data/spec/test_data/v5.2/expected_blob.rbi +212 -212
  70. data/spec/test_data/v5.2/expected_internal_metadata.rbi +213 -213
  71. data/spec/test_data/v5.2/expected_potion.rbi +212 -212
  72. data/spec/test_data/v5.2/expected_schema_migration.rbi +213 -213
  73. data/spec/test_data/v5.2/expected_spell_book.rbi +212 -212
  74. data/spec/test_data/v5.2/expected_squib.rbi +213 -213
  75. data/spec/test_data/v5.2/expected_wand.rbi +212 -212
  76. data/spec/test_data/v5.2/expected_wizard.rbi +213 -213
  77. data/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi +213 -213
  78. data/spec/test_data/v6.0/expected_attachment.rbi +244 -244
  79. data/spec/test_data/v6.0/expected_blob.rbi +244 -244
  80. data/spec/test_data/v6.0/expected_internal_metadata.rbi +245 -245
  81. data/spec/test_data/v6.0/expected_potion.rbi +244 -244
  82. data/spec/test_data/v6.0/expected_schema_migration.rbi +245 -245
  83. data/spec/test_data/v6.0/expected_spell_book.rbi +244 -244
  84. data/spec/test_data/v6.0/expected_squib.rbi +245 -245
  85. data/spec/test_data/v6.0/expected_wand.rbi +244 -244
  86. data/spec/test_data/v6.0/expected_wizard.rbi +245 -245
  87. data/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi +245 -245
  88. metadata +8 -185
  89. data/spec/bin/install.sh +0 -11
  90. data/spec/support/v4.2/.gitignore +0 -17
  91. data/spec/support/v4.2/Gemfile +0 -33
  92. data/spec/support/v4.2/Gemfile.lock +0 -128
  93. data/spec/support/v4.2/README.rdoc +0 -28
  94. data/spec/support/v4.2/Rakefile +0 -6
  95. data/spec/support/v4.2/app/assets/images/.keep +0 -0
  96. data/spec/support/v4.2/app/assets/stylesheets/application.css +0 -15
  97. data/spec/support/v4.2/app/controllers/application_controller.rb +0 -6
  98. data/spec/support/v4.2/app/controllers/concerns/.keep +0 -0
  99. data/spec/support/v4.2/app/helpers/application_helper.rb +0 -3
  100. data/spec/support/v4.2/app/helpers/bar_helper.rb +0 -3
  101. data/spec/support/v4.2/app/helpers/baz_helper.rb +0 -3
  102. data/spec/support/v4.2/app/helpers/foo_helper.rb +0 -3
  103. data/spec/support/v4.2/app/mailers/.keep +0 -0
  104. data/spec/support/v4.2/app/mailers/application_mailer.rb +0 -3
  105. data/spec/support/v4.2/app/mailers/daily_prophet_mailer.rb +0 -9
  106. data/spec/support/v4.2/app/mailers/hogwarts_acceptance_mailer.rb +0 -13
  107. data/spec/support/v4.2/app/models/.keep +0 -0
  108. data/spec/support/v4.2/app/models/application_record.rb +0 -4
  109. data/spec/support/v4.2/app/models/concerns/.keep +0 -0
  110. data/spec/support/v4.2/app/models/concerns/mythical.rb +0 -11
  111. data/spec/support/v4.2/app/models/potion.rb +0 -5
  112. data/spec/support/v4.2/app/models/spell_book.rb +0 -11
  113. data/spec/support/v4.2/app/models/squib.rb +0 -6
  114. data/spec/support/v4.2/app/models/wand.rb +0 -19
  115. data/spec/support/v4.2/app/models/wizard.rb +0 -29
  116. data/spec/support/v4.2/app/views/layouts/application.html.erb +0 -13
  117. data/spec/support/v4.2/bin/bundle +0 -3
  118. data/spec/support/v4.2/bin/rails +0 -4
  119. data/spec/support/v4.2/bin/rake +0 -4
  120. data/spec/support/v4.2/bin/setup +0 -29
  121. data/spec/support/v4.2/config.ru +0 -4
  122. data/spec/support/v4.2/config/application.rb +0 -36
  123. data/spec/support/v4.2/config/boot.rb +0 -4
  124. data/spec/support/v4.2/config/database.yml +0 -25
  125. data/spec/support/v4.2/config/environment.rb +0 -6
  126. data/spec/support/v4.2/config/environments/development.rb +0 -29
  127. data/spec/support/v4.2/config/environments/production.rb +0 -68
  128. data/spec/support/v4.2/config/environments/test.rb +0 -43
  129. data/spec/support/v4.2/config/initializers/backtrace_silencers.rb +0 -8
  130. data/spec/support/v4.2/config/initializers/cookies_serializer.rb +0 -4
  131. data/spec/support/v4.2/config/initializers/filter_parameter_logging.rb +0 -5
  132. data/spec/support/v4.2/config/initializers/inflections.rb +0 -17
  133. data/spec/support/v4.2/config/initializers/mime_types.rb +0 -5
  134. data/spec/support/v4.2/config/initializers/session_store.rb +0 -4
  135. data/spec/support/v4.2/config/initializers/sorbet_rails.rb +0 -3
  136. data/spec/support/v4.2/config/initializers/to_time_preserves_timezone.rb +0 -11
  137. data/spec/support/v4.2/config/initializers/wrap_parameters.rb +0 -15
  138. data/spec/support/v4.2/config/locales/en.yml +0 -23
  139. data/spec/support/v4.2/config/routes.rb +0 -58
  140. data/spec/support/v4.2/db/migrate/20190620000001_create_wizards.rb +0 -13
  141. data/spec/support/v4.2/db/migrate/20190620000002_create_wands.rb +0 -12
  142. data/spec/support/v4.2/db/migrate/20190620000003_create_spell_books.rb +0 -10
  143. data/spec/support/v4.2/db/migrate/20190620000004_add_more_column_types_to_wands.rb +0 -17
  144. data/spec/support/v4.2/db/migrate/20190620000005_add_broom_to_wizard.rb +0 -6
  145. data/spec/support/v4.2/db/migrate/20190620000007_add_type_to_wizard.rb +0 -6
  146. data/spec/support/v4.2/db/schema.rb +0 -49
  147. data/spec/support/v4.2/db/seeds.rb +0 -8
  148. data/spec/support/v4.2/lib/assets/.keep +0 -0
  149. data/spec/support/v4.2/lib/mythical_rbi_plugin.rb +0 -16
  150. data/spec/support/v4.2/lib/tasks/.keep +0 -0
  151. data/spec/support/v4.2/log/.keep +0 -0
  152. data/spec/support/v4.2/sorbet_test_cases.rb +0 -238
  153. data/spec/support/v4.2/test/controllers/.keep +0 -0
  154. data/spec/support/v4.2/test/fixtures/.keep +0 -0
  155. data/spec/support/v4.2/test/helpers/.keep +0 -0
  156. data/spec/support/v4.2/test/integration/.keep +0 -0
  157. data/spec/support/v4.2/test/mailers/.keep +0 -0
  158. data/spec/support/v4.2/test/models/.keep +0 -0
  159. data/spec/support/v4.2/test/test_helper.rb +0 -11
  160. data/spec/support/v4.2/typed-override.yaml +0 -2
  161. data/spec/support/v4.2/vendor/assets/stylesheets/.keep +0 -0
  162. data/spec/test_data/v4.2/expected_application_mailer.rbi +0 -5
  163. data/spec/test_data/v4.2/expected_daily_prophet_mailer.rbi +0 -7
  164. data/spec/test_data/v4.2/expected_helpers.rbi +0 -22
  165. data/spec/test_data/v4.2/expected_helpers_with_application_and_devise_helpers.rbi +0 -29
  166. data/spec/test_data/v4.2/expected_hogwarts_acceptance_mailer.rbi +0 -10
  167. data/spec/test_data/v4.2/expected_no_routes.rbi +0 -4
  168. data/spec/test_data/v4.2/expected_potion.rbi +0 -657
  169. data/spec/test_data/v4.2/expected_routes.rbi +0 -19
  170. data/spec/test_data/v4.2/expected_spell_book.rbi +0 -771
  171. data/spec/test_data/v4.2/expected_squib.rbi +0 -912
  172. data/spec/test_data/v4.2/expected_srb_tc_output.txt +0 -65
  173. data/spec/test_data/v4.2/expected_wand.rbi +0 -873
  174. data/spec/test_data/v4.2/expected_wizard.rbi +0 -912
  175. data/spec/test_data/v4.2/expected_wizard_wo_spellbook.rbi +0 -912
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94d5e7839ac88952e888bdde9ac9ee2c838c7833732a9e5f3af80c2eaf29b62c
4
- data.tar.gz: 74d8006e67f5283ba3f8dbdbefc347a49284c31307ad4cbc9a4e5a9986de80a6
3
+ metadata.gz: c8a83533dd2f5cd4cd6dc60f015808792494c7826240edd37c04e8de10aa4089
4
+ data.tar.gz: 9162300d63a55b865a901d55a2e76261ebf64ac003fae61d1904c8656c37b879
5
5
  SHA512:
6
- metadata.gz: 734626fabb0cd9761597f102b4b626a09c4f6f15663abb776fcdadf044851e4f08cfb7da2e125c1109a115037a79192b16bc9f69f989a789b8c57d55835da8ee
7
- data.tar.gz: 9d6dff417e3a1c160055b6880117a333efa0f3a3d6ff4ec8d0d9dce0b9298130857ed97a2e0e9e7d149019dd51b38a349b02302818fa57c47fec06eb8e28e6ab
6
+ metadata.gz: 21c050153045a1d5dab06bea09e8e571fbf598b073f53d9da34f42bd446dd79b43d67076f8f686e1e534306797253763bee825c0ec3d28dbcc0bc0bba86247be
7
+ data.tar.gz: a25bdfdfa28cab5ea91233ae34ae116005f9a7b99481892851a4af74d70ffee75dfba2618bb91f557b07fe97ef5335b4072f2d8fbe678e5afb644183b02d450d
data/.gitignore CHANGED
@@ -95,3 +95,5 @@ build-iPhoneSimulator/
95
95
 
96
96
  lib/sorbet/rbi/hidden-definitions/errors.txt
97
97
  .vscode
98
+
99
+ .rake_tasks~
@@ -1,7 +1,6 @@
1
1
  language: ruby
2
2
  env:
3
3
  matrix:
4
- - RAILS_VERSION=4.2
5
4
  - RAILS_VERSION=5.0
6
5
  - RAILS_VERSION=5.1
7
6
  - RAILS_VERSION=5.2
@@ -28,7 +27,6 @@ matrix:
28
27
  before_install:
29
28
  - gem install bundler -v 2.0.1 --no-doc
30
29
  - gem install bundler -v 1.17.3 --no-doc
31
- install: "./spec/bin/install.sh"
32
30
  script:
33
31
  - (cd lib && bundle exec srb tc)
34
32
  - "./spec/bin/run_spec.sh"
@@ -87,7 +87,6 @@ To run the tests against all supported Rails branches, use:
87
87
  You can also switch to a version of Rails with `RAILS_VERSION`:
88
88
 
89
89
  ```sh
90
- ❯ RAILS_VERSION=4.2 ./spec/bin/run_spec.sh
91
90
  ❯ RAILS_VERSION=5.0 ./spec/bin/run_spec.sh
92
91
  ❯ RAILS_VERSION=5.1 ./spec/bin/run_spec.sh
93
92
  ❯ RAILS_VERSION=5.2 ./spec/bin/run_spec.sh
@@ -124,9 +123,8 @@ copied into each app with `cp`.
124
123
  The `rails-template.rb` file uses the
125
124
  [Rails Application Template](https://guides.rubyonrails.org/rails_application_templates.html)
126
125
  functionality included in Rails. You can then regenerate each Rails app from
127
- the same file using `bundle _1.17.3_ exec rake update_spec:v4_2`, `bundle exec rake update_spec:v5_0`,
128
- `bundle exec rake update_spec:v5_1`, etc. (or just `bundle exec rake update_spec:v5_plus`,
129
- though this excludes regenerating 4.2 because 4.2 blocks usage of Bundler 2.x).
126
+ the same file using `bundle exec rake update_spec:v5_0`,
127
+ `bundle exec rake update_spec:v5_1`, etc. (or just `bundle exec rake update_spec:all`.
130
128
 
131
129
  #### Expected Output
132
130
 
data/Gemfile CHANGED
@@ -13,10 +13,6 @@ case rails_version
13
13
  when "master"
14
14
  gem "rails", {github: "rails/rails"}
15
15
  gem "bundler", ">= 1.3.0"
16
- when "4.2"
17
- gem "rails", "~> 4.2.11"
18
- gem "bundler", "~> 1.17.3"
19
- gem "sqlite3", "~> 1.3.6"
20
16
  when "5.0"
21
17
  gem "rails", "~> 5.0.7"
22
18
  gem "bundler", ">= 2.0"
data/README.md CHANGED
@@ -27,13 +27,15 @@ gem 'sorbet-rails'
27
27
  ❯ bundle install
28
28
  ```
29
29
 
30
+ Warning: *don't* add `sorbet-rails` to a specific environment group (eg. `development` only). `sorbet-rails` adds a bunch of helper methods to your Rails runtime as well as generators for RBI files. You'll want to run the gem in all environments.
31
+
30
32
  3. Generate RBI files for your routes, models, etc
31
33
  ```sh
32
34
  ❯ rake rails_rbi:routes
33
35
  ❯ rake rails_rbi:models
34
36
  ❯ rake rails_rbi:helpers
35
37
  ❯ rake rails_rbi:mailers
36
- ❯ rake rails_rbi:params
38
+ ❯ rake rails_rbi:custom
37
39
 
38
40
  # or run them all at once
39
41
  ❯ rake rails_rbi:all
@@ -54,7 +56,7 @@ This Rake task generates RBI files for all models in the Rails application (all
54
56
  ```sh
55
57
  ❯ rake rails_rbi:models
56
58
  ```
57
- You can also regenerate RBI files for specific models:
59
+ You can also regenerate RBI files for specific models. To accommodate for STI, this will generate rbi for all the subclasses of the models included.
58
60
  ```sh
59
61
  ❯ rake rails_rbi:models[ModelName,AnotherOne,...]
60
62
  ```
@@ -68,15 +70,19 @@ The generation task currently creates the following signatures:
68
70
 
69
71
  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.
70
72
 
73
+ We also add following methods to make type-checking more easily:
74
+ - [`find_n`, `first_n`, `last_n`](https://github.com/chanzuckerberg/sorbet-rails#find-first-and-last)
75
+ - [`pluck_to_tstruct`](#pluck_to_tstruct-instead-of-pluck)
76
+
71
77
  ### Controllers
72
78
  ```sh
73
- ❯ rake rails_rbi:params
79
+ ❯ rake rails_rbi:custom
74
80
  ```
75
81
 
76
82
  `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`
77
83
 
78
84
  This is the conversion in essence:
79
- ```
85
+ ```ruby
80
86
  params.require(:key) -> params.require_typed(:key, TA[Type].new)
81
87
  params.fetch(:key) -> params.fetch_typed(:key, TA[Type].new)
82
88
  params.fetch(:key, default_value) -> params.fetch_typed(:key, TA[Type].new, default_value)
@@ -84,7 +90,7 @@ params[:key] -> params.fetch_typed(:key, TA[T.nilable(Type)
84
90
  ```
85
91
 
86
92
  For example:
87
- ```
93
+ ```ruby
88
94
  # require_typed
89
95
  key = params.require_typed(:key, TA[String].new)
90
96
  T.reveal_type(key) # String
@@ -230,6 +236,30 @@ with:
230
236
  Model.unscoped.scoping do … end
231
237
  ```
232
238
 
239
+ ### `select` with a block
240
+
241
+ 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.
242
+
243
+ ### `pluck_to_tstruct` instead of `pluck`
244
+
245
+ 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`
246
+
247
+ ```ruby
248
+ # -- API
249
+ Arel.pluck_to_tstruct(TA[ <TStructSubClass> ].new)
250
+
251
+ # -- example
252
+ class WizardStruct < T::Struct
253
+ const :name, String
254
+ const :house, T.nilable(String)
255
+ end
256
+
257
+ Wizard.pluck_to_tstruct(TA[WizardStruct].new) # T::Array[WizardStruct]
258
+ Wizard.all.pluck_to_tstruct(TA[WizardStruct].new) # T::Array[WizardStruct]
259
+ ```
260
+
261
+ This method is based on [pluck_to_hash](https://github.com/girishso/pluck_to_hash) gem.
262
+
233
263
  ## Extending Model Generation Task with Custom Plugins
234
264
 
235
265
  `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.
@@ -307,16 +337,20 @@ These are the currently-supported gems and their symbolized names:
307
337
 
308
338
  | Gem | Symbol |
309
339
  |--------------|----------------|
340
+ | [ElasticSearch]| `:elastic_search` |
341
+ | [FriendlyId] | `:friendly_id` |
310
342
  | [Kaminari] | `:kaminari` |
311
343
  | [PgSearch] | `:pg_search` |
312
- | [FriendlyId] | `:friendly_id` |
344
+ | [Shrine] | `:shrine` |
313
345
 
314
- You can also configure the core model plugins if needed. The default plugins are defined in the [config](https://github.com/chanzuckerberg/sorbet-rails/blob/master/lib/sorbet-rails/lib/sorbet-rails/config.rb). For the full list of plugin symbols, check out [here](https://github.com/chanzuckerberg/sorbet-rails/blob/master/lib/sorbet-rails/model_plugins/plugins.rb).
346
+ You can also configure the core model plugins if needed. The default plugins are defined in the [config](https://github.com/chanzuckerberg/sorbet-rails/blob/master/lib/sorbet-rails/config.rb). For the full list of plugin symbols, check out [here](https://github.com/chanzuckerberg/sorbet-rails/blob/master/lib/sorbet-rails/model_plugins/plugins.rb).
315
347
 
316
348
 
317
349
  [Kaminari]: https://github.com/kaminari/kaminari
318
350
  [PgSearch]: https://github.com/Casecommons/pg_search
319
351
  [FriendlyId]: https://github.com/norman/friendly_id
352
+ [ElasticSearch]: https://github.com/elastic/elasticsearch-rails
353
+ [Shrine]: https://github.com/shrinerb/shrine
320
354
 
321
355
  ## Contributing
322
356
 
data/Rakefile CHANGED
@@ -8,9 +8,8 @@ task :default => :spec
8
8
  namespace :update_spec do
9
9
  require 'fileutils'
10
10
 
11
- # This excludes 4.2 because it won't work with Bundler 2.0
12
- desc "Generate Rails apps for all versions (except 4.2)."
13
- task :v5_plus do |t, args|
11
+ desc "Generate Rails apps for all versions."
12
+ task :all do |t, args|
14
13
  Rake::Task['update_spec:v6_0'].invoke
15
14
  Rake::Task['update_spec:v5_2'].invoke
16
15
  Rake::Task['update_spec:v5_1'].invoke
@@ -57,19 +56,9 @@ namespace :update_spec do
57
56
  end
58
57
  end
59
58
 
60
- desc "Delete the Rails 4.2 spec directory and regenerate it."
61
- task :v4_2 do |t, args|
62
- Bundler.with_clean_env do
63
- FileUtils.rm_rf 'spec/support/v4.2' if File.directory?('spec/support/v4.2')
64
- system("gem install rails -v 4.2.11")
65
- system("rails _4.2.11_ -v")
66
- system("RAILS_VERSION='4.2' rails _4.2.11_ new --template spec/generators/rails-template.rb spec/support/v4.2 --skip-javascript --skip-test --skip-sprockets --skip-spring --skip-listen")
67
- end
68
- end
69
-
70
59
  desc "Update sorbet_test_cases.rb in all the Rails apps in spec/support."
71
60
  task :sorbet_test_cases do |t, args|
72
- ['v6.0', 'v5.2', 'v5.1', 'v5.0', 'v4.2'].each do |version|
61
+ ['v6.0', 'v5.2', 'v5.1', 'v5.0'].each do |version|
73
62
  FileUtils.cp("spec/generators/sorbet_test_cases.rb", "spec/support/#{version}/sorbet_test_cases.rb")
74
63
  end
75
64
  end
@@ -1,31 +1,5 @@
1
1
  # typed: strong
2
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
3
  module SorbetRails::CustomParamsMethods
30
4
  extend T::Sig
31
5
 
@@ -48,3 +22,7 @@ module SorbetRails::CustomParamsMethods
48
22
  }
49
23
  def fetch_typed(key, ta, *args); end
50
24
  end
25
+
26
+ class ActionController::Parameters
27
+ include SorbetRails::CustomParamsMethods
28
+ end
@@ -0,0 +1,22 @@
1
+ # typed: strong
2
+
3
+ module SorbetRails::PluckToTStruct
4
+ extend T::Sig
5
+ sig {
6
+ type_parameters(:U).
7
+ params(
8
+ ta_struct: ITypeAssert[T.type_parameter(:U)],
9
+ ).
10
+ returns(T::Array[T.type_parameter(:U)])
11
+ }
12
+ def pluck_to_tstruct(ta_struct, &blk); end
13
+ end
14
+
15
+ class ActiveRecord::Base
16
+ extend SorbetRails::PluckToTStruct
17
+ end
18
+
19
+ class ActiveRecord::Relation
20
+ Elem = type_member
21
+ include SorbetRails::PluckToTStruct
22
+ end
@@ -0,0 +1,27 @@
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
@@ -0,0 +1,40 @@
1
+ # typed: true
2
+ class ElasticSearchPlugin < SorbetRails::ModelPlugins::Base
3
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
4
+ def generate(root)
5
+ return unless @model_class.include?(::Elasticsearch::Model)
6
+
7
+ model_rbi = root.create_class(model_class_name)
8
+ model_rbi.create_method(
9
+ 'mapping',
10
+ class_method: true,
11
+ parameters: [
12
+ ::Parlour::RbiGenerator::Parameter.new(
13
+ "options",
14
+ type: "T.nilable(T::Hash[Symbol, T.untyped])", default: 'nil',
15
+ ),
16
+ ::Parlour::RbiGenerator::Parameter.new(
17
+ "&block",
18
+ type: "T.proc.bind(Elasticsearch::Model::Indexing::Mappings).void",
19
+ )
20
+ ],
21
+ return_type: "Elasticsearch::Model::Indexing::Mappings",
22
+ )
23
+
24
+ model_rbi.create_method(
25
+ 'mappings',
26
+ class_method: true,
27
+ parameters: [
28
+ ::Parlour::RbiGenerator::Parameter.new(
29
+ "options",
30
+ type: "T.nilable(T::Hash[Symbol, T.untyped])", default: 'nil',
31
+ ),
32
+ ::Parlour::RbiGenerator::Parameter.new(
33
+ "&block",
34
+ type: "T.proc.bind(Elasticsearch::Model::Indexing::Mappings).void",
35
+ )
36
+ ],
37
+ return_type: "Elasticsearch::Model::Indexing::Mappings",
38
+ )
39
+ end
40
+ end
@@ -0,0 +1,76 @@
1
+ # typed: false
2
+ class ShrinePlugin < SorbetRails::ModelPlugins::Base
3
+ sig { override.params(root: Parlour::RbiGenerator::Namespace).void }
4
+ def generate(root)
5
+ model_rbi = root.create_class(model_class_name)
6
+ processed_attachments = Set.new
7
+ @model_class.included_modules.each do |included_module|
8
+ # based on https://github.com/shrinerb/shrine/blob/master/lib/shrine/attachment.rb
9
+ if included_module.is_a?(Shrine::Attachment)
10
+ attachment_name = included_module.attachment_name.to_s
11
+ next if processed_attachments.include?(attachment_name)
12
+ processed_attachments.add(attachment_name)
13
+
14
+ # TODO: detect nilability based on column nilability
15
+ model_rbi.create_method(
16
+ attachment_name,
17
+ return_type: "T.nilable(#{included_module.shrine_class}::UploadedFile)",
18
+ )
19
+ model_rbi.create_method(
20
+ "#{attachment_name}=",
21
+ parameters: [
22
+ ::Parlour::RbiGenerator::Parameter.new(
23
+ "file",
24
+ type:
25
+ "T.any(String, T::Hash[T.untyped, T.untyped],
26
+ #{included_module.shrine_class}::UploadedFile)".squish!,
27
+ ),
28
+ ],
29
+ )
30
+ model_rbi.create_method(
31
+ "#{attachment_name}_attacher",
32
+ return_type: "T.nilable(#{included_module.shrine_class}::Attacher)",
33
+ )
34
+
35
+ # remote_url plugin
36
+ # https://github.com/shrinerb/shrine/blob/2b7fad37dbaa955a7d3b82e9e05eaacb3506b4ba/
37
+ # ../lib/shrine/plugins/remote_url.rb
38
+ if included_module.is_a?(Shrine::Plugins::RemoteUrl::AttachmentMethods)
39
+ model_rbi.create_method(
40
+ "#{attachment_name}_remote_url",
41
+ return_type: "T.nilable(String)",
42
+ )
43
+ model_rbi.create_method(
44
+ "#{attachment_name}_remote_url=",
45
+ parameters: [
46
+ ::Parlour::RbiGenerator::Parameter.new(
47
+ "url",
48
+ type: T.untyped # TODO likely T.nilable(String)
49
+ ),
50
+ ],
51
+ )
52
+ end
53
+
54
+ #--
55
+ attachment = Object.const_get("#{included_module.shrine_class}::Attachment")
56
+ attachment_rbi = root.create_class(
57
+ attachment.name,
58
+ superclass: 'Shrine::Attachment',
59
+ )
60
+ attachment_rbi.create_method(
61
+ "initialize",
62
+ parameters: [
63
+ ::Parlour::RbiGenerator::Parameter.new('name', type: 'T.any(String, Symbol)'),
64
+ ::Parlour::RbiGenerator::Parameter.new('**option', type: 'T.untyped'),
65
+ ]
66
+ )
67
+ #--
68
+ uploaded_file = Object.const_get("#{included_module.shrine_class}::UploadedFile")
69
+ uploaded_file_rbi = root.create_class(
70
+ uploaded_file.name,
71
+ superclass: 'Shrine::UploadedFile',
72
+ )
73
+ end
74
+ end
75
+ end
76
+ end
@@ -38,17 +38,8 @@ class SorbetRails::ModelPlugins::ActiveRecordAssoc < SorbetRails::ModelPlugins::
38
38
  assoc_type = "T.nilable(#{assoc_class})"
39
39
  if reflection.belongs_to?
40
40
  column_def = @columns_hash[reflection.foreign_key.to_s]
41
- if ENV["RAILS_VERSION"] == "4.2"
42
- # Before Rails 5, belongs_to relations were nilable by default
43
- # if this is a belongs_to connection, we may be able to detect whether
44
- # this field is required & use a stronger type
45
- if column_def
46
- assoc_type = assoc_class if !column_def.null
47
- end
48
- else
49
- # In Rails 5 and later, belongs_to are required unless specified to be optional
50
- assoc_type = assoc_class if !reflection.options[:optional]
51
- end
41
+ # In Rails 5 and later, belongs_to are required unless specified to be optional
42
+ assoc_type = assoc_class if !reflection.options[:optional]
52
43
  end
53
44
 
54
45
  assoc_module_rbi.create_method(
@@ -75,8 +75,7 @@ class SorbetRails::ModelPlugins::ActiveRecordAttribute < SorbetRails::ModelPlugi
75
75
 
76
76
  sig do
77
77
  params(
78
- # in v4.2, datetime can be TimeZoneConverter
79
- klass: T.any(Object, ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter),
78
+ klass: Object,
80
79
  time_zone_aware: T::Boolean,
81
80
  ).returns(T.any(String, Class))
82
81
  end
@@ -88,10 +87,6 @@ class SorbetRails::ModelPlugins::ActiveRecordAttribute < SorbetRails::ModelPlugi
88
87
  time_zone_aware ? ActiveSupport::TimeWithZone : Time
89
88
  when ActiveRecord::Type::Date
90
89
  Date
91
- when ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter
92
- # if type has already been decorated with TimeZoneConverter, it's probably
93
- # a Rails 4.2 datetime column and can be considered a TimeWithZone
94
- ActiveSupport::TimeWithZone
95
90
  when ActiveRecord::Type::Decimal
96
91
  BigDecimal
97
92
  when ActiveRecord::Type::Float
@@ -145,6 +140,8 @@ class SorbetRails::ModelPlugins::ActiveRecordAttribute < SorbetRails::ModelPlugi
145
140
  "T.any(#{assignable_time_types.join(', ')})"
146
141
  elsif column_type == "T.nilable(ActiveSupport::TimeWithZone)"
147
142
  "T.nilable(T.any(#{assignable_time_types.join(', ')}))"
143
+ elsif column_type == String
144
+ 'T.any(String, Symbol)'
148
145
  else
149
146
  column_type.to_s
150
147
  end