tapioca 0.6.1 → 0.7.0

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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +13 -2
  3. data/README.md +79 -25
  4. data/Rakefile +10 -14
  5. data/lib/tapioca/cli.rb +66 -80
  6. data/lib/tapioca/{generators/base.rb → commands/command.rb} +17 -10
  7. data/lib/tapioca/{generators → commands}/dsl.rb +59 -45
  8. data/lib/tapioca/{generators → commands}/gem.rb +93 -30
  9. data/lib/tapioca/{generators → commands}/init.rb +9 -13
  10. data/lib/tapioca/{generators → commands}/require.rb +8 -10
  11. data/lib/tapioca/commands/todo.rb +84 -0
  12. data/lib/tapioca/commands.rb +13 -0
  13. data/lib/tapioca/dsl/compiler.rb +185 -0
  14. data/lib/tapioca/{compilers/dsl → dsl/compilers}/aasm.rb +12 -9
  15. data/lib/tapioca/{compilers/dsl → dsl/compilers}/action_controller_helpers.rb +13 -20
  16. data/lib/tapioca/{compilers/dsl → dsl/compilers}/action_mailer.rb +10 -8
  17. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_job.rb +11 -9
  18. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_model_attributes.rb +32 -24
  19. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_model_secure_password.rb +10 -12
  20. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_associations.rb +29 -35
  21. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_columns.rb +26 -24
  22. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_enum.rb +14 -12
  23. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_fixtures.rb +10 -8
  24. data/lib/tapioca/dsl/compilers/active_record_relations.rb +712 -0
  25. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_scope.rb +21 -20
  26. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_typed_store.rb +12 -17
  27. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_resource.rb +10 -8
  28. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_storage.rb +11 -11
  29. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_support_concern.rb +19 -14
  30. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_support_current_attributes.rb +16 -21
  31. data/lib/tapioca/{compilers/dsl → dsl/compilers}/config.rb +10 -8
  32. data/lib/tapioca/{compilers/dsl → dsl/compilers}/frozen_record.rb +13 -11
  33. data/lib/tapioca/{compilers/dsl → dsl/compilers}/identity_cache.rb +28 -25
  34. data/lib/tapioca/{compilers/dsl → dsl/compilers}/mixed_in_class_attributes.rb +12 -10
  35. data/lib/tapioca/{compilers/dsl → dsl/compilers}/protobuf.rb +10 -8
  36. data/lib/tapioca/{compilers/dsl → dsl/compilers}/rails_generators.rb +13 -14
  37. data/lib/tapioca/{compilers/dsl → dsl/compilers}/sidekiq_worker.rb +14 -13
  38. data/lib/tapioca/{compilers/dsl → dsl/compilers}/smart_properties.rb +12 -13
  39. data/lib/tapioca/{compilers/dsl → dsl/compilers}/state_machines.rb +12 -10
  40. data/lib/tapioca/{compilers/dsl → dsl/compilers}/url_helpers.rb +16 -14
  41. data/lib/tapioca/dsl/compilers.rb +31 -0
  42. data/lib/tapioca/{compilers/dsl → dsl}/extensions/frozen_record.rb +2 -2
  43. data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +114 -0
  44. data/lib/tapioca/dsl/helpers/active_record_constants_helper.rb +29 -0
  45. data/lib/tapioca/{compilers/dsl → dsl/helpers}/param_helper.rb +2 -2
  46. data/lib/tapioca/{compilers/dsl_compiler.rb → dsl/pipeline.rb} +41 -33
  47. data/lib/tapioca/gem/events.rb +120 -0
  48. data/lib/tapioca/gem/listeners/base.rb +48 -0
  49. data/lib/tapioca/gem/listeners/dynamic_mixins.rb +32 -0
  50. data/lib/tapioca/gem/listeners/methods.rb +183 -0
  51. data/lib/tapioca/gem/listeners/mixins.rb +101 -0
  52. data/lib/tapioca/gem/listeners/remove_empty_payload_scopes.rb +21 -0
  53. data/lib/tapioca/gem/listeners/sorbet_enums.rb +26 -0
  54. data/lib/tapioca/gem/listeners/sorbet_helpers.rb +29 -0
  55. data/lib/tapioca/gem/listeners/sorbet_props.rb +33 -0
  56. data/lib/tapioca/gem/listeners/sorbet_required_ancestors.rb +23 -0
  57. data/lib/tapioca/gem/listeners/sorbet_signatures.rb +79 -0
  58. data/lib/tapioca/gem/listeners/sorbet_type_variables.rb +51 -0
  59. data/lib/tapioca/gem/listeners/subconstants.rb +37 -0
  60. data/lib/tapioca/gem/listeners/yard_doc.rb +96 -0
  61. data/lib/tapioca/gem/listeners.rb +16 -0
  62. data/lib/tapioca/gem/pipeline.rb +365 -0
  63. data/lib/tapioca/gemfile.rb +44 -20
  64. data/lib/tapioca/helpers/cli_helper.rb +16 -8
  65. data/lib/tapioca/helpers/config_helper.rb +113 -0
  66. data/lib/tapioca/helpers/rbi_helper.rb +17 -0
  67. data/lib/tapioca/helpers/shims_helper.rb +87 -0
  68. data/lib/tapioca/helpers/sorbet_helper.rb +57 -0
  69. data/lib/tapioca/helpers/test/dsl_compiler.rb +118 -0
  70. data/lib/tapioca/helpers/test/isolation.rb +1 -1
  71. data/lib/tapioca/helpers/test/template.rb +13 -2
  72. data/lib/tapioca/internal.rb +17 -10
  73. data/lib/tapioca/rbi_ext/model.rb +2 -48
  74. data/lib/tapioca/rbi_formatter.rb +37 -0
  75. data/lib/tapioca/runtime/dynamic_mixin_compiler.rb +227 -0
  76. data/lib/tapioca/runtime/generic_type_registry.rb +166 -0
  77. data/lib/tapioca/runtime/loader.rb +123 -0
  78. data/lib/tapioca/runtime/reflection.rb +153 -0
  79. data/lib/tapioca/runtime/trackers/autoload.rb +72 -0
  80. data/lib/tapioca/runtime/trackers/constant_definition.rb +44 -0
  81. data/lib/tapioca/runtime/trackers/mixin.rb +80 -0
  82. data/lib/tapioca/runtime/trackers/required_ancestor.rb +50 -0
  83. data/lib/tapioca/{trackers.rb → runtime/trackers.rb} +4 -3
  84. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +110 -54
  85. data/lib/tapioca/sorbet_ext/name_patch.rb +7 -1
  86. data/lib/tapioca/{compilers → static}/requires_compiler.rb +5 -12
  87. data/lib/tapioca/static/symbol_loader.rb +83 -0
  88. data/lib/tapioca/static/symbol_table_parser.rb +63 -0
  89. data/lib/tapioca/version.rb +1 -1
  90. data/lib/tapioca.rb +2 -7
  91. metadata +82 -62
  92. data/lib/tapioca/compilers/dsl/active_record_relations.rb +0 -711
  93. data/lib/tapioca/compilers/dsl/base.rb +0 -179
  94. data/lib/tapioca/compilers/dsl/helper/active_record_constants.rb +0 -27
  95. data/lib/tapioca/compilers/dynamic_mixin_compiler.rb +0 -198
  96. data/lib/tapioca/compilers/sorbet.rb +0 -59
  97. data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +0 -780
  98. data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +0 -90
  99. data/lib/tapioca/compilers/symbol_table_compiler.rb +0 -17
  100. data/lib/tapioca/compilers/todos_compiler.rb +0 -32
  101. data/lib/tapioca/generators/todo.rb +0 -76
  102. data/lib/tapioca/generators.rb +0 -9
  103. data/lib/tapioca/generic_type_registry.rb +0 -149
  104. data/lib/tapioca/helpers/active_record_column_type_helper.rb +0 -98
  105. data/lib/tapioca/loader.rb +0 -119
  106. data/lib/tapioca/reflection.rb +0 -151
  107. data/lib/tapioca/trackers/autoload.rb +0 -70
  108. data/lib/tapioca/trackers/constant_definition.rb +0 -42
  109. data/lib/tapioca/trackers/mixin.rb +0 -78
