tapioca 0.16.9 → 0.17.7

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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -0
  3. data/exe/tapioca +6 -1
  4. data/lib/ruby_lsp/tapioca/addon.rb +73 -43
  5. data/lib/ruby_lsp/tapioca/run_gem_rbi_check.rb +43 -43
  6. data/lib/ruby_lsp/tapioca/server_addon.rb +13 -10
  7. data/lib/tapioca/bundler_ext/auto_require_hook.rb +6 -14
  8. data/lib/tapioca/cli.rb +16 -8
  9. data/lib/tapioca/commands/abstract_dsl.rb +39 -66
  10. data/lib/tapioca/commands/abstract_gem.rb +25 -46
  11. data/lib/tapioca/commands/annotations.rb +28 -34
  12. data/lib/tapioca/commands/check_shims.rb +6 -15
  13. data/lib/tapioca/commands/command.rb +12 -26
  14. data/lib/tapioca/commands/command_without_tracker.rb +2 -5
  15. data/lib/tapioca/commands/configure.rb +11 -16
  16. data/lib/tapioca/commands/dsl_compiler_list.rb +2 -1
  17. data/lib/tapioca/commands/dsl_generate.rb +2 -1
  18. data/lib/tapioca/commands/dsl_verify.rb +2 -1
  19. data/lib/tapioca/commands/gem_generate.rb +5 -9
  20. data/lib/tapioca/commands/gem_sync.rb +2 -1
  21. data/lib/tapioca/commands/gem_verify.rb +3 -2
  22. data/lib/tapioca/commands/require.rb +3 -7
  23. data/lib/tapioca/commands/todo.rb +6 -10
  24. data/lib/tapioca/dsl/compiler.rb +36 -63
  25. data/lib/tapioca/dsl/compilers/aasm.rb +33 -44
  26. data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +8 -7
  27. data/lib/tapioca/dsl/compilers/action_mailer.rb +6 -5
  28. data/lib/tapioca/dsl/compilers/action_text.rb +6 -5
  29. data/lib/tapioca/dsl/compilers/active_job.rb +6 -10
  30. data/lib/tapioca/dsl/compilers/active_model_attributes.rb +10 -11
  31. data/lib/tapioca/dsl/compilers/active_model_secure_password.rb +5 -6
  32. data/lib/tapioca/dsl/compilers/active_model_validations_confirmation.rb +5 -12
  33. data/lib/tapioca/dsl/compilers/active_record_associations.rb +17 -44
  34. data/lib/tapioca/dsl/compilers/active_record_columns.rb +20 -26
  35. data/lib/tapioca/dsl/compilers/active_record_delegated_types.rb +9 -8
  36. data/lib/tapioca/dsl/compilers/active_record_enum.rb +7 -6
  37. data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +54 -62
  38. data/lib/tapioca/dsl/compilers/active_record_relations.rb +148 -209
  39. data/lib/tapioca/dsl/compilers/active_record_scope.rb +8 -13
  40. data/lib/tapioca/dsl/compilers/active_record_secure_token.rb +5 -4
  41. data/lib/tapioca/dsl/compilers/active_record_store.rb +5 -4
  42. data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +19 -28
  43. data/lib/tapioca/dsl/compilers/active_resource.rb +19 -21
  44. data/lib/tapioca/dsl/compilers/active_storage.rb +6 -14
  45. data/lib/tapioca/dsl/compilers/active_support_concern.rb +9 -8
  46. data/lib/tapioca/dsl/compilers/active_support_current_attributes.rb +8 -7
  47. data/lib/tapioca/dsl/compilers/active_support_time_ext.rb +5 -4
  48. data/lib/tapioca/dsl/compilers/config.rb +5 -4
  49. data/lib/tapioca/dsl/compilers/frozen_record.rb +7 -11
  50. data/lib/tapioca/dsl/compilers/graphql_input_object.rb +9 -10
  51. data/lib/tapioca/dsl/compilers/graphql_mutation.rb +6 -10
  52. data/lib/tapioca/dsl/compilers/identity_cache.rb +11 -39
  53. data/lib/tapioca/dsl/compilers/json_api_client_resource.rb +9 -18
  54. data/lib/tapioca/dsl/compilers/kredis.rb +7 -8
  55. data/lib/tapioca/dsl/compilers/mixed_in_class_attributes.rb +5 -4
  56. data/lib/tapioca/dsl/compilers/protobuf.rb +13 -26
  57. data/lib/tapioca/dsl/compilers/rails_generators.rb +9 -11
  58. data/lib/tapioca/dsl/compilers/sidekiq_worker.rb +23 -13
  59. data/lib/tapioca/dsl/compilers/smart_properties.rb +32 -38
  60. data/lib/tapioca/dsl/compilers/state_machines.rb +15 -26
  61. data/lib/tapioca/dsl/compilers/url_helpers.rb +10 -9
  62. data/lib/tapioca/dsl/compilers.rb +4 -7
  63. data/lib/tapioca/dsl/helpers/active_model_type_helper.rb +13 -16
  64. data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +13 -28
  65. data/lib/tapioca/dsl/helpers/active_record_constants_helper.rb +19 -15
  66. data/lib/tapioca/dsl/helpers/graphql_type_helper.rb +5 -24
  67. data/lib/tapioca/dsl/pipeline.rb +30 -58
  68. data/lib/tapioca/executor.rb +6 -12
  69. data/lib/tapioca/gem/events.rb +24 -34
  70. data/lib/tapioca/gem/listeners/base.rb +7 -10
  71. data/lib/tapioca/gem/listeners/dynamic_mixins.rb +4 -2
  72. data/lib/tapioca/gem/listeners/foreign_constants.rb +5 -7
  73. data/lib/tapioca/gem/listeners/methods.rb +36 -47
  74. data/lib/tapioca/gem/listeners/mixins.rb +6 -18
  75. data/lib/tapioca/gem/listeners/remove_empty_payload_scopes.rb +4 -2
  76. data/lib/tapioca/gem/listeners/sorbet_enums.rb +4 -2
  77. data/lib/tapioca/gem/listeners/sorbet_helpers.rb +4 -2
  78. data/lib/tapioca/gem/listeners/sorbet_props.rb +4 -2
  79. data/lib/tapioca/gem/listeners/sorbet_required_ancestors.rb +4 -2
  80. data/lib/tapioca/gem/listeners/sorbet_signatures.rb +7 -5
  81. data/lib/tapioca/gem/listeners/sorbet_type_variables.rb +6 -4
  82. data/lib/tapioca/gem/listeners/source_location.rb +15 -8
  83. data/lib/tapioca/gem/listeners/subconstants.rb +5 -4
  84. data/lib/tapioca/gem/listeners/yard_doc.rb +30 -23
  85. data/lib/tapioca/gem/pipeline.rb +107 -91
  86. data/lib/tapioca/gem_info.rb +1 -1
  87. data/lib/tapioca/gemfile.rb +64 -73
  88. data/lib/tapioca/helpers/cli_helper.rb +4 -7
  89. data/lib/tapioca/helpers/config_helper.rb +17 -29
  90. data/lib/tapioca/helpers/env_helper.rb +2 -5
  91. data/lib/tapioca/helpers/gem_helper.rb +5 -5
  92. data/lib/tapioca/helpers/git_attributes.rb +3 -3
  93. data/lib/tapioca/helpers/rbi_files_helper.rb +76 -73
  94. data/lib/tapioca/helpers/rbi_helper.rb +14 -22
  95. data/lib/tapioca/helpers/sorbet_helper.rb +9 -18
  96. data/lib/tapioca/helpers/source_uri.rb +15 -25
  97. data/lib/tapioca/helpers/test/content.rb +7 -10
  98. data/lib/tapioca/helpers/test/dsl_compiler.rb +20 -33
  99. data/lib/tapioca/helpers/test/isolation.rb +10 -14
  100. data/lib/tapioca/helpers/test/template.rb +6 -11
  101. data/lib/tapioca/internal.rb +18 -8
  102. data/lib/tapioca/loaders/dsl.rb +11 -19
  103. data/lib/tapioca/loaders/gem.rb +6 -21
  104. data/lib/tapioca/loaders/loader.rb +21 -39
  105. data/lib/tapioca/rbi_ext/model.rb +12 -37
  106. data/lib/tapioca/rbi_formatter.rb +10 -19
  107. data/lib/tapioca/rbs/rewriter.rb +55 -0
  108. data/lib/tapioca/repo_index.rb +7 -9
  109. data/lib/tapioca/runtime/attached_class_of_32.rb +1 -1
  110. data/lib/tapioca/runtime/attached_class_of_legacy.rb +2 -5
  111. data/lib/tapioca/runtime/dynamic_mixin_compiler.rb +23 -23
  112. data/lib/tapioca/runtime/generic_type_registry.rb +13 -23
  113. data/lib/tapioca/runtime/reflection.rb +81 -60
  114. data/lib/tapioca/runtime/source_location.rb +44 -0
  115. data/lib/tapioca/runtime/trackers/autoload.rb +7 -9
  116. data/lib/tapioca/runtime/trackers/constant_definition.rb +18 -14
  117. data/lib/tapioca/runtime/trackers/method_definition.rb +65 -0
  118. data/lib/tapioca/runtime/trackers/mixin.rb +8 -11
  119. data/lib/tapioca/runtime/trackers/required_ancestor.rb +3 -3
  120. data/lib/tapioca/runtime/trackers/tracker.rb +3 -6
  121. data/lib/tapioca/runtime/trackers.rb +5 -8
  122. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +9 -15
  123. data/lib/tapioca/sorbet_ext/name_patch.rb +2 -2
  124. data/lib/tapioca/sorbet_ext/proc_bind_patch.rb +1 -1
  125. data/lib/tapioca/static/requires_compiler.rb +6 -6
  126. data/lib/tapioca/static/symbol_loader.rb +14 -16
  127. data/lib/tapioca/static/symbol_table_parser.rb +8 -8
  128. data/lib/tapioca/version.rb +1 -1
  129. data/lib/tapioca.rb +22 -29
  130. metadata +27 -10
