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.
- checksums.yaml +4 -4
- data/Gemfile +13 -2
- data/README.md +79 -25
- data/Rakefile +10 -14
- data/lib/tapioca/cli.rb +66 -80
- data/lib/tapioca/{generators/base.rb → commands/command.rb} +17 -10
- data/lib/tapioca/{generators → commands}/dsl.rb +59 -45
- data/lib/tapioca/{generators → commands}/gem.rb +93 -30
- data/lib/tapioca/{generators → commands}/init.rb +9 -13
- data/lib/tapioca/{generators → commands}/require.rb +8 -10
- data/lib/tapioca/commands/todo.rb +84 -0
- data/lib/tapioca/commands.rb +13 -0
- data/lib/tapioca/dsl/compiler.rb +185 -0
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/aasm.rb +12 -9
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/action_controller_helpers.rb +13 -20
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/action_mailer.rb +10 -8
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_job.rb +11 -9
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_model_attributes.rb +32 -24
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_model_secure_password.rb +10 -12
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_associations.rb +29 -35
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_columns.rb +26 -24
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_enum.rb +14 -12
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_fixtures.rb +10 -8
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +712 -0
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_scope.rb +21 -20
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_typed_store.rb +12 -17
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_resource.rb +10 -8
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_storage.rb +11 -11
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_support_concern.rb +19 -14
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_support_current_attributes.rb +16 -21
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/config.rb +10 -8
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/frozen_record.rb +13 -11
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/identity_cache.rb +28 -25
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/mixed_in_class_attributes.rb +12 -10
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/protobuf.rb +10 -8
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/rails_generators.rb +13 -14
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/sidekiq_worker.rb +14 -13
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/smart_properties.rb +12 -13
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/state_machines.rb +12 -10
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/url_helpers.rb +16 -14
- data/lib/tapioca/dsl/compilers.rb +31 -0
- data/lib/tapioca/{compilers/dsl → dsl}/extensions/frozen_record.rb +2 -2
- data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +114 -0
- data/lib/tapioca/dsl/helpers/active_record_constants_helper.rb +29 -0
- data/lib/tapioca/{compilers/dsl → dsl/helpers}/param_helper.rb +2 -2
- data/lib/tapioca/{compilers/dsl_compiler.rb → dsl/pipeline.rb} +41 -33
- data/lib/tapioca/gem/events.rb +120 -0
- data/lib/tapioca/gem/listeners/base.rb +48 -0
- data/lib/tapioca/gem/listeners/dynamic_mixins.rb +32 -0
- data/lib/tapioca/gem/listeners/methods.rb +183 -0
- data/lib/tapioca/gem/listeners/mixins.rb +101 -0
- data/lib/tapioca/gem/listeners/remove_empty_payload_scopes.rb +21 -0
- data/lib/tapioca/gem/listeners/sorbet_enums.rb +26 -0
- data/lib/tapioca/gem/listeners/sorbet_helpers.rb +29 -0
- data/lib/tapioca/gem/listeners/sorbet_props.rb +33 -0
- data/lib/tapioca/gem/listeners/sorbet_required_ancestors.rb +23 -0
- data/lib/tapioca/gem/listeners/sorbet_signatures.rb +79 -0
- data/lib/tapioca/gem/listeners/sorbet_type_variables.rb +51 -0
- data/lib/tapioca/gem/listeners/subconstants.rb +37 -0
- data/lib/tapioca/gem/listeners/yard_doc.rb +96 -0
- data/lib/tapioca/gem/listeners.rb +16 -0
- data/lib/tapioca/gem/pipeline.rb +365 -0
- data/lib/tapioca/gemfile.rb +44 -20
- data/lib/tapioca/helpers/cli_helper.rb +16 -8
- data/lib/tapioca/helpers/config_helper.rb +113 -0
- data/lib/tapioca/helpers/rbi_helper.rb +17 -0
- data/lib/tapioca/helpers/shims_helper.rb +87 -0
- data/lib/tapioca/helpers/sorbet_helper.rb +57 -0
- data/lib/tapioca/helpers/test/dsl_compiler.rb +118 -0
- data/lib/tapioca/helpers/test/isolation.rb +1 -1
- data/lib/tapioca/helpers/test/template.rb +13 -2
- data/lib/tapioca/internal.rb +17 -10
- data/lib/tapioca/rbi_ext/model.rb +2 -48
- data/lib/tapioca/rbi_formatter.rb +37 -0
- data/lib/tapioca/runtime/dynamic_mixin_compiler.rb +227 -0
- data/lib/tapioca/runtime/generic_type_registry.rb +166 -0
- data/lib/tapioca/runtime/loader.rb +123 -0
- data/lib/tapioca/runtime/reflection.rb +153 -0
- data/lib/tapioca/runtime/trackers/autoload.rb +72 -0
- data/lib/tapioca/runtime/trackers/constant_definition.rb +44 -0
- data/lib/tapioca/runtime/trackers/mixin.rb +80 -0
- data/lib/tapioca/runtime/trackers/required_ancestor.rb +50 -0
- data/lib/tapioca/{trackers.rb → runtime/trackers.rb} +4 -3
- data/lib/tapioca/sorbet_ext/generic_name_patch.rb +110 -54
- data/lib/tapioca/sorbet_ext/name_patch.rb +7 -1
- data/lib/tapioca/{compilers → static}/requires_compiler.rb +5 -12
- data/lib/tapioca/static/symbol_loader.rb +83 -0
- data/lib/tapioca/static/symbol_table_parser.rb +63 -0
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +2 -7
- metadata +82 -62
- data/lib/tapioca/compilers/dsl/active_record_relations.rb +0 -711
- data/lib/tapioca/compilers/dsl/base.rb +0 -179
- data/lib/tapioca/compilers/dsl/helper/active_record_constants.rb +0 -27
- data/lib/tapioca/compilers/dynamic_mixin_compiler.rb +0 -198
- data/lib/tapioca/compilers/sorbet.rb +0 -59
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +0 -780
- data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +0 -90
- data/lib/tapioca/compilers/symbol_table_compiler.rb +0 -17
- data/lib/tapioca/compilers/todos_compiler.rb +0 -32
- data/lib/tapioca/generators/todo.rb +0 -76
- data/lib/tapioca/generators.rb +0 -9
- data/lib/tapioca/generic_type_registry.rb +0 -149
- data/lib/tapioca/helpers/active_record_column_type_helper.rb +0 -98
- data/lib/tapioca/loader.rb +0 -119
- data/lib/tapioca/reflection.rb +0 -151
- data/lib/tapioca/trackers/autoload.rb +0 -70
- data/lib/tapioca/trackers/constant_definition.rb +0 -42
- 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
|
|
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
|
|
14
|
-
module
|
|
15
|
-
# `Tapioca::Compilers::
|
|
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
|
|
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 <
|
|
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
|
-
|
|
71
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
12
|
-
module
|
|
13
|
-
# `Tapioca::Compilers::
|
|
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
|
|
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 <
|
|
51
|
+
class MixedInClassAttributes < Compiler
|
|
52
52
|
extend T::Sig
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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) &&
|
|
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
|
|
12
|
-
module
|
|
13
|
-
# `Tapioca::Compilers::
|
|
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
|
|
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 <
|
|
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
|
-
|
|
74
|
-
|
|
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
|
|
13
|
-
module
|
|
14
|
-
# `Tapioca::Compilers::
|
|
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 <
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
|
88
|
-
|
|
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
|
-
|
|
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
|
|
12
|
-
module
|
|
13
|
-
# `Tapioca::Compilers::
|
|
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
|
|
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 <
|
|
43
|
+
class SidekiqWorker < Compiler
|
|
44
44
|
extend T::Sig
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
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(
|
|
68
|
-
generate_perform_method(
|
|
69
|
-
generate_perform_method(
|
|
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(
|
|
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
|
|
8
|
+
# so let's not even define the compiler.
|
|
9
9
|
return
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
module Tapioca
|
|
13
|
-
module
|
|
14
|
-
module
|
|
15
|
-
# `Tapioca::Compilers::
|
|
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
|
|
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 <
|
|
63
|
+
class SmartProperties < Compiler
|
|
64
64
|
extend T::Sig
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
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 =
|
|
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
|
|
8
|
+
# so let's not even define the compiler.
|
|
9
9
|
return
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
module Tapioca
|
|
13
|
-
module
|
|
14
|
-
module
|
|
15
|
-
# `Tapioca::Compilers::
|
|
16
|
-
# [`state_machine`](https://github.com/state-machines/state_machines). The
|
|
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
|
|
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 <
|
|
118
|
+
class StateMachines < Compiler
|
|
119
119
|
extend T::Sig
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
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
|
|
14
|
-
module
|
|
15
|
-
# `Tapioca::Compilers::
|
|
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
|
-
# #
|
|
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
|
|
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 <
|
|
87
|
+
class UrlHelpers < Compiler
|
|
88
88
|
extend T::Sig
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
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,
|
|
98
|
-
create_mixins_for(mod,
|
|
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,
|
|
144
|
-
def create_mixins_for(mod,
|
|
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
|