@@ -5,14 +5,16 @@ begin
5
5
  require "identity_cache"
6
6
  rescue LoadError
7
7
  # means IdentityCache is not installed,
8
- # so let's not even define the generator.
8
+ # so let's not even define the compiler.
9
9
  return
10
10
  end
11
11
 
12
+ require "tapioca/dsl/helpers/active_record_column_type_helper"
13
+
12
14
  module Tapioca
13
- module Compilers
14
- module Dsl
15
- # `Tapioca::Compilers::DSL::IdentityCache` generates RBI files for Active Record models
15
+ module Dsl
16
+ module Compilers
17
+ # `Tapioca::Dsl::Compilers::IdentityCache` generates RBI files for Active Record models
16
18
  # that use `include IdentityCache`.
17
19
  # [`IdentityCache`](https://github.com/Shopify/identity_cache) is a blob level caching solution
18
20
  # to plug into Active Record.
@@ -31,7 +33,7 @@ module Tapioca
31
33
  # end
32
34
  # ~~~
33
35
  #
34
- # this generator will produce the RBI file `post.rbi` with the following content:
36
+ # this compiler will produce the RBI file `post.rbi` with the following content:
35
37
  #
36
38
  # ~~~rbi
37
39
  # # post.rbi
@@ -59,7 +61,7 @@ module Tapioca
59
61
  # def fetch_by_title_and_review_date(title, review_date, includes: nil); end
