tapioca 0.17.8 → 0.17.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/tapioca/commands/abstract_dsl.rb +21 -2
  4. data/lib/tapioca/commands/abstract_gem.rb +21 -2
  5. data/lib/tapioca/commands/annotations.rb +7 -1
  6. data/lib/tapioca/commands/check_shims.rb +9 -1
  7. data/lib/tapioca/commands/command.rb +1 -1
  8. data/lib/tapioca/dsl/compiler.rb +17 -12
  9. data/lib/tapioca/dsl/compilers/aasm.rb +2 -2
  10. data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +2 -2
  11. data/lib/tapioca/dsl/compilers/action_mailer.rb +1 -1
  12. data/lib/tapioca/dsl/compilers/action_text.rb +1 -1
  13. data/lib/tapioca/dsl/compilers/active_job.rb +1 -1
  14. data/lib/tapioca/dsl/compilers/active_model_attributes.rb +1 -1
  15. data/lib/tapioca/dsl/compilers/active_model_secure_password.rb +7 -1
  16. data/lib/tapioca/dsl/compilers/active_model_validations_confirmation.rb +1 -1
  17. data/lib/tapioca/dsl/compilers/active_record_associations.rb +1 -1
  18. data/lib/tapioca/dsl/compilers/active_record_columns.rb +8 -2
  19. data/lib/tapioca/dsl/compilers/active_record_delegated_types.rb +1 -1
  20. data/lib/tapioca/dsl/compilers/active_record_enum.rb +2 -2
  21. data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +1 -1
  22. data/lib/tapioca/dsl/compilers/active_record_relations.rb +94 -100
  23. data/lib/tapioca/dsl/compilers/active_record_scope.rb +1 -1
  24. data/lib/tapioca/dsl/compilers/active_record_secure_token.rb +1 -1
  25. data/lib/tapioca/dsl/compilers/active_record_store.rb +1 -1
  26. data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +1 -1
  27. data/lib/tapioca/dsl/compilers/active_resource.rb +1 -1
  28. data/lib/tapioca/dsl/compilers/active_storage.rb +2 -2
  29. data/lib/tapioca/dsl/compilers/active_support_concern.rb +6 -6
  30. data/lib/tapioca/dsl/compilers/active_support_current_attributes.rb +1 -1
  31. data/lib/tapioca/dsl/compilers/active_support_time_ext.rb +1 -1
  32. data/lib/tapioca/dsl/compilers/config.rb +2 -2
  33. data/lib/tapioca/dsl/compilers/frozen_record.rb +1 -1
  34. data/lib/tapioca/dsl/compilers/graphql_input_object.rb +1 -1
  35. data/lib/tapioca/dsl/compilers/graphql_mutation.rb +1 -1
  36. data/lib/tapioca/dsl/compilers/identity_cache.rb +2 -2
  37. data/lib/tapioca/dsl/compilers/json_api_client_resource.rb +1 -1
  38. data/lib/tapioca/dsl/compilers/kredis.rb +1 -1
  39. data/lib/tapioca/dsl/compilers/mixed_in_class_attributes.rb +2 -2
  40. data/lib/tapioca/dsl/compilers/protobuf.rb +7 -3
  41. data/lib/tapioca/dsl/compilers/rails_generators.rb +1 -1
  42. data/lib/tapioca/dsl/compilers/sidekiq_worker.rb +1 -1
  43. data/lib/tapioca/dsl/compilers/smart_properties.rb +1 -1
  44. data/lib/tapioca/dsl/compilers/state_machines.rb +2 -2
  45. data/lib/tapioca/dsl/compilers/url_helpers.rb +7 -7
  46. data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +7 -3
  47. data/lib/tapioca/dsl/helpers/graphql_type_helper.rb +18 -3
  48. data/lib/tapioca/dsl/pipeline.rb +25 -11
  49. data/lib/tapioca/gem/events.rb +15 -8
  50. data/lib/tapioca/gem/listeners/methods.rb +19 -7
  51. data/lib/tapioca/gem/listeners/mixins.rb +3 -3
  52. data/lib/tapioca/gem/listeners/sorbet_type_variables.rb +1 -1
  53. data/lib/tapioca/gem/pipeline.rb +25 -18
  54. data/lib/tapioca/gemfile.rb +1 -1
  55. data/lib/tapioca/helpers/config_helper.rb +5 -1
  56. data/lib/tapioca/helpers/rbi_files_helper.rb +8 -1
  57. data/lib/tapioca/helpers/test/content.rb +1 -1
  58. data/lib/tapioca/internal.rb +1 -0
  59. data/lib/tapioca/loaders/gem.rb +15 -3
  60. data/lib/tapioca/rbi_ext/model.rb +9 -2
  61. data/lib/tapioca/repo_index.rb +1 -1
  62. data/lib/tapioca/runtime/attached_class_of_32.rb +1 -1
  63. data/lib/tapioca/runtime/attached_class_of_legacy.rb +1 -1
  64. data/lib/tapioca/runtime/dynamic_mixin_compiler.rb +6 -6
  65. data/lib/tapioca/runtime/generic_type_registry.rb +8 -8
  66. data/lib/tapioca/runtime/helpers.rb +40 -0
  67. data/lib/tapioca/runtime/reflection.rb +19 -19
  68. data/lib/tapioca/runtime/trackers/autoload.rb +1 -1
  69. data/lib/tapioca/runtime/trackers/constant_definition.rb +3 -3
  70. data/lib/tapioca/runtime/trackers/method_definition.rb +4 -4
  71. data/lib/tapioca/runtime/trackers/mixin.rb +5 -5
  72. data/lib/tapioca/runtime/trackers/required_ancestor.rb +3 -3
  73. data/lib/tapioca/runtime/trackers/tracker.rb +1 -1
  74. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +4 -4
  75. data/lib/tapioca/sorbet_ext/name_patch.rb +3 -14
  76. data/lib/tapioca/static/requires_compiler.rb +1 -1
  77. data/lib/tapioca/version.rb +1 -1
  78. data/lib/tapioca.rb +0 -36
  79. metadata +20 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 489bd75ab0b8322c633ee51dbdb7f0bf4701fbca5cf64401c418d8a7fb454418