@@ -63,13 +63,13 @@ module Tapioca
63
63
  # end
64
64
  #
65
65
  # ~~~
66
+ #: [ConstantType = (singleton(ActiveRecord::Base) & Extensions::ActiveRecord)]
66
67
  class ActiveRecordDelegatedTypes < Compiler
67
68
  extend T::Sig
68
69
  include Helpers::ActiveRecordConstantsHelper
69
70
 
70
- ConstantType = type_member { { fixed: T.all(T.class_of(ActiveRecord::Base), Extensions::ActiveRecord) } }
71
-
72
- sig { override.void }
71
+ # @override
72
+ #: -> void
73
73
  def decorate
74
74
  return if constant.__tapioca_delegated_types.nil?
75
75
 
@@ -90,7 +90,8 @@ module Tapioca
90
90
  class << self
91
91
  extend T::Sig
92
92
 
93
- sig { override.returns(T::Enumerable[Module]) }
93
+ # @override
94
+ #: -> T::Enumerable[Module]
94
95
  def gather_constants
95
96
  descendants_of(::ActiveRecord::Base).reject(&:abstract_class?)
96
97
  end
@@ -98,7 +99,7 @@ module Tapioca
98
99
 
99
100
  private
100
101
 
101
- sig { params(mod: RBI::Scope, role: Symbol, types: T::Array[String]).void }
102
+ #: (RBI::Scope mod, Symbol role, Array[String] types) -> void
102
103
  def populate_role_accessors(mod, role, types)