60
62
  # end
61
63
  # ~~~
62
- class IdentityCache < Base
64
+ class IdentityCache < Compiler
63
65
  extend T::Sig
64
66
 
65
67
  COLLECTION_TYPE = T.let(
@@ -67,8 +69,10 @@ module Tapioca
67
69
  T.proc.params(type: T.any(Module, String)).returns(String)
68
70
  )
69
71
 
70
- sig { override.params(root: RBI::Tree, constant: T.class_of(::ActiveRecord::Base)).void }
71
- def decorate(root, constant)
72
+ ConstantType = type_member(fixed: T.class_of(::ActiveRecord::Base))
73
+
74
+ sig { override.void }
75
+ def decorate
72
76
  caches = constant.send(:all_cached_associations)
73
77
  cache_indexes = constant.send(:cache_indexes)
74
78
  return if caches.empty? && cache_indexes.empty?
@@ -79,7 +83,7 @@ module Tapioca
79
83
  cache_belongs = constant.send(:cached_belongs_tos)
80
84
 
81
85
  cache_indexes.each do |field|
82
- create_fetch_by_methods(field, model, constant)
86
+ create_fetch_by_methods(field, model)
83
87
  end
84
88
 
85
89
  cache_manys.values.each do |field|
@@ -97,7 +101,7 @@ module Tapioca
97
101
  end
98
102
 
99
103
  sig { override.returns(T::Enumerable[Module]) }
100
- def gather_constants
104
+ def self.gather_constants
101
105
  descendants_of(::ActiveRecord::Base).select do |klass|
102
106
  klass < ::IdentityCache::WithoutPrimaryIndex
103
107
  end
@@ -116,7 +120,7 @@ module Tapioca
116
120
  if returns_collection
117
121
  COLLECTION_TYPE.call(cache_type)
118
122
  else
119
- "T.nilable(::#{cache_type})"
123
+ as_nilable_type(T.must(qualified_name_of(cache_type)))
120
124
  end
121
125
  rescue ArgumentError
122
126
  "T.untyped"
@@ -144,28 +148,26 @@ module Tapioca
144
148
  sig do
145
149
  params(
146
150
  field: T.untyped,
147
- klass: RBI::Scope,
148
- constant: T.class_of(::ActiveRecord::Base),
151
+ klass: RBI::Scope
149
152
  ).void
150
153
  end
151
- def create_fetch_by_methods(field, klass, constant)
154
+ def create_fetch_by_methods(field, klass)
152
155
  is_cache_index = field.instance_variable_defined?(:@attribute_proc)
153
156
 
154
157
  # Both `cache_index` and `cache_attribute` generate aliased methods
155
- create_aliased_fetch_by_methods(field, klass, constant)
158
+ create_aliased_fetch_by_methods(field, klass)
156
159
 
157
160
  # If the method used was `cache_index` a few extra methods are created
158
- create_index_fetch_by_methods(field, klass, constant) if is_cache_index
161
+ create_index_fetch_by_methods(field, klass) if is_cache_index
159
162
  end
160
163
 
161
164
  sig do
162
165
  params(
163
166
  field: T.untyped,
164
- klass: RBI::Scope,
165
- constant: T.class_of(::ActiveRecord::Base),
167
+ klass: RBI::Scope
166
168
  ).void
167
169
  end
168
- def create_index_fetch_by_methods(field, klass, constant)
170
+ def create_index_fetch_by_methods(field, klass)
169
171
  field_length = field.key_fields.length
170
172
  fields_name = field.key_fields.join("_and_")
171
173
  name = "fetch_by_#{fields_name}"
@@ -175,18 +177,20 @@ module Tapioca
175
177
  parameters << create_kw_opt_param("includes", default: "nil", type: "T.untyped")
176
178
 
177
179
  if field.unique