4
- data.tar.gz: 62e4137c4fb603186d93b2f470148f5a8b7baa73bcfb6ed8b000a519dc1f106a
3
+ metadata.gz: fd0aedb9a8295fc96a30b43e9a3da1f84bebdf3f97bb2fbd1fd99375fdad6fc1
4
+ data.tar.gz: 2c649b047df9cb012f7ed8502c9206e419e70a6bc7c1d2d07785aaad51af649e
5
5
  SHA512:
6
- metadata.gz: ef5107149d789dda2d5c426a14b611ab1062f8aaa919ec179805c95bf7ad7d22eaae368ac9e0ed86b61cfac38b5bbbfc2fa65fa262837ce22ff4ee054b5cbf31
7
- data.tar.gz: e568320ce79f3e9afa07d1ea1fc58aa7aef422f782b77c4b93707016b680bd2e3c2c971b136016dbf754ed82199e461178467195166f2c7738dec40632ac5de1
6
+ metadata.gz: d1fe2a59d4570b065179f64d6de4e6bd27f494b2c23545c4a2ccf64a9cf33383ca5fd99a5eaf1ac3d93ff720b68780504b09beb501ad5567c6ea5c917d9004fe
7
+ data.tar.gz: '08514a0edef06b920cc2a07493f86f9a428e33554d1509210cfc4a0d044735303043efceb1a14f3ce2d18b29d4693bcd8e36a9153c4c4c836aa0fcbacd5110ef'
data/README.md CHANGED
@@ -673,7 +673,7 @@ module Tapioca
673
673
 
674
674
  ConstantType = type_member {{ fixed: T.class_of(Encryptable) }}
675
675
 
676
- sig { override.returns(T::Enumerable[Module]) }
676
+ sig { override.returns(T::Enumerable[T::Module[T.anything]]) }
677
677
  def self.gather_constants
678
678
  # Collect all the classes that include Encryptable
679
679
  all_classes.select { |c| c < ::Encryptable }
@@ -806,7 +806,7 @@ module Tapioca
806
806
 
807
807
  ConstantType = type_member {{ fixed: T.class_of(Encryptable) }}
808
808
 
809
- sig { override.returns(T::Enumerable[Module]) }
809
+ sig { override.returns(T::Enumerable[T::Module[T.anything]]) }
810
810
  def self.gather_constants
811
811
  # Collect all the classes that include Encryptable
812
812
  all_classes.select { |c| c < ::Encryptable }
@@ -8,7 +8,26 @@ module Tapioca
8
8
  include SorbetHelper
9
9
  include RBIFilesHelper
10
10
 