103
104
  mod.create_method(
104
105
  "#{role}_name",
@@ -115,18 +116,18 @@ module Tapioca
115
116
  mod.create_method(
116
117
  "build_#{role}",
117
118
  parameters: [create_rest_param("args", type: "T.untyped")],
118
- return_type: "T.any(#{types.join(", ")})",
119
+ return_type: types.size == 1 ? types.first : "T.any(#{types.join(", ")})",
119
120
  )
120
121
  end
121
122
 
122
- sig { params(mod: RBI::Scope, role: Symbol, types: T::Array[String], options: T::Hash[Symbol, T.untyped]).void }
123
+ #: (RBI::Scope mod, Symbol role, Array[String] types, Hash[Symbol, untyped] options) -> void
123
124
  def populate_type_helpers(mod, role, types, options)
124
125
  types.each do |type|
125
126
  populate_type_helper(mod, role, type, options)
126
127
  end
127
128
  end
128
129
 
129
- sig { params(mod: RBI::Scope, role: Symbol, type: String, options: T::Hash[Symbol, T.untyped]).void }
130
+ #: (RBI::Scope mod, Symbol role, String type, Hash[Symbol, untyped] options) -> void
130
131
  def populate_type_helper(mod, role, type, options)
131
132
  singular = type.tableize.tr("/", "_").singularize
132
133
  query = "#{singular}?"
@@ -49,12 +49,12 @@ module Tapioca
49
49
  # end
50
50
  # end
51
51
  # ~~~
52
+ #: [ConstantType = singleton(::ActiveRecord::Base)]
52
53
  class ActiveRecordEnum < Compiler
53
54
  extend T::Sig
54
55
 
55
- ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
56
-
57
- sig { override.void }
56
+ # @override
57
+ #: -> void
58
58
  def decorate
59
59
  return if constant.defined_enums.empty?
60
60
 
@@ -77,7 +77,8 @@ module Tapioca
77
77
  class << self
78
78
  extend T::Sig
79
79
 
80
- sig { override.returns(T::Enumerable[Module]) }
80
+ # @override
81
+ #: -> T::Enumerable[Module]
81
82
  def gather_constants
82
83
  descendants_of(::ActiveRecord::Base)
83
84
  end
@@ -85,7 +86,7 @@ module Tapioca
85
86
 
86
87
  private
87
88
 
88
- sig { params(enum_map: T::Hash[T.untyped, T.untyped]).returns(String) }
89
+ #: (Hash[untyped, untyped] enum_map) -> String
89
90
  def type_for_enum(enum_map)
90
91
  value_type = enum_map.values.map { |v| v.class.name }.uniq
91
92
  value_type = if value_type.length == 1
@@ -97,7 +98,7 @@ module Tapioca
97
98
  "T::Hash[T.any(String, Symbol), #{value_type}]"
98
99
  end
99
100
 
100
- sig { params(klass: RBI::Scope).void }
101
+ #: (RBI::Scope klass) -> void
101
102
  def generate_instance_methods(klass)
102
103
  methods = constant.send(:_enum_methods_module).instance_methods
103
104
 
@@ -33,13 +33,14 @@ module Tapioca
33
33
  # def posts(fixture_name = nil, *other_fixtures); end
34
34
  # end
35
35
  # ~~~
36
+ #: [ConstantType = singleton(ActiveSupport::TestCase)]
36
37
  class ActiveRecordFixtures < Compiler
37
38
  extend T::Sig
38
39
 
39
- ConstantType = type_member { { fixed: T.class_of(ActiveSupport::TestCase) } }
40
40
  MISSING = Object.new
41
41
 
42
- sig { override.void }
42
+ # @override
43
+ #: -> void
43
44
  def decorate
44
45
  method_names = if fixture_loader.respond_to?(:fixture_sets)
45
46
  method_names_from_lazy_fixture_loader
@@ -60,7 +61,8 @@ module Tapioca
60
61
  class << self
61
62
  extend T::Sig
62
63
 
63
- sig { override.returns(T::Enumerable[Module]) }
64
+ # @override
65
+ #: -> T::Enumerable[Module]
64
66
  def gather_constants
65
67
  return [] unless defined?(Rails.application) && Rails.application
66
68
 
@@ -70,35 +72,32 @@ module Tapioca
70
72
 
71
73
  private
72
74
 
73
- sig { returns(T::Class[ActiveRecord::TestFixtures]) }
75
+ #: -> Class[ActiveRecord::TestFixtures]
74
76
  def fixture_loader
75
- @fixture_loader ||= T.let(
76
- Class.new do
77
- T.unsafe(self).include(ActiveRecord::TestFixtures)
78
-
79
- if respond_to?(:fixture_paths=)
80
- T.unsafe(self).fixture_paths = [Rails.root.join("test", "fixtures")]
81
- else
82
- T.unsafe(self).fixture_path = Rails.root.join("test", "fixtures")
83
- end
77
+ @fixture_loader ||= Class.new do
78
+ T.unsafe(self).include(ActiveRecord::TestFixtures)
84
79
 
85
- # https://github.com/rails/rails/blob/7c70791470fc517deb7c640bead9f1b47efb5539/activerecord/lib/active_record/test_fixtures.rb#L46
86
- singleton_class.define_method(:file_fixture_path) do
87
- Rails.root.join("test", "fixtures", "files")
88
- end
80
+ if respond_to?(:fixture_paths=)
81
+ T.unsafe(self).fixture_paths = [Rails.root.join("test", "fixtures")]
82
+ else
83
+ T.unsafe(self).fixture_path = Rails.root.join("test", "fixtures")
84
+ end
85
+
86
+ # https://github.com/rails/rails/blob/7c70791470fc517deb7c640bead9f1b47efb5539/activerecord/lib/active_record/test_fixtures.rb#L46
87
+ singleton_class.define_method(:file_fixture_path) do
88
+ Rails.root.join("test", "fixtures", "files")
89
+ end
89
90
 
90
- T.unsafe(self).fixtures(:all)
91
- end,
92
- T.nilable(T::Class[ActiveRecord::TestFixtures]),
93
- )
91
+ T.unsafe(self).fixtures(:all)
92
+ end #: Class[ActiveRecord::TestFixtures]?
94
93
  end
95
94
 
96
- sig { returns(T::Array[String]) }
95
+ #: -> Array[String]
97
96
  def method_names_from_lazy_fixture_loader
98
97
  T.unsafe(fixture_loader).fixture_sets.keys
99
98
  end
100
99
 
101
- sig { returns(T::Array[String]) }
100
+ #: -> Array[String]
102
101
  def method_names_from_eager_fixture_loader
103
102
  fixture_loader.ancestors # get all ancestors from class that includes AR fixtures
104
103
  .drop(1) # drop the anonymous class itself from the array
@@ -108,7 +107,7 @@ module Tapioca
108
107
  end
109
108
  end
110
109
 
111
- sig { params(mod: RBI::Scope, name: String).void }
110
+ #: (RBI::Scope mod, String name) -> void
112
111
  def create_fixture_method(mod, name)
113
112
  return_type = return_type_for_fixture(name)
114
113
  mod.create_method(name) do |node|
@@ -135,7 +134,7 @@ module Tapioca
135
134
  end
136
135
  end
137
136
 
138
- sig { params(fixture_name: String).returns(String) }
137
+ #: (String fixture_name) -> String
139
138
  def return_type_for_fixture(fixture_name)
140
139
  fixture_class_mapping_from_fixture_files[fixture_name] ||
141
140
  fixture_class_from_fixture_set(fixture_name) ||
@@ -143,7 +142,7 @@ module Tapioca
143
142
  "T.untyped"
144
143
  end
145
144
 
146
- sig { params(fixture_name: String).returns(T.nilable(String)) }
145
+ #: (String fixture_name) -> String?
147
146
  def fixture_class_from_fixture_set(fixture_name)
148
147
  # only rails 7.1+ support fixture sets so this is conditional
149
148
  return unless fixture_loader.respond_to?(:fixture_sets)
@@ -157,54 +156,47 @@ module Tapioca
157
156
  model_name
158
157
  end
159
158
 
160
- sig { returns(T::Hash[String, String]) }
159
+ #: -> Hash[String, String]
161
160
  def fixture_class_from_active_record_base_class_mapping
162
- @fixture_class_mapping ||= T.let(
163
- begin
164
- ActiveRecord::Base.descendants.each_with_object({}) do |model_class, mapping|
165
- class_name = model_class.name
161
+ @fixture_class_mapping ||=
162
+ ActiveRecord::Base.descendants.each_with_object({}) do |model_class, mapping|
163
+ class_name = model_class.name
166
164
 
167
- fixture_name = class_name.underscore.gsub("/", "_")
168
- fixture_name = fixture_name.pluralize if ActiveRecord::Base.pluralize_table_names
165
+ fixture_name = class_name.underscore.gsub("/", "_")
166
+ fixture_name = fixture_name.pluralize if ActiveRecord::Base.pluralize_table_names
169
167
 
170
- mapping[fixture_name] = class_name
168
+ mapping[fixture_name] = class_name
171
169
 
172
- mapping
173
- end
174
- end,
175
- T.nilable(T::Hash[String, String]),
176
- )
170
+ mapping
171
+ end #: Hash[String, String]?
177
172
  end
178
173
 
179
- sig { returns(T::Hash[String, String]) }
174
+ #: -> Hash[String, String]
180
175
  def fixture_class_mapping_from_fixture_files
181
- @fixture_file_class_mapping ||= T.let(
182
- begin
183
- fixture_paths = if T.unsafe(fixture_loader).respond_to?(:fixture_paths)
184
- T.unsafe(fixture_loader).fixture_paths
185
- else
186
- T.unsafe(fixture_loader).fixture_path
187
- end
176
+ @fixture_file_class_mapping ||= begin
177
+ fixture_paths = if T.unsafe(fixture_loader).respond_to?(:fixture_paths)
178
+ T.unsafe(fixture_loader).fixture_paths
179
+ else
180
+ T.unsafe(fixture_loader).fixture_path
181
+ end
188
182
 
189
- Array(fixture_paths).each_with_object({}) do |path, mapping|
190
- Dir["#{path}{.yml,/{**,*}/*.yml}"].select do |file|
191
- next unless ::File.file?(file)
183
+ Array(fixture_paths).each_with_object({}) do |path, mapping|
184
+ Dir["#{path}{.yml,/{**,*}/*.yml}"].select do |file|
185
+ next unless ::File.file?(file)
192
186
 
193
- ActiveRecord::FixtureSet::File.open(file) do |fh|
194
- fixture_name = file.delete_prefix(path.to_s).delete_prefix("/").delete_suffix(".yml")
195
- next unless fh.model_class
187
+ ActiveRecord::FixtureSet::File.open(file) do |fh|
188
+ fixture_name = file.delete_prefix(path.to_s).delete_prefix("/").delete_suffix(".yml")
189
+ next unless fh.model_class
196
190
 
197
- mapping[fixture_name] = fh.model_class
198
- rescue ActiveRecord::Fixture::FormatError
199
- # For fixtures that are not associated to any models and just contain raw data or fixtures that
200
- # contain invalid formatting, we want to skip them and avoid crashing
201
- mapping[fixture_name] = MISSING
202
- end
191
+ mapping[fixture_name] = fh.model_class
192
+ rescue ActiveRecord::Fixture::FormatError
193
+ # For fixtures that are not associated to any models and just contain raw data or fixtures that
194
+ # contain invalid formatting, we want to skip them and avoid crashing
195
+ mapping[fixture_name] = MISSING
203
196
  end
204
197
  end
205
- end,
206
- T.nilable(T::Hash[String, String]),
207
- )
198
+ end
199
+ end #: Hash[String, String]?
208
200
  end
209
201
  end
210
202
  end