180
+ type = T.must(qualified_name_of(constant))
181
+
178
182
  klass.create_method(
179
183
  "#{name}!",
180
184
  class_method: true,
181
185
  parameters: parameters,
182
- return_type: "::#{constant}"
186
+ return_type: type
183
187
  )
184
188
 
185
189
  klass.create_method(
186
190
  name,
187
191
  class_method: true,
188
192
  parameters: parameters,
189
- return_type: "T.nilable(::#{constant})"
193
+ return_type: as_nilable_type(type)
190
194
  )
191
195
  else
192
196
  klass.create_method(
@@ -213,12 +217,11 @@ module Tapioca
213
217
  sig do
214
218
  params(
215
219
  field: T.untyped,
216
- klass: RBI::Scope,
217
- constant: T.class_of(::ActiveRecord::Base),
220
+ klass: RBI::Scope
218
221
  ).void
219
222
  end
220
- def create_aliased_fetch_by_methods(field, klass, constant)
221
- type, _ = ActiveRecordColumnTypeHelper.new(constant).type_for(field.alias_name.to_s)
223
+ def create_aliased_fetch_by_methods(field, klass)
224
+ type, _ = Helpers::ActiveRecordColumnTypeHelper.new(constant).type_for(field.alias_name.to_s)
222
225
  multi_type = type.delete_prefix("T.nilable(").delete_suffix(")").delete_prefix("::")
223
226
  length = field.key_fields.length
224
227
  suffix = field.send(:fetch_method_suffix)
@@ -8,9 +8,9 @@ rescue LoadError
8
8
  end
9
9
 
10
10
  module Tapioca
11
- module Compilers
12
- module Dsl
13
- # `Tapioca::Compilers::Dsl::MixedInClassAttributes` generates RBI files for modules that dynamically use
11
+ module Dsl
12
+ module Compilers
13
+ # `Tapioca::Dsl::Compilers::MixedInClassAttributes` generates RBI files for modules that dynamically use
14
14
  # `class_attribute` on classes.
15
15
  #
16
16
  # For example, given the following concern
@@ -25,7 +25,7 @@ module Tapioca
25
25
  # end
26
26
  # ~~~
27
27
  #
28
- # this generator will produce the RBI file `taggeable.rbi` with the following content:
28
+ # this compiler will produce the RBI file `taggeable.rbi` with the following content:
29
29
  #
30
30
  # ~~~rbi
31
31
  # # typed: strong
@@ -48,12 +48,14 @@ module Tapioca
48
48
  # end
49
49
  # end
50
50
  # ~~~
51
- class MixedInClassAttributes < Base
51
+ class MixedInClassAttributes < Compiler
52
52
  extend T::Sig
53
53
 
54
- sig { override.params(root: RBI::Tree, constant: Module).void }
55
- def decorate(root, constant)
56
- mixin_compiler = DynamicMixinCompiler.new(constant)
54
+ ConstantType = type_member(fixed: Module)
55
+
56
+ sig { override.void }
57
+ def decorate
58
+ mixin_compiler = Runtime::DynamicMixinCompiler.new(constant)
57
59
  return if mixin_compiler.empty_attributes?
58
60
 
59
61
  root.create_path(constant) do |mod|
@@ -62,10 +64,10 @@ module Tapioca
62
64
  end
63
65
 
64
66
  sig { override.returns(T::Enumerable[Module]) }
65
- def gather_constants
67
+ def self.gather_constants
66
68
  # Select all non-anonymous modules that have overridden Module.included
67
69
  all_modules.select do |mod|
68
- !mod.is_a?(Class) && name_of(mod) && Tapioca::Reflection.method_of(mod, :included).owner != Module
70
+ !mod.is_a?(Class) && name_of(mod) && Runtime::Reflection.method_of(mod, :included).owner != Module
69
71
  end
70
72
  end
71
73
  end
@@ -8,9 +8,9 @@ rescue LoadError
8
8
  end
9
9
 
10
10
  module Tapioca
11
- module Compilers
12
- module Dsl
13
- # `Tapioca::Compilers::Dsl::Protobuf` decorates RBI files for subclasses of
11
+ module Dsl
12
+ module Compilers
13
+ # `Tapioca::Dsl::Compilers::Protobuf` decorates RBI files for subclasses of
14
14
  # [`Google::Protobuf::MessageExts`](https://github.com/protocolbuffers/protobuf/tree/master/ruby).
15
15
  #
16
16
  # For example, with the following "cart.rb" file:
@@ -28,7 +28,7 @@ module Tapioca
28
28
  # end
29
29
  # ~~~
30
30
  #
31
- # this generator will produce the RBI file `cart.rbi` with the following content:
31
+ # this compiler will produce the RBI file `cart.rbi` with the following content:
32
32
  #
33
33
  # ~~~rbi
34
34
  # # cart.rbi
@@ -60,7 +60,7 @@ module Tapioca
60
60
  # def number_value=(value); end
61
61
  # end
62
62
  # ~~~
63
- class Protobuf < Base
63
+ class Protobuf < Compiler
64
64
  class Field < T::Struct
65
65
  prop :name, String
66
66
  prop :type, String
@@ -70,8 +70,10 @@ module Tapioca
70
70
 
71
71
  extend T::Sig
72
72
 
73
- sig { override.params(root: RBI::Tree, constant: Module).void }
74
- def decorate(root, constant)
73
+ ConstantType = type_member(fixed: Module)
74
+
75
+ sig { override.void }
76
+ def decorate
75
77
  root.create_path(constant) do |klass|
76
78
  if constant == Google::Protobuf::RepeatedField
77
79
  create_type_members(klass, "Elem")
@@ -92,7 +94,7 @@ module Tapioca
92
94
  end
93
95
 
94
96
  sig { override.returns(T::Enumerable[Module]) }
95
- def gather_constants
97
+ def self.gather_constants
96
98
  marker = Google::Protobuf::MessageExts::ClassMethods
97
99
  results = T.cast(ObjectSpace.each_object(marker).to_a, T::Array[Module])
98
100
  results.any? ? results + [Google::Protobuf::RepeatedField, Google::Protobuf::Map] : []
@@ -9,9 +9,9 @@ rescue LoadError
9
9
  end
10
10
 
11
11
  module Tapioca
12
- module Compilers
13
- module Dsl
14
- # `Tapioca::Compilers::Dsl::RailsGenerators` generates RBI files for Rails generators
12
+ module Dsl
13
+ module Compilers
14
+ # `Tapioca::Dsl::Compilers::RailsGenerators` generates RBI files for Rails generators
15
15
  #
16
16
  # For example, with the following generator:
17
17
  #
@@ -38,7 +38,7 @@ module Tapioca
38
38
  # def skip_comments; end
39
39
  # end
40
40
  # ~~~
41
- class RailsGenerators < Base
41
+ class RailsGenerators < Compiler
42
42
  extend T::Sig
43
43
 
44
44
  BUILT_IN_MATCHER = T.let(
@@ -46,9 +46,11 @@ module Tapioca
46
46
  Regexp
47
47
  )
48
48
 
49
- sig { override.params(root: RBI::Tree, constant: T.class_of(::Rails::Generators::Base)).void }
50
- def decorate(root, constant)
51
- base_class = base_class_for(constant)
49
+ ConstantType = type_member(fixed: T.class_of(::Rails::Generators::Base))
50
+
51
+ sig { override.void }
52
+ def decorate
53
+ base_class = base_class_of_constant
52
54
  arguments = constant.arguments - base_class.arguments
53
55
  class_options = constant.class_options.reject do |name, option|
54
56
  base_class.class_options[name] == option
@@ -63,7 +65,7 @@ module Tapioca
63
65
  end
64
66
 
65
67
  sig { override.returns(T::Enumerable[Module]) }
66
- def gather_constants
68
+ def self.gather_constants
67
69
  all_classes.select do |const|
68
70
  name = qualified_name_of(const)
69
71
 
@@ -84,11 +86,8 @@ module Tapioca
84
86
  )
