tapioca 0.6.4 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +8 -2
- data/README.md +27 -15
- data/Rakefile +10 -14
- data/lib/tapioca/cli.rb +65 -80
- data/lib/tapioca/{generators/base.rb → commands/command.rb} +16 -9
- 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 +13 -11
- 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 +28 -34
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_columns.rb +18 -16
- 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 +11 -16
- 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 +23 -22
- 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 +12 -13
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/sidekiq_worker.rb +14 -13
- data/lib/tapioca/{compilers/dsl → dsl/compilers}/smart_properties.rb +11 -9
- 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/helpers/cli_helper.rb +7 -0
- data/lib/tapioca/helpers/config_helper.rb +5 -8
- 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 +33 -15
- data/lib/tapioca/sorbet_ext/name_patch.rb +7 -1
- data/lib/tapioca/{compilers → static}/requires_compiler.rb +2 -2
- 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 +80 -60
- data/lib/tapioca/compilers/dsl/active_record_relations.rb +0 -720
- data/lib/tapioca/compilers/dsl/base.rb +0 -195
- data/lib/tapioca/compilers/dsl/helper/active_record_constants.rb +0 -27
- data/lib/tapioca/compilers/dynamic_mixin_compiler.rb +0 -223
- 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 -164
- data/lib/tapioca/helpers/active_record_column_type_helper.rb +0 -108
- 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
@@ -1,195 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "tapioca/rbi_ext/model"
|
5
|
-
require "tapioca/compilers/dsl/param_helper"
|
6
|
-
require "tapioca/compilers/dsl_compiler"
|
7
|
-
|
8
|
-
module Tapioca
|
9
|
-
module Compilers
|
10
|
-
module Dsl
|
11
|
-
DSL_COMPILERS_DIR = T.let(File.expand_path("..", __FILE__).to_s, String)
|
12
|
-
|
13
|
-
class Base
|
14
|
-
extend T::Sig
|
15
|
-
extend T::Helpers
|
16
|
-
|
17
|
-
include Reflection
|
18
|
-
|
19
|
-
abstract!
|
20
|
-
|
21
|
-
sig { returns(T::Set[Module]) }
|
22
|
-
attr_reader :processable_constants
|
23
|
-
|
24
|
-
sig { returns(T::Array[String]) }
|
25
|
-
attr_reader :errors
|
26
|
-
|
27
|
-
sig { params(name: String).returns(T.nilable(T.class_of(Tapioca::Compilers::Dsl::Base))) }
|
28
|
-
def self.resolve(name)
|
29
|
-
# Try to find built-in tapioca generator first, then globally defined generator.
|
30
|
-
potentials = ["Tapioca::Compilers::Dsl::#{name}", name].map do |potential_name|
|
31
|
-
Object.const_get(potential_name)
|
32
|
-
rescue NameError
|
33
|
-
# Skip if we can't find generator by the potential name
|
34
|
-
nil
|
35
|
-
end
|
36
|
-
|
37
|
-
potentials.compact.first
|
38
|
-
end
|
39
|
-
|
40
|
-
sig { params(compiler: Tapioca::Compilers::DslCompiler).void }
|
41
|
-
def initialize(compiler)
|
42
|
-
@compiler = compiler
|
43
|
-
@processable_constants = T.let(Set.new(gather_constants), T::Set[Module])
|
44
|
-
@processable_constants.compare_by_identity
|
45
|
-
@errors = T.let([], T::Array[String])
|
46
|
-
end
|
47
|
-
|
48
|
-
sig { params(constant: Module).returns(T::Boolean) }
|
49
|
-
def handles?(constant)
|
50
|
-
processable_constants.include?(constant)
|
51
|
-
end
|
52
|
-
|
53
|
-
sig { params(generator_name: String).returns(T::Boolean) }
|
54
|
-
def generator_enabled?(generator_name)
|
55
|
-
@compiler.generator_enabled?(generator_name)
|
56
|
-
end
|
57
|
-
|
58
|
-
sig do
|
59
|
-
abstract
|
60
|
-
.type_parameters(:T)
|
61
|
-
.params(
|
62
|
-
tree: RBI::Tree,
|
63
|
-
constant: T.type_parameter(:T)
|
64
|
-
)
|
65
|
-
.void
|
66
|
-
end
|
67
|
-
def decorate(tree, constant); end
|
68
|
-
|
69
|
-
sig { abstract.returns(T::Enumerable[Module]) }
|
70
|
-
def gather_constants; end
|
71
|
-
|
72
|
-
# NOTE: This should eventually accept an `Error` object or `Exception` rather than simply a `String`.
|
73
|
-
sig { params(error: String).void }
|
74
|
-
def add_error(error)
|
75
|
-
@errors << error
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
sig { returns(T::Enumerable[Class]) }
|
81
|
-
def all_classes
|
82
|
-
@all_classes = T.let(@all_classes, T.nilable(T::Enumerable[Class]))
|
83
|
-
@all_classes ||= T.cast(ObjectSpace.each_object(Class), T::Enumerable[Class]).each
|
84
|
-
end
|
85
|
-
|
86
|
-
sig { returns(T::Enumerable[Module]) }
|
87
|
-
def all_modules
|
88
|
-
@all_modules = T.let(@all_modules, T.nilable(T::Enumerable[Module]))
|
89
|
-
@all_modules ||= T.cast(ObjectSpace.each_object(Module), T::Enumerable[Module]).each
|
90
|
-
end
|
91
|
-
|
92
|
-
# Get the types of each parameter from a method signature
|
93
|
-
sig do
|
94
|
-
params(
|
95
|
-
method_def: T.any(Method, UnboundMethod),
|
96
|
-
signature: T.untyped # as `T::Private::Methods::Signature` is private
|
97
|
-
).returns(T::Array[String])
|
98
|
-
end
|
99
|
-
def parameters_types_from_signature(method_def, signature)
|
100
|
-
params = T.let([], T::Array[String])
|
101
|
-
|
102
|
-
return method_def.parameters.map { "T.untyped" } unless signature
|
103
|
-
|
104
|
-
# parameters types
|
105
|
-
signature.arg_types.each { |arg_type| params << arg_type[1].to_s }
|
106
|
-
|
107
|
-
# keyword parameters types
|
108
|
-
signature.kwarg_types.each { |_, kwarg_type| params << kwarg_type.to_s }
|
109
|
-
|
110
|
-
# rest parameter type
|
111
|
-
params << signature.rest_type.to_s if signature.has_rest
|
112
|
-
|
113
|
-
# special case `.void` in a proc
|
114
|
-
unless signature.block_name.nil?
|
115
|
-
params << signature.block_type.to_s.gsub("returns(<VOID>)", "void")
|
116
|
-
end
|
117
|
-
|
118
|
-
params
|
119
|
-
end
|
120
|
-
|
121
|
-
sig { params(scope: RBI::Scope, method_def: T.any(Method, UnboundMethod), class_method: T::Boolean).void }
|
122
|
-
def create_method_from_def(scope, method_def, class_method: false)
|
123
|
-
scope.create_method(
|
124
|
-
method_def.name.to_s,
|
125
|
-
parameters: compile_method_parameters_to_rbi(method_def),
|
126
|
-
return_type: compile_method_return_type_to_rbi(method_def),
|
127
|
-
class_method: class_method
|
128
|
-
)
|
129
|
-
end
|
130
|
-
|
131
|
-
include ParamHelper
|
132
|
-
|
133
|
-
sig { params(method_def: T.any(Method, UnboundMethod)).returns(T::Array[RBI::TypedParam]) }
|
134
|
-
def compile_method_parameters_to_rbi(method_def)
|
135
|
-
signature = T::Private::Methods.signature_for_method(method_def)
|
136
|
-
method_def = signature.nil? ? method_def : signature.method
|
137
|
-
method_types = parameters_types_from_signature(method_def, signature)
|
138
|
-
|
139
|
-
parameters = T.let(method_def.parameters, T::Array[[Symbol, T.nilable(Symbol)]])
|
140
|
-
|
141
|
-
parameters.each_with_index.map do |(type, name), index|
|
142
|
-
fallback_arg_name = "_arg#{index}"
|
143
|
-
|
144
|
-
name = name ? name.to_s : fallback_arg_name
|
145
|
-
name = fallback_arg_name unless valid_parameter_name?(name)
|
146
|
-
method_type = T.must(method_types[index])
|
147
|
-
|
148
|
-
case type
|
149
|
-
when :req
|
150
|
-
create_param(name, type: method_type)
|
151
|
-
when :opt
|
152
|
-
create_opt_param(name, type: method_type, default: "T.unsafe(nil)")
|
153
|
-
when :rest
|
154
|
-
create_rest_param(name, type: method_type)
|
155
|
-
when :keyreq
|
156
|
-
create_kw_param(name, type: method_type)
|
157
|
-
when :key
|
158
|
-
create_kw_opt_param(name, type: method_type, default: "T.unsafe(nil)")
|
159
|
-
when :keyrest
|
160
|
-
create_kw_rest_param(name, type: method_type)
|
161
|
-
when :block
|
162
|
-
create_block_param(name, type: method_type)
|
163
|
-
else
|
164
|
-
raise "Unknown type `#{type}`."
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
sig { params(method_def: T.any(Method, UnboundMethod)).returns(String) }
|
170
|
-
def compile_method_return_type_to_rbi(method_def)
|
171
|
-
signature = T::Private::Methods.signature_for_method(method_def)
|
172
|
-
return_type = signature.nil? ? "T.untyped" : name_of_type(signature.return_type)
|
173
|
-
return_type = "void" if return_type == "<VOID>"
|
174
|
-
# Map <NOT-TYPED> to `T.untyped`
|
175
|
-
return_type = "T.untyped" if return_type == "<NOT-TYPED>"
|
176
|
-
return_type
|
177
|
-
end
|
178
|
-
|
179
|
-
sig { params(type: String).returns(String) }
|
180
|
-
def as_nilable_type(type)
|
181
|
-
if type.start_with?("T.nilable(", "::T.nilable(") || type == "T.untyped" || type == "::T.untyped"
|
182
|
-
type
|
183
|
-
else
|
184
|
-
"T.nilable(#{type})"
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
sig { params(name: String).returns(T::Boolean) }
|
189
|
-
def valid_parameter_name?(name)
|
190
|
-
name.match?(/^[[[:alnum:]]_]+$/)
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module Tapioca
|
5
|
-
module Compilers
|
6
|
-
module Dsl
|
7
|
-
module Helper
|
8
|
-
module ActiveRecordConstants
|
9
|
-
extend T::Sig
|
10
|
-
|
11
|
-
AttributeMethodsModuleName = T.let("GeneratedAttributeMethods", String)
|
12
|
-
AssociationMethodsModuleName = T.let("GeneratedAssociationMethods", String)
|
13
|
-
|
14
|
-
RelationMethodsModuleName = T.let("GeneratedRelationMethods", String)
|
15
|
-
AssociationRelationMethodsModuleName = T.let("GeneratedAssociationRelationMethods", String)
|
16
|
-
CommonRelationMethodsModuleName = T.let("CommonRelationMethods", String)
|
17
|
-
|
18
|
-
RelationClassName = T.let("PrivateRelation", String)
|
19
|
-
RelationWhereChainClassName = T.let("PrivateRelationWhereChain", String)
|
20
|
-
AssociationRelationClassName = T.let("PrivateAssociationRelation", String)
|
21
|
-
AssociationRelationWhereChainClassName = T.let("PrivateAssociationRelationWhereChain", String)
|
22
|
-
AssociationsCollectionProxyClassName = T.let("PrivateCollectionProxy", String)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,223 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
class DynamicMixinCompiler
|
5
|
-
extend T::Sig
|
6
|
-
include Tapioca::Reflection
|
7
|
-
|
8
|
-
sig { returns(T::Array[Module]) }
|
9
|
-
attr_reader :dynamic_extends, :dynamic_includes
|
10
|
-
|
11
|
-
sig { returns(T::Array[Symbol]) }
|
12
|
-
attr_reader :class_attribute_readers, :class_attribute_writers, :class_attribute_predicates
|
13
|
-
|
14
|
-
sig { returns(T::Array[Symbol]) }
|
15
|
-
attr_reader :instance_attribute_readers, :instance_attribute_writers, :instance_attribute_predicates
|
16
|
-
|
17
|
-
sig { params(constant: Module).void }
|
18
|
-
def initialize(constant)
|
19
|
-
@constant = constant
|
20
|
-
mixins_from_modules = {}.compare_by_identity
|
21
|
-
class_attribute_readers = T.let([], T::Array[Symbol])
|
22
|
-
class_attribute_writers = T.let([], T::Array[Symbol])
|
23
|
-
class_attribute_predicates = T.let([], T::Array[Symbol])
|
24
|
-
|
25
|
-
instance_attribute_readers = T.let([], T::Array[Symbol])
|
26
|
-
instance_attribute_writers = T.let([], T::Array[Symbol])
|
27
|
-
instance_attribute_predicates = T.let([], T::Array[Symbol])
|
28
|
-
|
29
|
-
Class.new do
|
30
|
-
# Override the `self.include` method
|
31
|
-
define_singleton_method(:include) do |mod|
|
32
|
-
# Take a snapshot of the list of singleton class ancestors
|
33
|
-
# before the actual include
|
34
|
-
before = singleton_class.ancestors
|
35
|
-
# Call the actual `include` method with the supplied module
|
36
|
-
super(mod).tap do
|
37
|
-
# Take a snapshot of the list of singleton class ancestors
|
38
|
-
# after the actual include
|
39
|
-
after = singleton_class.ancestors
|
40
|
-
# The difference is the modules that are added to the list
|
41
|
-
# of ancestors of the singleton class. Those are all the
|
42
|
-
# modules that were `extend`ed due to the `include` call.
|
43
|
-
#
|
44
|
-
# We record those modules on our lookup table keyed by
|
45
|
-
# the included module with the values being all the modules
|
46
|
-
# that that module pulls into the singleton class.
|
47
|
-
#
|
48
|
-
# We need to reverse the order, since the extend order should
|
49
|
-
# be the inverse of the ancestor order. That is, earlier
|
50
|
-
# extended modules would be later in the ancestor chain.
|
51
|
-
mixins_from_modules[mod] = (after - before).reverse!
|
52
|
-
end
|
53
|
-
rescue Exception # rubocop:disable Lint/RescueException
|
54
|
-
# this is a best effort, bail if we can't perform this
|
55
|
-
end
|
56
|
-
|
57
|
-
define_singleton_method(:class_attribute) do |*attrs, **kwargs|
|
58
|
-
class_attribute_readers.concat(attrs)
|
59
|
-
class_attribute_writers.concat(attrs)
|
60
|
-
|
61
|
-
instance_predicate = kwargs.fetch(:instance_predicate, true)
|
62
|
-
instance_accessor = kwargs.fetch(:instance_accessor, true)
|
63
|
-
instance_reader = kwargs.fetch(:instance_reader, instance_accessor)
|
64
|
-
instance_writer = kwargs.fetch(:instance_writer, instance_accessor)
|
65
|
-
|
66
|
-
if instance_reader
|
67
|
-
instance_attribute_readers.concat(attrs)
|
68
|
-
end
|
69
|
-
|
70
|
-
if instance_writer
|
71
|
-
instance_attribute_writers.concat(attrs)
|
72
|
-
end
|
73
|
-
|
74
|
-
if instance_predicate
|
75
|
-
class_attribute_predicates.concat(attrs)
|
76
|
-
|
77
|
-
if instance_reader
|
78
|
-
instance_attribute_predicates.concat(attrs)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
super(*attrs, **kwargs) if defined?(super)
|
83
|
-
end
|
84
|
-
|
85
|
-
# rubocop:disable Style/MissingRespondToMissing
|
86
|
-
T::Sig::WithoutRuntime.sig { params(symbol: Symbol, args: T.untyped).returns(T.untyped) }
|
87
|
-
def method_missing(symbol, *args)
|
88
|
-
# We need this here so that we can handle any random instance
|
89
|
-
# method calls on the fake including class that may be done by
|
90
|
-
# the included module during the `self.included` hook.
|
91
|
-
end
|
92
|
-
|
93
|
-
class << self
|
94
|
-
extend T::Sig
|
95
|
-
|
96
|
-
T::Sig::WithoutRuntime.sig { params(symbol: Symbol, args: T.untyped).returns(T.untyped) }
|
97
|
-
def method_missing(symbol, *args)
|
98
|
-
# Similarly, we need this here so that we can handle any
|
99
|
-
# random class method calls on the fake including class
|
100
|
-
# that may be done by the included module during the
|
101
|
-
# `self.included` hook.
|
102
|
-
end
|
103
|
-
end
|
104
|
-
# rubocop:enable Style/MissingRespondToMissing
|
105
|
-
end.include(constant)
|
106
|
-
|
107
|
-
# The value that corresponds to the original included constant
|
108
|
-
# is the list of all dynamically extended modules because of that
|
109
|
-
# constant. We grab that value by deleting the key for the original
|
110
|
-
# constant.
|
111
|
-
@dynamic_extends = T.let(mixins_from_modules.delete(constant) || [], T::Array[Module])
|
112
|
-
|
113
|
-
# Since we deleted the original constant from the list of keys, all
|
114
|
-
# the keys that remain are the ones that are dynamically included modules
|
115
|
-
# during the include of the original constant.
|
116
|
-
@dynamic_includes = T.let(mixins_from_modules.keys, T::Array[Module])
|
117
|
-
|
118
|
-
@class_attribute_readers = T.let(class_attribute_readers, T::Array[Symbol])
|
119
|
-
@class_attribute_writers = T.let(class_attribute_writers, T::Array[Symbol])
|
120
|
-
@class_attribute_predicates = T.let(class_attribute_predicates, T::Array[Symbol])
|
121
|
-
|
122
|
-
@instance_attribute_readers = T.let(instance_attribute_readers, T::Array[Symbol])
|
123
|
-
@instance_attribute_writers = T.let(instance_attribute_writers, T::Array[Symbol])
|
124
|
-
@instance_attribute_predicates = T.let(instance_attribute_predicates, T::Array[Symbol])
|
125
|
-
end
|
126
|
-
|
127
|
-
sig { returns(T::Boolean) }
|
128
|
-
def empty_attributes?
|
129
|
-
@class_attribute_readers.empty? && @class_attribute_writers.empty?
|
130
|
-
end
|
131
|
-
|
132
|
-
sig { params(tree: RBI::Tree).void }
|
133
|
-
def compile_class_attributes(tree)
|
134
|
-
return if empty_attributes?
|
135
|
-
|
136
|
-
# Create a synthetic module to hold the generated class methods
|
137
|
-
tree << RBI::Module.new("GeneratedClassMethods") do |mod|
|
138
|
-
class_attribute_readers.each do |attribute|
|
139
|
-
mod << RBI::Method.new(attribute.to_s)
|
140
|
-
end
|
141
|
-
|
142
|
-
class_attribute_writers.each do |attribute|
|
143
|
-
mod << RBI::Method.new("#{attribute}=") do |method|
|
144
|
-
method << RBI::Param.new("value")
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
class_attribute_predicates.each do |attribute|
|
149
|
-
mod << RBI::Method.new("#{attribute}?")
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
# Create a synthetic module to hold the generated instance methods
|
154
|
-
tree << RBI::Module.new("GeneratedInstanceMethods") do |mod|
|
155
|
-
instance_attribute_readers.each do |attribute|
|
156
|
-
mod << RBI::Method.new(attribute.to_s)
|
157
|
-
end
|
158
|
-
|
159
|
-
instance_attribute_writers.each do |attribute|
|
160
|
-
mod << RBI::Method.new("#{attribute}=") do |method|
|
161
|
-
method << RBI::Param.new("value")
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
instance_attribute_predicates.each do |attribute|
|
166
|
-
mod << RBI::Method.new("#{attribute}?")
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
# Add a mixes_in_class_methods and include for the generated modules
|
171
|
-
tree << RBI::MixesInClassMethods.new("GeneratedClassMethods")
|
172
|
-
tree << RBI::Include.new("GeneratedInstanceMethods")
|
173
|
-
end
|
174
|
-
|
175
|
-
sig { params(tree: RBI::Tree).returns([T::Array[Module], T::Array[Module]]) }
|
176
|
-
def compile_mixes_in_class_methods(tree)
|
177
|
-
includes = dynamic_includes.map do |mod|
|
178
|
-
qname = qualified_name_of(mod)
|
179
|
-
|
180
|
-
next if qname.nil? || qname.empty?
|
181
|
-
next if filtered_mixin?(qname)
|
182
|
-
|
183
|
-
tree << RBI::Include.new(qname)
|
184
|
-
|
185
|
-
mod
|
186
|
-
end.compact
|
187
|
-
|
188
|
-
# If we can generate multiple mixes_in_class_methods, then we want to use all dynamic extends that are not the
|
189
|
-
# constant itself
|
190
|
-
mixed_in_class_methods = dynamic_extends.select do |mod|
|
191
|
-
mod != @constant && !module_included_by_another_dynamic_extend?(mod, dynamic_extends)
|
192
|
-
end
|
193
|
-
|
194
|
-
return [[], []] if mixed_in_class_methods.empty?
|
195
|
-
|
196
|
-
mixed_in_class_methods.each do |mod|
|
197
|
-
qualified_name = qualified_name_of(mod)
|
198
|
-
|
199
|
-
next if qualified_name.nil? || qualified_name.empty?
|
200
|
-
next if filtered_mixin?(qualified_name)
|
201
|
-
|
202
|
-
tree << RBI::MixesInClassMethods.new(qualified_name)
|
203
|
-
end
|
204
|
-
|
205
|
-
[mixed_in_class_methods, includes]
|
206
|
-
rescue
|
207
|
-
[[], []] # silence errors
|
208
|
-
end
|
209
|
-
|
210
|
-
sig { params(mod: Module, dynamic_extends: T::Array[Module]).returns(T::Boolean) }
|
211
|
-
def module_included_by_another_dynamic_extend?(mod, dynamic_extends)
|
212
|
-
dynamic_extends.any? do |dynamic_extend|
|
213
|
-
mod != dynamic_extend && ancestors_of(dynamic_extend).include?(mod)
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
sig { params(qualified_mixin_name: String).returns(T::Boolean) }
|
218
|
-
def filtered_mixin?(qualified_mixin_name)
|
219
|
-
# filter T:: namespace mixins that aren't T::Props
|
220
|
-
# T::Props and subconstants have semantic value
|
221
|
-
qualified_mixin_name.start_with?("::T::") && !qualified_mixin_name.start_with?("::T::Props")
|
222
|
-
end
|
223
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "pathname"
|
5
|
-
require "shellwords"
|
6
|
-
|
7
|
-
module Tapioca
|
8
|
-
module Compilers
|
9
|
-
module Sorbet
|
10
|
-
SORBET_GEM_SPEC = T.let(
|
11
|
-
Gem::Specification.find_by_name("sorbet-static"),
|
12
|
-
Gem::Specification
|
13
|
-
)
|
14
|
-
SORBET = T.let(
|
15
|
-
Pathname.new(SORBET_GEM_SPEC.full_gem_path) / "libexec" / "sorbet",
|
16
|
-
Pathname
|
17
|
-
)
|
18
|
-
EXE_PATH_ENV_VAR = "TAPIOCA_SORBET_EXE"
|
19
|
-
|
20
|
-
FEATURE_REQUIREMENTS = T.let({
|
21
|
-
# First tag that includes https://github.com/sorbet/sorbet/pull/4706
|
22
|
-
to_ary_nil_support: Gem::Requirement.new(">= 0.5.9220"),
|
23
|
-
}.freeze, T::Hash[Symbol, Gem::Requirement])
|
24
|
-
|
25
|
-
class << self
|
26
|
-
extend(T::Sig)
|
27
|
-
|
28
|
-
sig { params(args: String).returns(String) }
|
29
|
-
def run(*args)
|
30
|
-
IO.popen(
|
31
|
-
[
|
32
|
-
sorbet_path,
|
33
|
-
"--quiet",
|
34
|
-
*args,
|
35
|
-
].join(" "),
|
36
|
-
err: "/dev/null"
|
37
|
-
).read
|
38
|
-
end
|
39
|
-
|
40
|
-
sig { returns(String) }
|
41
|
-
def sorbet_path
|
42
|
-
sorbet_path = ENV.fetch(EXE_PATH_ENV_VAR, SORBET)
|
43
|
-
sorbet_path = SORBET if sorbet_path.empty?
|
44
|
-
sorbet_path.to_s.shellescape
|
45
|
-
end
|
46
|
-
|
47
|
-
sig { params(feature: Symbol, version: T.nilable(Gem::Version)).returns(T::Boolean) }
|
48
|
-
def supports?(feature, version: nil)
|
49
|
-
version = SORBET_GEM_SPEC.version unless version
|
50
|
-
requirement = FEATURE_REQUIREMENTS[feature]
|
51
|
-
|
52
|
-
raise "Invalid Sorbet feature #{feature}" unless requirement
|
53
|
-
|
54
|
-
requirement.satisfied_by?(version)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|