11
- #: (requested_constants: Array[String], requested_paths: Array[Pathname], outpath: Pathname, only: Array[String], exclude: Array[String], file_header: bool, tapioca_path: String, ?skip_constant: Array[String], ?quiet: bool, ?verbose: bool, ?number_of_workers: Integer?, ?auto_strictness: bool, ?gem_dir: String, ?rbi_formatter: RBIFormatter, ?app_root: String, ?halt_upon_load_error: bool, ?compiler_options: Hash[String, untyped], ?lsp_addon: bool) -> void
11
+ #: (
12
+ #| requested_constants: Array[String],
13
+ #| requested_paths: Array[Pathname],
14
+ #| outpath: Pathname,
15
+ #| only: Array[String],
16
+ #| exclude: Array[String],
17
+ #| file_header: bool,
18
+ #| tapioca_path: String,
19
+ #| ?skip_constant: Array[String],
20
+ #| ?quiet: bool,
21
+ #| ?verbose: bool,
22
+ #| ?number_of_workers: Integer?,
23
+ #| ?auto_strictness: bool,
24
+ #| ?gem_dir: String,
25
+ #| ?rbi_formatter: RBIFormatter,
26
+ #| ?app_root: String,
27
+ #| ?halt_upon_load_error: bool,
28
+ #| ?compiler_options: Hash[String, untyped],
29
+ #| ?lsp_addon: bool
30
+ #| ) -> void
12
31
  def initialize(
13
32
  requested_constants:,
14
33
  requested_paths:,
@@ -143,7 +162,7 @@ module Tapioca
143
162
  filenames.to_set
144
163
  end
145
164
 
146
- #: (Array[String] constant_names, ?ignore_missing: bool) -> Array[Module]
165
+ #: (Array[String] constant_names, ?ignore_missing: bool) -> Array[T::Module[top]]
147
166
  def constantize(constant_names, ignore_missing: false)
148
167
  constant_map = constant_names.to_h do |name|
149
168
  [name, Object.const_get(name)]
@@ -8,7 +8,26 @@ module Tapioca
8
8
  include SorbetHelper
9
9
  include RBIFilesHelper
10
10
 
11
- #: (gem_names: Array[String], exclude: Array[String], include_dependencies: bool, prerequire: String?, postrequire: String, typed_overrides: Hash[String, String], outpath: Pathname, file_header: bool, include_doc: bool, include_loc: bool, include_exported_rbis: bool, ?number_of_workers: Integer?, ?auto_strictness: bool, ?dsl_dir: String, ?rbi_formatter: RBIFormatter, ?halt_upon_load_error: bool, ?lsp_addon: bool?, ?verbose: bool?) -> void
11
+ #: (
12
+ #| gem_names: Array[String],
13
+ #| exclude: Array[String],
14
+ #| include_dependencies: bool,
15
+ #| prerequire: String?,
16
+ #| postrequire: String,
17
+ #| typed_overrides: Hash[String, String],
18
+ #| outpath: Pathname,
19
+ #| file_header: bool,
20
+ #| include_doc: bool,
21
+ #| include_loc: bool,
22
+ #| include_exported_rbis: bool,
23
+ #| ?number_of_workers: Integer?,
24
+ #| ?auto_strictness: bool,
25
+ #| ?dsl_dir: String,
26
+ #| ?rbi_formatter: RBIFormatter,
27
+ #| ?halt_upon_load_error: bool,
28
+ #| ?lsp_addon: bool?,
29
+ #| ?verbose: bool?
30
+ #| ) -> void
12
31
  def initialize(
13
32
  gem_names:,
14
33
  exclude:,
@@ -70,7 +89,7 @@ module Tapioca
70
89
  reason: "types exported from the `#{gem.name}` gem",
71
90
  ) if @file_header
72
91
 
73
- rbi.root = Tapioca.with_disabled_exits do
92
+ rbi.root = Runtime.with_disabled_exits do
74
93
  Tapioca::Gem::Pipeline.new(
75
94
  gem,
76
95
  include_doc: @include_doc,
@@ -6,7 +6,13 @@ module Tapioca
6
6
  class Annotations < CommandWithoutTracker
7
7
  extend T::Sig
8
8
 
9
- #: (central_repo_root_uris: Array[String], ?auth: String?, ?netrc_file: String?, ?central_repo_index_path: String, ?typed_overrides: Hash[String, String]) -> void
9
+ #: (
10
+ #| central_repo_root_uris: Array[String],
11
+ #| ?auth: String?,
12
+ #| ?netrc_file: String?,
13
+ #| ?central_repo_index_path: String,
14
+ #| ?typed_overrides: Hash[String, String]
15
+ #| ) -> void
10
16
  def initialize(
11
17
  central_repo_root_uris:,
12
18
  auth: nil,
@@ -8,7 +8,15 @@ module Tapioca
8
8
  include SorbetHelper
9
9
  include RBIFilesHelper
10
10
 
11
- #: (gem_rbi_dir: String, dsl_rbi_dir: String, annotations_rbi_dir: String, shim_rbi_dir: String, todo_rbi_file: String, payload: bool, number_of_workers: Integer?) -> void
11
+ #: (
12
+ #| gem_rbi_dir: String,
13
+ #| dsl_rbi_dir: String,
14
+ #| annotations_rbi_dir: String,
15
+ #| shim_rbi_dir: String,
16
+ #| todo_rbi_file: String,
17
+ #| payload: bool,
18
+ #| number_of_workers: Integer?
19
+ #| ) -> void
12
20
  def initialize(
13
21
  gem_rbi_dir:,
14
22
  dsl_rbi_dir:,
@@ -21,7 +21,7 @@ module Tapioca
21
21
  # @final
22
22
  #: -> void
23
23
  def run
24
- Tapioca.silence_warnings do
24
+ Runtime.silence_warnings do
25
25
  execute
26
26
  end
27
27
  end
@@ -4,7 +4,7 @@
4
4
  module Tapioca
5
5
  module Dsl
6
6
  # @abstract
7
- #: [ConstantType < Module]
7
+ #: [ConstantType < T::Module[top]]
8
8
  class Compiler
9
9
  extend T::Sig
10
10
 
@@ -21,26 +21,26 @@ module Tapioca
21
21
  #: Hash[String, untyped]
22
22
  attr_reader :options
23
23
 
24
- @@requested_constants = [] #: Array[Module] # rubocop:disable Style/ClassVars
24
+ @@requested_constants = [] #: Array[T::Module[top]] # rubocop:disable Style/ClassVars
25
25
 
26
26
  class << self
27
27
  extend T::Sig
28
28
 
29
- #: (Module constant) -> bool
29
+ #: (T::Module[top] constant) -> bool
30
30
  def handles?(constant)
31
31
  processable_constants.include?(constant)
32
32
  end
33
33
 
34
34
  # @abstract
35
- #: -> T::Enumerable[Module]
35
+ #: -> Enumerable[T::Module[top]]
36
36
  def gather_constants = raise NotImplementedError, "Abstract method called"
37
37
 
38
- #: -> Set[Module]
38
+ #: -> Set[T::Module[top]]
39
39
  def processable_constants
40
- @processable_constants ||= T::Set[Module].new.compare_by_identity.merge(gather_constants) #: Set[Module]?
40
+ @processable_constants ||= T::Set[T::Module[T.anything]].new.compare_by_identity.merge(gather_constants) #: Set[T::Module[top]]?
41
41
  end
42
42
 
43
- #: (Array[Module] constants) -> void
43
+ #: (Array[T::Module[top]] constants) -> void
44
44
  def requested_constants=(constants)
45
45
  @@requested_constants = constants # rubocop:disable Style/ClassVars
46
46
  end
@@ -68,22 +68,27 @@ module Tapioca
68
68
  end
69
69
  end
70
70
 
71
- #: -> T::Enumerable[Class[top]]
71
+ #: -> Enumerable[Class[top]]
72
72
  def all_classes
73
- @all_classes ||= all_modules.grep(Class).freeze #: T::Enumerable[Class[top]]?
73
+ @all_classes ||= all_modules.grep(Class).freeze #: Enumerable[Class[top]]?
74
74
  end
75
75
 
76
- #: -> T::Enumerable[Module]
76
+ #: -> Enumerable[T::Module[top]]
77
77
  def all_modules
78
78
  @all_modules ||= if @@requested_constants.any?
79
79
  @@requested_constants.grep(Module)
80
80
  else
81
81
  ObjectSpace.each_object(Module).to_a
82
- end.freeze #: T::Enumerable[Module]?
82
+ end.freeze #: Enumerable[T::Module[top]]?
83
83
  end
84
84
  end
85
85
 
86
- #: (Tapioca::Dsl::Pipeline pipeline, RBI::Tree root, ConstantType constant, ?Hash[String, untyped] options) -> void
86
+ #: (
87
+ #| Tapioca::Dsl::Pipeline pipeline,
88
+ #| RBI::Tree root,
89
+ #| ConstantType constant,
90
+ #| ?Hash[String, untyped] options
91
+ #| ) -> void
87
92
  def initialize(pipeline, root, constant, options = {})
88
93
  @pipeline = pipeline
89
94
  @root = root
@@ -203,9 +203,9 @@ module Tapioca
203
203
  extend T::Sig
204
204
 
205
205
  # @override
206
- #: -> T::Enumerable[Module]
206
+ #: -> Enumerable[T::Module[top]]
207
207
  def gather_constants
208
- T.cast(ObjectSpace.each_object(::AASM::ClassMethods), T::Enumerable[Module])
208
+ T.cast(ObjectSpace.each_object(::AASM::ClassMethods), T::Enumerable[T::Module[T.anything]])
209
209
  end
210
210
  end
211
211
  end
@@ -121,7 +121,7 @@ module Tapioca
121
121
  extend T::Sig
122
122
 
123
123
  # @override
124
- #: -> T::Enumerable[Module]
124
+ #: -> Enumerable[T::Module[top]]
125
125
  def gather_constants
126
126
  descendants_of(::ActionController::Base).select(&:name).select do |klass|
127
127
  klass.const_defined?(:HelperMethods, false)
@@ -152,7 +152,7 @@ module Tapioca
152
152
  )
153
153
  end
154
154
 
155
- #: (Module mod) -> Array[String]
155
+ #: (T::Module[top] mod) -> Array[String]
156
156
  def gather_includes(mod)
157
157
  mod.ancestors
158
158
  .reject { |ancestor| ancestor.is_a?(Class) || ancestor == mod || name_of(ancestor).nil? }
@@ -54,7 +54,7 @@ module Tapioca
54
54
  extend T::Sig
55
55
 
56
56
  # @override
57
- #: -> T::Enumerable[Module]
57
+ #: -> Enumerable[T::Module[top]]
58
58
  def gather_constants
59
59
  descendants_of(::ActionMailer::Base).reject(&:abstract?)
60
60
  end
@@ -84,7 +84,7 @@ module Tapioca
84
84
  end
85
85
 
86
86
  # @override
87
- #: -> T::Enumerable[Module]
87
+ #: -> Enumerable[T::Module[top]]
88
88
  def gather_constants
89
89
  descendants_of(::ActiveRecord::Base)
90
90
  .reject(&:abstract_class?)
@@ -88,7 +88,7 @@ module Tapioca
88
88
  extend T::Sig
89
89
 
90
90
  # @override
91
- #: -> T::Enumerable[Module]
91
+ #: -> Enumerable[T::Module[top]]
92
92
  def gather_constants
93
93
  descendants_of(::ActiveJob::Base)
94
94
  end
@@ -63,7 +63,7 @@ module Tapioca
63
63
  extend T::Sig
64
64
 
65
65
  # @override
66
- #: -> T::Enumerable[Module]
66
+ #: -> Enumerable[T::Module[top]]
67
67
  def gather_constants
68
68
  all_classes.grep(::ActiveModel::Attributes::ClassMethods)
69
69
  end
@@ -93,8 +93,14 @@ module Tapioca
93
93
  extend T::Sig
94
94
 
95
95
  # @override
96
- #: -> T::Enumerable[Module]
96
+ #: -> Enumerable[T::Module[top]]
97
97
  def gather_constants
98
+ # In some versions of Rails 8.1, `ActiveModel::SecurePassword` uses `Numeric#minutes`
99
+ # which isn't explicitly required in the gem, and it might not be loaded already.
100
+ # We might need to require it before referencing the constant to avoid a NoMethodError when
101
+ # the constant is autoloaded.
102
+ require "active_support/core_ext/numeric/time" unless defined?(1.minutes)
103
+
98
104
  # This selects all classes that are `ActiveModel::SecurePassword::ClassMethods === klass`.
99
105
  # In other words, we select all classes that have `ActiveModel::SecurePassword::ClassMethods`
100
106
  # as an ancestor of its singleton class, i.e. all classes that have extended the
@@ -46,7 +46,7 @@ module Tapioca
46
46
 
47
47
  class << self
48
48
  # @override
49
- #: -> T::Enumerable[Module]
49
+ #: -> Enumerable[T::Module[top]]
50
50
  def gather_constants
51
51
  # Collect all the classes that include ActiveModel::Validations
52
52
  all_classes.select { |c| ActiveModel::Validations > c }
@@ -141,7 +141,7 @@ module Tapioca
141
141
  extend T::Sig
142
142
 
143
143
  # @override
144
- #: -> T::Enumerable[Module]
144
+ #: -> Enumerable[T::Module[top]]
145
145
  def gather_constants
146
146
  descendants_of(::ActiveRecord::Base).reject(&:abstract_class?)
147
147
  end
@@ -166,7 +166,7 @@ module Tapioca
166
166
  extend T::Sig
167
167
 
168
168
  # @override
169
- #: -> T::Enumerable[Module]
169
+ #: -> Enumerable[T::Module[top]]
170
170
  def gather_constants
171
171
  descendants_of(::ActiveRecord::Base).reject(&:abstract_class?)
172
172
  end
@@ -189,7 +189,13 @@ module Tapioca
189
189
  )
190
190
  end
191
191
 
192
- #: (RBI::Scope klass, String name, Array[String]? methods_to_add, ?return_type: String, ?parameters: Array[RBI::TypedParam]) -> void
192
+ #: (
193
+ #| RBI::Scope klass,
194
+ #| String name,
195
+ #| Array[String]? methods_to_add,
196
+ #| ?return_type: String,
197
+ #| ?parameters: Array[RBI::TypedParam]
198
+ #| ) -> void
193
199
  def add_method(klass, name, methods_to_add, return_type: "void", parameters: [])
194
200
  klass.create_method(
195
201
  name,
@@ -91,7 +91,7 @@ module Tapioca
91
91
  extend T::Sig
92
92
 
93
93
  # @override
94
- #: -> T::Enumerable[Module]
94
+ #: -> Enumerable[T::Module[top]]
95
95
  def gather_constants
96
96
  descendants_of(::ActiveRecord::Base).reject(&:abstract_class?)
97
97
  end
@@ -13,7 +13,7 @@ module Tapioca
13
13
  #
14
14
  # ~~~rb
15
15
  # class Post < ApplicationRecord
16
- # enum title_type: %i(book all web), _suffix: :title
16
+ # enum :title_type, %i(book all web), suffix: :title
17
17
  # end
18
18
  # ~~~
19
19
  #
@@ -78,7 +78,7 @@ module Tapioca
78
78
  extend T::Sig
79
79
 
80
80
  # @override
81
- #: -> T::Enumerable[Module]
81
+ #: -> Enumerable[T::Module[top]]
82
82
  def gather_constants
83
83
  descendants_of(::ActiveRecord::Base)
84
84
  end
@@ -62,7 +62,7 @@ module Tapioca
62
62
  extend T::Sig
63
63
 
64
64
  # @override
65
- #: -> T::Enumerable[Module]
65
+ #: -> Enumerable[T::Module[top]]
66
66
  def gather_constants
67
67
  return [] unless defined?(Rails.application) && Rails.application
68
68
 
@@ -184,7 +184,7 @@ module Tapioca
184
184
  extend T::Sig
185
185
 
186
186
  # @override
187
- #: -> T::Enumerable[Module]
187
+ #: -> Enumerable[T::Module[top]]
188
188
  def gather_constants
189
189
  ActiveRecord::Base.descendants.reject(&:abstract_class?)
190
190
  end
@@ -229,15 +229,7 @@ module Tapioca
229
229
  use_ranges: ["T.untyped", "nil"],
230
230
  } #: Hash[Symbol, [String, String]]
231
231
  CALCULATION_METHODS = ActiveRecord::Calculations.instance_methods(false) #: Array[Symbol]
232
- ENUMERABLE_QUERY_METHODS = [:any?, :many?, :none?, :one?] #: Array[Symbol]
233
- FIND_OR_CREATE_METHODS = [
234
- :find_or_create_by,
235
- :find_or_create_by!,
236
- :find_or_initialize_by,
237
- :create_or_find_by,
238
- :create_or_find_by!,
239
- ] #: Array[Symbol]
240
- BUILDER_METHODS = [:new, :create, :create!, :build] #: Array[Symbol]
232
+ RELATION_METHODS = ActiveRecord::Relation.instance_methods(false) #: Array[Symbol]
241
233
  TO_ARRAY_METHODS = [:to_ary, :to_a] #: Array[Symbol]
242
234
 
243
235
  private
@@ -612,47 +604,9 @@ module Tapioca
612
604
 
613
605
  #: -> void
614
606
  def create_association_relation_methods
615
- returning_type = "T.nilable(T.any(T::Array[Symbol], FalseClass))"
616
- unique_by_type = "T.nilable(T.any(T::Array[Symbol], Symbol))"
617
-
618
- ASSOCIATION_METHODS.each do |method_name|
619
- case method_name
620
- when :insert_all, :insert_all!, :upsert_all
621
- parameters = [
622
- create_param("attributes", type: "T::Array[Hash]"),
623
- create_kw_opt_param("returning", type: returning_type, default: "nil"),
624
- ]
625
-
626
- # Bang methods don't have the `unique_by` parameter
627
- unless bang_method?(method_name)
628
- parameters << create_kw_opt_param("unique_by", type: unique_by_type, default: "nil")
629
- end
630
-
631
- association_relation_methods_module.create_method(
632
- method_name.to_s,
633
- parameters: parameters,
634
- return_type: "ActiveRecord::Result",
635
- )
636
- when :insert, :insert!, :upsert
637
- parameters = [
638
- create_param("attributes", type: "Hash"),
639
- create_kw_opt_param("returning", type: returning_type, default: "nil"),
640
- ]
641
-
642
- # Bang methods don't have the `unique_by` parameter
643
- unless bang_method?(method_name)
644
- parameters << create_kw_opt_param("unique_by", type: unique_by_type, default: "nil")
645
- end
646
-
647
- association_relation_methods_module.create_method(
648
- method_name.to_s,
649
- parameters: parameters,
650
- return_type: "ActiveRecord::Result",
651
- )
652
- when :proxy_association
653
- # skip - private method
654
- end
655
- end
607
+ # skips insert/upsert methods - these methods' signatures aren't model-specific and don't need to be generated dynamically
608
+ # also skips proxy_association method - it's a private method
609
+ # but there could be other association methods that we need to generate
656
610
  end
657
611
 
658
612
  #: -> void
@@ -907,61 +861,96 @@ module Tapioca
907
861
  end
908
862
  end
909
863
 
910
- ENUMERABLE_QUERY_METHODS.each do |method_name|
911
- block_type = "T.nilable(T.proc.params(record: #{constant_name}).returns(T.untyped))"
912
- create_common_method(
913
- method_name,
914
- parameters: [
915
- create_block_param("block", type: block_type),
916
- ],
917
- return_type: "T::Boolean",
918
- )
919
- end
920
-
921
- FIND_OR_CREATE_METHODS.each do |method_name|
922
- common_relation_methods_module.create_method(method_name.to_s) do |method|
923
- method.add_param("attributes")
924
- method.add_block_param("block")
864
+ RELATION_METHODS.each do |method_name|
865
+ case method_name
866
+ when :any?, :many?, :none?, :one? # enumerable query methods
867
+ block_type = "T.nilable(T.proc.params(record: #{constant_name}).returns(T.untyped))"
868
+ create_common_method(
869
+ method_name,
870
+ parameters: [
871
+ create_block_param("block", type: block_type),
872
+ ],
873
+ return_type: "T::Boolean",
874
+ )
875
+ when :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, :create_or_find_by, :create_or_find_by! # find or create methods
876
+ common_relation_methods_module.create_method(method_name.to_s) do |method|
877
+ method.add_param("attributes")
878
+ method.add_block_param("block")
925
879
 
926
- # `T.untyped` matches `T::Array[T.untyped]` so the array signature
927
- # must be defined first for Sorbet to pick it, if valid.
928
- method.add_sig do |sig|
929
- sig.add_param("attributes", "T::Array[T.untyped]")
930
- sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
931
- sig.return_type = "T::Array[#{constant_name}]"
932
- end
880
+ # `T.untyped` matches `T::Array[T.untyped]` so the array signature
881
+ # must be defined first for Sorbet to pick it, if valid.
882
+ method.add_sig do |sig|
883
+ sig.add_param("attributes", "T::Array[T.untyped]")
884
+ sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
885
+ sig.return_type = "T::Array[#{constant_name}]"
886
+ end
933
887
 
934
- method.add_sig do |sig|
935
- sig.add_param("attributes", "T.untyped")
936
- sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
937
- sig.return_type = constant_name
888
+ method.add_sig do |sig|
889
+ sig.add_param("attributes", "T.untyped")
890
+ sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
891
+ sig.return_type = constant_name
892
+ end
938
893
  end
939
- end
940
- end
941
-
942
- BUILDER_METHODS.each do |method_name|
943
- common_relation_methods_module.create_method(method_name.to_s) do |method|
944
- method.add_opt_param("attributes", "nil")
945
- method.add_block_param("block")
894
+ when :new, :create, :create!, :build # builder methods
895
+ common_relation_methods_module.create_method(method_name.to_s) do |method|
896
+ method.add_opt_param("attributes", "nil")
897
+ method.add_block_param("block")
946
898
 
947
- method.add_sig do |sig|
948
- sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
949
- sig.return_type = constant_name
950
- end
899
+ method.add_sig do |sig|
900
+ sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
901
+ sig.return_type = constant_name
902
+ end
951
903
 
952
- # `T.untyped` matches `T::Array[T.untyped]` so the array signature
953
- # must be defined first for Sorbet to pick it, if valid.
954
- method.add_sig do |sig|
955
- sig.add_param("attributes", "T::Array[T.untyped]")
956
- sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
957
- sig.return_type = "T::Array[#{constant_name}]"
958
- end
904
+ # `T.untyped` matches `T::Array[T.untyped]` so the array signature
905
+ # must be defined first for Sorbet to pick it, if valid.
906
+ method.add_sig do |sig|
907
+ sig.add_param("attributes", "T::Array[T.untyped]")
908
+ sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
909
+ sig.return_type = "T::Array[#{constant_name}]"
910
+ end
959
911
 
960
- method.add_sig do |sig|
961
- sig.add_param("attributes", "T.untyped")
962
- sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
963
- sig.return_type = constant_name
912
+ method.add_sig do |sig|
913
+ sig.add_param("attributes", "T.untyped")
914
+ sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
915
+ sig.return_type = constant_name
916
+ end
964
917
  end
918
+ when :insert_all, :insert_all!, :upsert_all, :insert, :insert!, :upsert # insert methods
919
+ # skip - these methods' signatures aren't model-specific and don't need to be generated dynamically
920
+ when :delete, :destroy
921
+ # For these cases, it is valid to pass the above kind of things, but also:
922
+ # - a model identifier, which can be:
923
+ # - a numeric id, thus `Integer`
924
+ # - a string id, thus `String`
925
+ # - a collection of identifiers
926
+ # - a collection of identifiers, thus `T::Enumerable[T.any(Integer, String)]`
927
+ # which, coupled with the above case, gives us:
928
+ # `T.any(Model, Integer, String, T::Enumerable[T.any(Model, Integer, String, T::Enumerable[Model])])`
929
+
930
+ common_relation_methods_module.create_method(
931
+ method_name.to_s,
932
+ parameters: [
933
+ create_rest_param(
934
+ "records",
935
+ type: "T.any(#{constant_name}, Integer, String" \
936
+ ", T::Enumerable[T.any(#{constant_name}, Integer, String, T::Enumerable[#{constant_name}])])",
937
+ ),
938
+ ],
939
+ return_type: method_name == :delete ? "Integer" : "T::Array[#{constant_name}]",
940
+ )
941
+ when :delete_all, :destroy_all
942
+ common_relation_methods_module.create_method(
943
+ method_name.to_s,
944
+ return_type: method_name == :delete_all ? "Integer" : "T::Array[#{constant_name}]",
945
+ )
946
+ when :delete_by, :destroy_by
947
+ common_relation_methods_module.create_method(
948
+ method_name.to_s,
949
+ parameters: [
950
+ create_param("args", type: "T.untyped"),
951
+ ],
952
+ return_type: method_name == :delete_by ? "Integer" : "T::Array[#{constant_name}]",
953
+ )
965
954
  end
966
955
  end
967
956
 
@@ -1044,7 +1033,12 @@ module Tapioca
1044
1033
  end
1045
1034
  end
1046
1035
 
1047
- #: ((Symbol | String) name, ?parameters: Array[RBI::TypedParam], ?relation_return_type: String, ?association_return_type: String) -> void
1036
+ #: (
1037
+ #| (Symbol | String) name,
1038
+ #| ?parameters: Array[RBI::TypedParam],
1039
+ #| ?relation_return_type: String,
1040
+ #| ?association_return_type: String
1041
+ #| ) -> void
1048
1042
  def create_relation_method(
1049
1043
  name,
1050
1044
  parameters: [],
@@ -78,7 +78,7 @@ module Tapioca
78
78
 
79
79
  class << self
80
80
  # @override
81
- #: -> T::Enumerable[Module]
81
+ #: -> Enumerable[T::Module[top]]
82
82
  def gather_constants
83
83
  descendants_of(::ActiveRecord::Base).reject(&:abstract_class?)
84
84
  end
@@ -60,7 +60,7 @@ module Tapioca
60
60
  extend T::Sig
61
61
 
62
62
  # @override
63
- #: -> T::Enumerable[Module]
63
+ #: -> Enumerable[T::Module[top]]
64
64
  def gather_constants
65
65
  descendants_of(::ActiveRecord::Base).reject(&:abstract_class?)
66
66
  end