85
87
  end
86
88
 
87
- sig do
88
- params(constant: T.class_of(::Rails::Generators::Base))
89
- .returns(T.class_of(::Rails::Generators::Base))
90
- end
91
- def base_class_for(constant)
89
+ sig { returns(T.class_of(::Rails::Generators::Base)) }
90
+ def base_class_of_constant
92
91
  ancestor = inherited_ancestors_of(constant).find do |klass|
93
92
  qualified_name_of(klass)&.match?(BUILT_IN_MATCHER)
94
93
  end
@@ -111,7 +110,7 @@ module Tapioca
111
110
  if arg.required || arg.default
112
111
  type
113
112
  else
114
- "T.nilable(#{type})"
113
+ as_nilable_type(type)
115
114
  end
116
115
  end
117
116
  end
@@ -8,9 +8,9 @@ rescue LoadError
8
8
  end
9
9
 
10
10
  module Tapioca
11
- module Compilers
12
- module Dsl
13
- # `Tapioca::Compilers::Dsl::SidekiqWorker` generates RBI files classes that include
11
+ module Dsl
12
+ module Compilers
13
+ # `Tapioca::Dsl::Compilers::SidekiqWorker` generates RBI files classes that include
14
14
  # [`Sidekiq::Worker`](https://github.com/mperham/sidekiq/wiki/Getting-Started).
15
15
  #
16
16
  # For example, with the following class that includes `Sidekiq::Worker`:
@@ -24,7 +24,7 @@ module Tapioca
24
24
  # end
25
25
  # ~~~
26
26
  #
27
- # this generator will produce the RBI file `notifier_worker.rbi` with the following content:
27
+ # this compiler will produce the RBI file `notifier_worker.rbi` with the following content:
28
28
  #
29
29
  # ~~~rbi
30
30
  # # notifier_worker.rbi
@@ -40,11 +40,13 @@ module Tapioca
40
40
  # def self.perform_in(interval, customer_id); end
41
41
  # end
42
42
  # ~~~
43
- class SidekiqWorker < Base
43
+ class SidekiqWorker < Compiler
44
44
  extend T::Sig
45
45
 
46
- sig { override.params(root: RBI::Tree, constant: T.class_of(::Sidekiq::Worker)).void }
47
- def decorate(root, constant)
46
+ ConstantType = type_member(fixed: T.class_of(::Sidekiq::Worker))
47
+
48
+ sig { override.void }
49
+ def decorate
48
50
  return unless constant.instance_methods.include?(:perform)
49
51
 
50
52
  root.create_path(constant) do |worker|
@@ -64,14 +66,14 @@ module Tapioca
64
66
  *async_params,
65
67
  ]
66
68
 
67
- generate_perform_method(constant, worker, "perform_async", async_params)
68
- generate_perform_method(constant, worker, "perform_at", at_params)
69
- generate_perform_method(constant, worker, "perform_in", in_params)
69
+ generate_perform_method(worker, "perform_async", async_params)
70
+ generate_perform_method(worker, "perform_at", at_params)
71
+ generate_perform_method(worker, "perform_in", in_params)
70
72
  end
71
73
  end
72
74
 
73
75
  sig { override.returns(T::Enumerable[Module]) }
74
- def gather_constants
76
+ def self.gather_constants
75
77
  all_classes.select { |c| c < Sidekiq::Worker }
76
78
  end
77
79
 
@@ -79,13 +81,12 @@ module Tapioca
79
81
 
80
82
  sig do
81
83
  params(
82
- constant: T.class_of(::Sidekiq::Worker),
83
84
  worker: RBI::Scope,
84
85
  method_name: String,
85
86
  parameters: T::Array[RBI::TypedParam]
86
87
  ).void
87
88
  end
88
- def generate_perform_method(constant, worker, method_name, parameters)
89
+ def generate_perform_method(worker, method_name, parameters)
89
90
  if constant.method(method_name.to_sym).owner == Sidekiq::Worker::ClassMethods
90
91
  worker.create_method(method_name, parameters: parameters, return_type: "String", class_method: true)
91
92
  end
@@ -5,14 +5,14 @@ begin
5
5
  require "smart_properties"
6
6
  rescue LoadError
7
7
  # means SmartProperties is not installed,
8
- # so let's not even define the generator.
8
+ # so let's not even define the compiler.
9
9
  return
10
10
  end
11
11
 
12
12
  module Tapioca
13
- module Compilers
14
- module Dsl
15
- # `Tapioca::Compilers::Dsl::SmartProperties` generates RBI files for classes that include
13
+ module Dsl
14
+ module Compilers
15
+ # `Tapioca::Dsl::Compilers::SmartProperties` generates RBI files for classes that include
16
16
  # [`SmartProperties`](https://github.com/t6d/smart_properties).
17
17
  #
18
18
  # For example, with the following class that includes `SmartProperties`:
@@ -29,7 +29,7 @@ module Tapioca
29
29
  # end
30
30
  # ~~~
31
31
  #
32
- # this generator will produce the RBI file `post.rbi` with the following content:
32
+ # this compiler will produce the RBI file `post.rbi` with the following content:
33
33
  #
34
34
  # ~~~rbi
35
35
  # # post.rbi
@@ -60,11 +60,13 @@ module Tapioca
60
60
  # def enabled=(enabled); end
61
61
  # end
62
62
  # ~~~
63
- class SmartProperties < Base
63
+ class SmartProperties < Compiler
64
64
  extend T::Sig
65
65
 
66
- sig { override.params(root: RBI::Tree, constant: T.class_of(::SmartProperties)).void }
67
- def decorate(root, constant)
66
+ ConstantType = type_member(fixed: T.class_of(::SmartProperties))
67
+
68
+ sig { override.void }
69
+ def decorate
68
70
  properties = T.let(
69
71
  T.unsafe(constant).properties,
70
72
  ::SmartProperties::PropertyCollection
@@ -84,7 +86,7 @@ module Tapioca
84
86
  end
85
87
 
86
88
  sig { override.returns(T::Enumerable[Module]) }
87
- def gather_constants
89
+ def self.gather_constants
88
90
  all_modules.select do |c|
89
91
  name_of(c) &&
90
92
  c != ::SmartProperties::Validations::Ancestor &&
@@ -143,11 +145,8 @@ module Tapioca
143
145
  "T.untyped"
144
146
  end
145
147
 
146
- # Early return for "T.untyped", nothing more to do.
147
- return type if type == "T.untyped"
148
-
149
148
  might_be_optional = Proc === required || !required
150
- type = "T.nilable(#{type})" if might_be_optional
149
+ type = as_nilable_type(type) if might_be_optional
151
150
 
152
151
  type
153
152
  end
@@ -5,15 +5,15 @@ begin
5
5
  require "state_machines"
6
6
  rescue LoadError
7
7
  # means StateMachines is not installed,
8
- # so let's not even define the generator.
8
+ # so let's not even define the compiler.
9
9
  return
10
10
  end
11
11
 
12
12
  module Tapioca
13
- module Compilers
14
- module Dsl
15
- # `Tapioca::Compilers::Dsl::StateMachines` generates RBI files for classes that setup a
16
- # [`state_machine`](https://github.com/state-machines/state_machines). The generator also
13
+ module Dsl
14
+ module Compilers
15
+ # `Tapioca::Dsl::Compilers::StateMachines` generates RBI files for classes that setup a
16
+ # [`state_machine`](https://github.com/state-machines/state_machines). The compiler also
17
17
  # processes the extra methods generated by
18
18
  # [StateMachines Active Record](https://github.com/state-machines/state_machines-activerecord)
19
19
  # and [StateMachines Active Model](https://github.com/state-machines/state_machines-activemodel)
@@ -38,7 +38,7 @@ module Tapioca
38
38
  # end
39
39
  # ~~~
40
40
  #
41
- # this generator will produce the RBI file `vehicle.rbi` with the following content:
41
+ # this compiler will produce the RBI file `vehicle.rbi` with the following content:
42
42
  #
43
43
  # ~~~rbi
44
44
  # # vehicle.rbi
@@ -115,11 +115,13 @@ module Tapioca
115
115
  # end
116
116
  # end
117
117
  # ~~~
118
- class StateMachines < Base
118
+ class StateMachines < Compiler
119
119
  extend T::Sig
120
120
 
121
- sig { override.params(root: RBI::Tree, constant: ::StateMachines::ClassMethods).void }
122
- def decorate(root, constant)
121
+ ConstantType = type_member(fixed: T.all(Module, ::StateMachines::ClassMethods))
122
+
123
+ sig { override.void }
124
+ def decorate
123
125
  return if constant.state_machines.empty?
124
126
 
125
127
  root.create_path(T.unsafe(constant)) do |klass|
@@ -159,7 +161,7 @@ module Tapioca
159
161
  end
160
162
 
161
163
  sig { override.returns(T::Enumerable[Module]) }
162
- def gather_constants
164
+ def self.gather_constants
163
165
  all_classes.select { |mod| mod < ::StateMachines::InstanceMethods }
164
166
  end
165
167
 
@@ -10,9 +10,9 @@ rescue LoadError
10
10
  end
11
11
 
12
12
  module Tapioca
13
- module Compilers
14
- module Dsl
15
- # `Tapioca::Compilers::Dsl::UrlHelpers` generates RBI files for classes that include or extend
13
+ module Dsl
14
+ module Compilers
15
+ # `Tapioca::Dsl::Compilers::UrlHelpers` generates RBI files for classes that include or extend
16
16
  # [`Rails.application.routes.url_helpers`](https://api.rubyonrails.org/v5.1.7/classes/ActionDispatch/Routing/UrlFor.html#module-ActionDispatch::Routing::UrlFor-label-URL+generation+for+named+routes).
17
17
  #
18
18
  # For example, with the following setup:
@@ -32,13 +32,13 @@ module Tapioca
32
32
  # # Use `T.unsafe` so that Sorbet does not complain about a dynamic
33
33
  # # module being included. This allows the `include` to happen properly
34
34
  # # at runtime but Sorbet won't see the include. However, since this
35
- # # generator will generate the proper RBI files for the include,
35
+ # # compiler will generate the proper RBI files for the include,
36
36
  # # static type checking will work as expected.
37
37
  # T.unsafe(self).include Rails.application.routes.url_helpers
38
38
  # end
39
39
  # ~~~
40
40
  #
41
- # this generator will produce the following RBI files:
41
+ # this compiler will produce the following RBI files:
42
42
  #
43
43
  # ~~~rbi
44
44
  # # generated_path_helpers_module.rbi
@@ -84,18 +84,20 @@ module Tapioca
84
84
  # include GeneratedUrlHelpersModule
85
85
  # end
86
86
  # ~~~
87
- class UrlHelpers < Base
87
+ class UrlHelpers < Compiler
88
88
  extend T::Sig
89
89
 
90
- sig { override.params(root: RBI::Tree, constant: Module).void }
91
- def decorate(root, constant)
90
+ ConstantType = type_member(fixed: Module)
91
+
92
+ sig { override.void }
93
+ def decorate
92
94
  case constant
93
95
  when GeneratedPathHelpersModule.singleton_class, GeneratedUrlHelpersModule.singleton_class
94
96
  generate_module_for(root, constant)
95
97
  else
96
98
  root.create_path(constant) do |mod|
97
- create_mixins_for(mod, constant, GeneratedUrlHelpersModule)
98
- create_mixins_for(mod, constant, GeneratedPathHelpersModule)
99
+ create_mixins_for(mod, GeneratedUrlHelpersModule)
100
+ create_mixins_for(mod, GeneratedPathHelpersModule)
99
101
  end
100
102
  end
101
103
  end
@@ -106,7 +108,7 @@ module Tapioca
106
108
  ], T::Array[Module])
107
109
 
108
110
  sig { override.returns(T::Enumerable[Module]) }
109
- def gather_constants
111
+ def self.gather_constants
110
112
  Object.const_set(:GeneratedUrlHelpersModule, Rails.application.routes.named_routes.url_helpers_module)
111
113
  Object.const_set(:GeneratedPathHelpersModule, Rails.application.routes.named_routes.path_helpers_module)
112
114
 
@@ -140,8 +142,8 @@ module Tapioca
140
142
  end
141
143
  end
142
144
 
143
- sig { params(mod: RBI::Scope, constant: Module, helper_module: Module).void }
144
- def create_mixins_for(mod, constant, helper_module)
145
+ sig { params(mod: RBI::Scope, helper_module: Module).void }
146
+ def create_mixins_for(mod, helper_module)
145
147
  include_helper = constant.ancestors.include?(helper_module) || NON_DISCOVERABLE_INCLUDERS.include?(constant)
146
148
  extend_helper = constant.singleton_class.ancestors.include?(helper_module)
147
149
 
@@ -150,7 +152,7 @@ module Tapioca
150
152
  end
151
153
 
152
154
  sig { params(mod: Module, helper: Module).returns(T::Boolean) }
153
- def includes_helper?(mod, helper)
155
+ private_class_method def self.includes_helper?(mod, helper)
154
156
  superclass_ancestors = []
155
157
 
156
158
  if Class === mod
@@ -0,0 +1,31 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "tapioca/rbi_ext/model"
5
+ require "tapioca/dsl/helpers/param_helper"
6
+ require "tapioca/dsl/pipeline"
7
+
8
+ module Tapioca
9
+ module Dsl
10
+ module Compilers
11
+ DIRECTORY = T.let(
12
+ File.expand_path("compilers", __dir__),
13
+ String
14
+ )
15
+
16
+ # DSL compilers are either built-in to Tapioca and live under the
17
+ # `Tapioca::Dsl::Compilers` namespace (i.e. this namespace), and
18
+ # can be referred to by just using the class name, or they live in
19
+ # a different namespace and can only be referred to using their fully
20
+ # qualified name. This constant encapsulates that dual lookup when
21
+ # a compiler needs to be resolved by name.
22
+ NAMESPACES = T.let(
23
+ [
24
+ "#{name}::", # compilers in this namespace
25
+ "::", # compilers that need to be fully namespaced
26
+ ],
27
+ T::Array[String]
28
+ )
29
+ end
30
+ end
31
+ end
@@ -8,8 +8,8 @@ rescue LoadError
8
8
  end
9
9
 
10
10
  module Tapioca
11
- module Compilers
12
- module Dsl
11
+ module Dsl
12
+ module Compilers
13
13
  module Extensions
14
14
  module FrozenRecord
15
15
  attr_reader :__tapioca_scope_names