tapioca 0.8.3 → 0.9.2
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 +5 -2
- data/README.md +188 -36
- data/lib/tapioca/cli.rb +130 -66
- data/lib/tapioca/commands/annotations.rb +167 -34
- data/lib/tapioca/commands/check_shims.rb +101 -0
- data/lib/tapioca/commands/{init.rb → configure.rb} +1 -1
- data/lib/tapioca/commands/dsl.rb +1 -1
- data/lib/tapioca/commands/gem.rb +15 -10
- data/lib/tapioca/commands.rb +2 -1
- data/lib/tapioca/dsl/compiler.rb +1 -13
- data/lib/tapioca/dsl/compilers/active_model_attributes.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +17 -0
- data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +5 -4
- data/lib/tapioca/dsl/compilers/frozen_record.rb +2 -2
- data/lib/tapioca/dsl/compilers/protobuf.rb +6 -0
- data/lib/tapioca/dsl/compilers.rb +0 -4
- data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +21 -3
- data/lib/tapioca/dsl/pipeline.rb +0 -2
- data/lib/tapioca/dsl.rb +8 -0
- data/lib/tapioca/executor.rb +0 -3
- data/lib/tapioca/gem/events.rb +22 -3
- data/lib/tapioca/gem/listeners/base.rb +11 -0
- data/lib/tapioca/gem/listeners/dynamic_mixins.rb +5 -0
- data/lib/tapioca/gem/listeners/foreign_constants.rb +65 -0
- data/lib/tapioca/gem/listeners/methods.rb +7 -18
- data/lib/tapioca/gem/listeners/mixins.rb +31 -10
- data/lib/tapioca/gem/listeners/remove_empty_payload_scopes.rb +5 -0
- data/lib/tapioca/gem/listeners/sorbet_enums.rb +5 -0
- data/lib/tapioca/gem/listeners/sorbet_helpers.rb +5 -0
- data/lib/tapioca/gem/listeners/sorbet_props.rb +5 -0
- data/lib/tapioca/gem/listeners/sorbet_required_ancestors.rb +5 -0
- data/lib/tapioca/gem/listeners/sorbet_signatures.rb +6 -1
- data/lib/tapioca/gem/listeners/sorbet_type_variables.rb +5 -0
- data/lib/tapioca/gem/listeners/source_location.rb +67 -0
- data/lib/tapioca/gem/listeners/subconstants.rb +5 -0
- data/lib/tapioca/gem/listeners/yard_doc.rb +5 -0
- data/lib/tapioca/gem/listeners.rb +2 -0
- data/lib/tapioca/gem/pipeline.rb +64 -19
- data/lib/tapioca/gem.rb +6 -0
- data/lib/tapioca/gemfile.rb +7 -6
- data/lib/tapioca/helpers/cli_helper.rb +8 -2
- data/lib/tapioca/helpers/config_helper.rb +0 -2
- data/lib/tapioca/helpers/env_helper.rb +16 -0
- data/lib/tapioca/helpers/rbi_files_helper.rb +255 -0
- data/lib/tapioca/helpers/rbi_helper.rb +98 -94
- data/lib/tapioca/helpers/sorbet_helper.rb +2 -3
- data/lib/tapioca/helpers/test/content.rb +0 -2
- data/lib/tapioca/helpers/test/template.rb +0 -2
- data/lib/tapioca/internal.rb +36 -12
- data/lib/tapioca/rbi_ext/model.rb +2 -15
- data/lib/tapioca/runtime/dynamic_mixin_compiler.rb +18 -16
- data/lib/tapioca/runtime/reflection.rb +26 -0
- data/lib/tapioca/runtime/trackers/constant_definition.rb +44 -16
- data/lib/tapioca/runtime/trackers/mixin.rb +49 -14
- data/lib/tapioca/sorbet_ext/generic_name_patch.rb +1 -4
- data/lib/tapioca/sorbet_ext/name_patch.rb +15 -5
- data/lib/tapioca/sorbet_ext/proc_bind_patch.rb +40 -0
- data/lib/tapioca/static/requires_compiler.rb +0 -2
- data/lib/tapioca/static/symbol_loader.rb +26 -30
- data/lib/tapioca/static/symbol_table_parser.rb +0 -3
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +3 -0
- metadata +24 -7
- data/lib/tapioca/dsl/helpers/param_helper.rb +0 -55
- data/lib/tapioca/helpers/shims_helper.rb +0 -115
- data/lib/tapioca/helpers/signatures_helper.rb +0 -17
- data/lib/tapioca/helpers/type_variable_helper.rb +0 -43
data/lib/tapioca/commands/gem.rb
CHANGED
@@ -5,7 +5,7 @@ module Tapioca
|
|
5
5
|
module Commands
|
6
6
|
class Gem < Command
|
7
7
|
include SorbetHelper
|
8
|
-
include
|
8
|
+
include RBIFilesHelper
|
9
9
|
|
10
10
|
sig do
|
11
11
|
params(
|
@@ -16,7 +16,8 @@ module Tapioca
|
|
16
16
|
typed_overrides: T::Hash[String, String],
|
17
17
|
outpath: Pathname,
|
18
18
|
file_header: T::Boolean,
|
19
|
-
|
19
|
+
include_doc: T::Boolean,
|
20
|
+
include_loc: T::Boolean,
|
20
21
|
include_exported_rbis: T::Boolean,
|
21
22
|
number_of_workers: T.nilable(Integer),
|
22
23
|
auto_strictness: T::Boolean,
|
@@ -32,7 +33,8 @@ module Tapioca
|
|
32
33
|
typed_overrides:,
|
33
34
|
outpath:,
|
34
35
|
file_header:,
|
35
|
-
|
36
|
+
include_doc:,
|
37
|
+
include_loc:,
|
36
38
|
include_exported_rbis:,
|
37
39
|
number_of_workers: nil,
|
38
40
|
auto_strictness: true,
|
@@ -57,7 +59,8 @@ module Tapioca
|
|
57
59
|
@bundle = T.let(nil, T.nilable(Gemfile))
|
58
60
|
@existing_rbis = T.let(nil, T.nilable(T::Hash[String, String]))
|
59
61
|
@expected_rbis = T.let(nil, T.nilable(T::Hash[String, String]))
|
60
|
-
@
|
62
|
+
@include_doc = T.let(include_doc, T::Boolean)
|
63
|
+
@include_loc = T.let(include_loc, T::Boolean)
|
61
64
|
@include_exported_rbis = include_exported_rbis
|
62
65
|
end
|
63
66
|
|
@@ -94,12 +97,12 @@ module Tapioca
|
|
94
97
|
end
|
95
98
|
end
|
96
99
|
|
97
|
-
sig { params(should_verify: T::Boolean).void }
|
98
|
-
def sync(should_verify: false)
|
100
|
+
sig { params(should_verify: T::Boolean, exclude: T::Array[String]).void }
|
101
|
+
def sync(should_verify: false, exclude: [])
|
99
102
|
if should_verify
|
100
103
|
say("Checking for out-of-date RBIs...")
|
101
104
|
say("")
|
102
|
-
perform_sync_verification
|
105
|
+
perform_sync_verification(exclude: exclude)
|
103
106
|
return
|
104
107
|
end
|
105
108
|
|
@@ -182,7 +185,7 @@ module Tapioca
|
|
182
185
|
default_command(:gem, gem.name),
|
183
186
|
reason: "types exported from the `#{gem.name}` gem",) if @file_header
|
184
187
|
|
185
|
-
rbi.root = Tapioca::Gem::Pipeline.new(gem, include_doc: @
|
188
|
+
rbi.root = Tapioca::Gem::Pipeline.new(gem, include_doc: @include_doc, include_loc: @include_loc).compile
|
186
189
|
|
187
190
|
merge_with_exported_rbi(gem, rbi) if @include_exported_rbis
|
188
191
|
|
@@ -201,11 +204,13 @@ module Tapioca
|
|
201
204
|
end
|
202
205
|
end
|
203
206
|
|
204
|
-
sig { void }
|
205
|
-
def perform_sync_verification
|
207
|
+
sig { params(exclude: T::Array[String]).void }
|
208
|
+
def perform_sync_verification(exclude: [])
|
206
209
|
diff = {}
|
207
210
|
|
208
211
|
removed_rbis.each do |gem_name|
|
212
|
+
next if exclude.include?(gem_name)
|
213
|
+
|
209
214
|
filename = existing_rbi(gem_name)
|
210
215
|
diff[filename] = :removed
|
211
216
|
end
|
data/lib/tapioca/commands.rb
CHANGED
@@ -5,8 +5,9 @@ module Tapioca
|
|
5
5
|
module Commands
|
6
6
|
autoload :Command, "tapioca/commands/command"
|
7
7
|
autoload :Annotations, "tapioca/commands/annotations"
|
8
|
+
autoload :CheckShims, "tapioca/commands/check_shims"
|
8
9
|
autoload :Dsl, "tapioca/commands/dsl"
|
9
|
-
autoload :
|
10
|
+
autoload :Configure, "tapioca/commands/configure"
|
10
11
|
autoload :Gem, "tapioca/commands/gem"
|
11
12
|
autoload :Require, "tapioca/commands/require"
|
12
13
|
autoload :Todo, "tapioca/commands/todo"
|
data/lib/tapioca/dsl/compiler.rb
CHANGED
@@ -1,12 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "rbi"
|
5
|
-
require "tapioca/rbi_ext/model"
|
6
|
-
require "tapioca/rbi_formatter"
|
7
|
-
require "tapioca/dsl/helpers/param_helper"
|
8
|
-
require "tapioca/dsl/pipeline"
|
9
|
-
|
10
4
|
module Tapioca
|
11
5
|
module Dsl
|
12
6
|
class Compiler
|
@@ -14,6 +8,7 @@ module Tapioca
|
|
14
8
|
extend T::Helpers
|
15
9
|
extend T::Generic
|
16
10
|
|
11
|
+
include RBIHelper
|
17
12
|
include Runtime::Reflection
|
18
13
|
extend Runtime::Reflection
|
19
14
|
|
@@ -119,8 +114,6 @@ module Tapioca
|
|
119
114
|
)
|
120
115
|
end
|
121
116
|
|
122
|
-
include Helpers::ParamHelper
|
123
|
-
|
124
117
|
sig { params(method_def: T.any(Method, UnboundMethod)).returns(T::Array[RBI::TypedParam]) }
|
125
118
|
def compile_method_parameters_to_rbi(method_def)
|
126
119
|
signature = signature_of(method_def)
|
@@ -175,11 +168,6 @@ module Tapioca
|
|
175
168
|
"T.nilable(#{type})"
|
176
169
|
end
|
177
170
|
end
|
178
|
-
|
179
|
-
sig { params(name: String).returns(T::Boolean) }
|
180
|
-
def valid_parameter_name?(name)
|
181
|
-
name.match?(/^[[[:alnum:]]_]+$/)
|
182
|
-
end
|
183
171
|
end
|
184
172
|
end
|
185
173
|
end
|
@@ -543,6 +543,23 @@ module Tapioca
|
|
543
543
|
],
|
544
544
|
return_type: constant_name
|
545
545
|
)
|
546
|
+
when :find_sole_by
|
547
|
+
create_common_method(
|
548
|
+
"find_sole_by",
|
549
|
+
common_relation_methods_module,
|
550
|
+
parameters: [
|
551
|
+
create_param("arg", type: "T.untyped"),
|
552
|
+
create_rest_param("args", type: "T.untyped"),
|
553
|
+
],
|
554
|
+
return_type: constant_name
|
555
|
+
)
|
556
|
+
when :sole
|
557
|
+
create_common_method(
|
558
|
+
"sole",
|
559
|
+
common_relation_methods_module,
|
560
|
+
parameters: [],
|
561
|
+
return_type: constant_name
|
562
|
+
)
|
546
563
|
when :first, :last, :take
|
547
564
|
create_common_method(
|
548
565
|
method_name,
|
@@ -95,17 +95,18 @@ module Tapioca
|
|
95
95
|
sig { override.void }
|
96
96
|
def decorate
|
97
97
|
stores = constant.typed_stores
|
98
|
-
return if stores.values.
|
98
|
+
return if stores.values.all? { |store| store.accessors.empty? }
|
99
99
|
|
100
100
|
root.create_path(constant) do |model|
|
101
101
|
stores.values.each do |store_data|
|
102
|
-
store_data.accessors.each do |accessor|
|
103
|
-
field = store_data.fields
|
102
|
+
store_data.accessors.each do |accessor, name|
|
103
|
+
field = store_data.fields.fetch(accessor)
|
104
104
|
type = type_for(field.type_sym)
|
105
105
|
type = as_nilable_type(type) if field.null
|
106
|
+
name ||= field.name # support < 1.5.0
|
106
107
|
|
107
108
|
store_accessors_module = model.create_module("StoreAccessors")
|
108
|
-
generate_methods(store_accessors_module,
|
109
|
+
generate_methods(store_accessors_module, name.to_s, type)
|
109
110
|
model.create_include("StoreAccessors")
|
110
111
|
end
|
111
112
|
end
|
@@ -65,7 +65,7 @@ module Tapioca
|
|
65
65
|
class FrozenRecord < Compiler
|
66
66
|
extend T::Sig
|
67
67
|
|
68
|
-
ConstantType = type_member { { fixed: T.class_of(::FrozenRecord::Base) } }
|
68
|
+
ConstantType = type_member { { fixed: T.all(T.class_of(::FrozenRecord::Base), Extensions::FrozenRecord) } }
|
69
69
|
|
70
70
|
sig { override.void }
|
71
71
|
def decorate
|
@@ -97,7 +97,7 @@ module Tapioca
|
|
97
97
|
|
98
98
|
sig { params(record: RBI::Scope).void }
|
99
99
|
def decorate_scopes(record)
|
100
|
-
scopes =
|
100
|
+
scopes = constant.__tapioca_scope_names
|
101
101
|
return if scopes.nil?
|
102
102
|
|
103
103
|
module_name = "GeneratedRelationMethods"
|
@@ -146,6 +146,11 @@ module Tapioca
|
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
149
|
+
sig { params(descriptor: Google::Protobuf::FieldDescriptor).returns(T::Boolean) }
|
150
|
+
def nilable_descriptor?(descriptor)
|
151
|
+
descriptor.label == :optional && descriptor.type == :message
|
152
|
+
end
|
153
|
+
|
149
154
|
sig { params(descriptor: Google::Protobuf::FieldDescriptor).returns(Field) }
|
150
155
|
def field_of(descriptor)
|
151
156
|
if descriptor.label == :repeated
|
@@ -185,6 +190,7 @@ module Tapioca
|
|
185
190
|
end
|
186
191
|
else
|
187
192
|
type = type_of(descriptor)
|
193
|
+
type = as_nilable_type(type) if nilable_descriptor?(descriptor)
|
188
194
|
|
189
195
|
Field.new(
|
190
196
|
name: descriptor.name,
|
@@ -35,15 +35,23 @@ module Tapioca
|
|
35
35
|
when ActiveRecord::Type::Boolean
|
36
36
|
"T::Boolean"
|
37
37
|
when ActiveRecord::Type::DateTime, ActiveRecord::Type::Time
|
38
|
-
"::
|
38
|
+
"::Time"
|
39
39
|
when ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter
|
40
40
|
"::ActiveSupport::TimeWithZone"
|
41
|
+
when ActiveRecord::Enum::EnumType
|
42
|
+
"::String"
|
41
43
|
else
|
42
44
|
handle_unknown_type(column_type)
|
43
45
|
end
|
44
46
|
|
45
47
|
column = @constant.columns_hash[column_name]
|
46
|
-
setter_type =
|
48
|
+
setter_type =
|
49
|
+
case column_type
|
50
|
+
when ActiveRecord::Enum::EnumType
|
51
|
+
enum_setter_type(column_type)
|
52
|
+
else
|
53
|
+
getter_type
|
54
|
+
end
|
47
55
|
|
48
56
|
if column&.null
|
49
57
|
return [as_nilable_type(getter_type), as_nilable_type(setter_type)]
|
@@ -75,7 +83,7 @@ module Tapioca
|
|
75
83
|
end
|
76
84
|
end
|
77
85
|
|
78
|
-
sig { params(column_type:
|
86
|
+
sig { params(column_type: BasicObject).returns(String) }
|
79
87
|
def handle_unknown_type(column_type)
|
80
88
|
return "T.untyped" unless ActiveModel::Type::Value === column_type
|
81
89
|
return "T.untyped" if Runtime::GenericTypeRegistry.generic_type_instance?(column_type)
|
@@ -108,6 +116,16 @@ module Tapioca
|
|
108
116
|
|
109
117
|
first_argument_type.to_s
|
110
118
|
end
|
119
|
+
|
120
|
+
sig { params(column_type: ActiveRecord::Enum::EnumType).returns(String) }
|
121
|
+
def enum_setter_type(column_type)
|
122
|
+
case column_type.subtype
|
123
|
+
when ActiveRecord::Type::Integer
|
124
|
+
"T.any(::String, ::Symbol, ::Integer)"
|
125
|
+
else
|
126
|
+
"T.any(::String, ::Symbol)"
|
127
|
+
end
|
128
|
+
end
|
111
129
|
end
|
112
130
|
end
|
113
131
|
end
|
data/lib/tapioca/dsl/pipeline.rb
CHANGED
data/lib/tapioca/dsl.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "rbi"
|
5
|
+
|
4
6
|
require "tapioca"
|
5
7
|
require "tapioca/runtime/reflection"
|
8
|
+
require "tapioca/helpers/sorbet_helper"
|
9
|
+
require "tapioca/helpers/rbi_helper"
|
10
|
+
require "tapioca/rbi_ext/model"
|
11
|
+
require "tapioca/rbi_formatter"
|
12
|
+
require "tapioca/dsl/compilers"
|
13
|
+
require "tapioca/dsl/pipeline"
|
6
14
|
require "tapioca/dsl/compiler"
|
data/lib/tapioca/executor.rb
CHANGED
data/lib/tapioca/gem/events.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "pathname"
|
5
|
-
|
6
4
|
module Tapioca
|
7
5
|
module Gem
|
8
6
|
class Event
|
@@ -42,6 +40,20 @@ module Tapioca
|
|
42
40
|
end
|
43
41
|
end
|
44
42
|
|
43
|
+
class ForeignConstantFound < ConstantFound
|
44
|
+
extend T::Sig
|
45
|
+
|
46
|
+
sig { override.returns(Module) }
|
47
|
+
def constant
|
48
|
+
T.cast(@constant, Module)
|
49
|
+
end
|
50
|
+
|
51
|
+
sig { params(symbol: String, constant: Module).void }
|
52
|
+
def initialize(symbol, constant)
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
45
57
|
class NodeAdded < Event
|
46
58
|
extend T::Helpers
|
47
59
|
extend T::Sig
|
@@ -88,9 +100,14 @@ module Tapioca
|
|
88
100
|
end
|
89
101
|
end
|
90
102
|
|
103
|
+
class ForeignScopeNodeAdded < ScopeNodeAdded; end
|
104
|
+
|
91
105
|
class MethodNodeAdded < NodeAdded
|
92
106
|
extend T::Sig
|
93
107
|
|
108
|
+
sig { returns(UnboundMethod) }
|
109
|
+
attr_reader :method
|
110
|
+
|
94
111
|
sig { returns(RBI::Method) }
|
95
112
|
attr_reader :node
|
96
113
|
|
@@ -104,14 +121,16 @@ module Tapioca
|
|
104
121
|
params(
|
105
122
|
symbol: String,
|
106
123
|
constant: Module,
|
124
|
+
method: UnboundMethod,
|
107
125
|
node: RBI::Method,
|
108
126
|
signature: T.untyped,
|
109
127
|
parameters: T::Array[[Symbol, String]]
|
110
128
|
).void.checked(:never)
|
111
129
|
end
|
112
|
-
def initialize(symbol, constant, node, signature, parameters)
|
130
|
+
def initialize(symbol, constant, method, node, signature, parameters) # rubocop:disable Metrics/ParameterLists
|
113
131
|
super(symbol, constant)
|
114
132
|
@node = node
|
133
|
+
@method = method
|
115
134
|
@signature = signature
|
116
135
|
@parameters = parameters
|
117
136
|
end
|
@@ -17,6 +17,8 @@ module Tapioca
|
|
17
17
|
|
18
18
|
sig { params(event: NodeAdded).void }
|
19
19
|
def dispatch(event)
|
20
|
+
return if ignore?(event)
|
21
|
+
|
20
22
|
case event
|
21
23
|
when ConstNodeAdded
|
22
24
|
on_const(event)
|
@@ -42,6 +44,15 @@ module Tapioca
|
|
42
44
|
sig { params(event: MethodNodeAdded).void }
|
43
45
|
def on_method(event)
|
44
46
|
end
|
47
|
+
|
48
|
+
sig { params(event: NodeAdded).returns(T::Boolean) }
|
49
|
+
def ignore?(event)
|
50
|
+
# Some listeners do not have to take any action on certain events. For example,
|
51
|
+
# almost every listener should skip ForeignScopeNodeAdded events in order not to generate
|
52
|
+
# unnecessary RBIs for foreign constants. This method should be overridden by listener
|
53
|
+
# subclasses to skip any events that aren't relevant to them.
|
54
|
+
false
|
55
|
+
end
|
45
56
|
end
|
46
57
|
end
|
47
58
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Tapioca
|
5
|
+
module Gem
|
6
|
+
module Listeners
|
7
|
+
class ForeignConstants < Base
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
include Runtime::Reflection
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
sig { override.params(event: ScopeNodeAdded).void }
|
15
|
+
def on_scope(event)
|
16
|
+
mixin = event.constant
|
17
|
+
return if Class === mixin # Classes can't be mixed into other constants
|
18
|
+
|
19
|
+
# There are cases where we want to process constants not declared by the current
|
20
|
+
# gem, i.e. "foreign constant". These are constants defined in another gem to which
|
21
|
+
# this gem is applying a mix-in. This pattern is especially common for gems that add
|
22
|
+
# behavior to Ruby standard library classes by mixing in modules to them.
|
23
|
+
#
|
24
|
+
# The way we identify these "foreign constants" is by asking the mixin tracker which
|
25
|
+
# constants have mixed in the current module that we are handling. We add all the
|
26
|
+
# constants that we discover to the pipeline to be processed.
|
27
|
+
Runtime::Trackers::Mixin.constants_with_mixin(mixin).each_value do |location_info|
|
28
|
+
location_info.each do |constant, location|
|
29
|
+
next unless mixed_in_by_gem?(location)
|
30
|
+
|
31
|
+
name = @pipeline.name_of(constant)
|
32
|
+
|
33
|
+
# Calling Tapioca::Gem::Pipeline#name_of on a singleton class returns `nil`.
|
34
|
+
# To handle this case, use string parsing to get the name of the singleton class's
|
35
|
+
# base constant. Then, generate RBIs as if the base constant is extending the mixin,
|
36
|
+
# which is functionally equivalent to including or prepending to the singleton class.
|
37
|
+
if !name && constant.singleton_class?
|
38
|
+
name = constant_name_from_singleton_class(constant)
|
39
|
+
next unless name
|
40
|
+
|
41
|
+
constant = T.cast(constantize(name), Module)
|
42
|
+
end
|
43
|
+
|
44
|
+
@pipeline.push_foreign_constant(name, constant) if name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
sig do
|
50
|
+
params(
|
51
|
+
location: String,
|
52
|
+
).returns(T::Boolean)
|
53
|
+
end
|
54
|
+
def mixed_in_by_gem?(location)
|
55
|
+
@pipeline.gem.contains_path?(location)
|
56
|
+
end
|
57
|
+
|
58
|
+
sig { override.params(event: NodeAdded).returns(T::Boolean) }
|
59
|
+
def ignore?(event)
|
60
|
+
event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -7,13 +7,9 @@ module Tapioca
|
|
7
7
|
class Methods < Base
|
8
8
|
extend T::Sig
|
9
9
|
|
10
|
+
include RBIHelper
|
10
11
|
include Runtime::Reflection
|
11
12
|
|
12
|
-
SPECIAL_METHOD_NAMES = T.let([
|
13
|
-
"!", "~", "+@", "**", "-@", "*", "/", "%", "+", "-", "<<", ">>", "&", "|", "^",
|
14
|
-
"<", "<=", "=>", ">", ">=", "==", "===", "!=", "=~", "!~", "<=>", "[]", "[]=", "`",
|
15
|
-
], T::Array[String])
|
16
|
-
|
17
13
|
private
|
18
14
|
|
19
15
|
sig { override.params(event: ScopeNodeAdded).void }
|
@@ -138,7 +134,7 @@ module Tapioca
|
|
138
134
|
end
|
139
135
|
end
|
140
136
|
|
141
|
-
@pipeline.push_method(symbol_name, constant, rbi_method, signature, sanitized_parameters)
|
137
|
+
@pipeline.push_method(symbol_name, constant, method, rbi_method, signature, sanitized_parameters)
|
142
138
|
tree << rbi_method
|
143
139
|
end
|
144
140
|
|
@@ -184,24 +180,17 @@ module Tapioca
|
|
184
180
|
.include?(method_name.gsub(/=$/, "").to_sym)
|
185
181
|
end
|
186
182
|
|
187
|
-
sig { params(name: String).returns(T::Boolean) }
|
188
|
-
def valid_method_name?(name)
|
189
|
-
return true if SPECIAL_METHOD_NAMES.include?(name)
|
190
|
-
|
191
|
-
!!name.match(/^[[:word:]]+[?!=]?$/)
|
192
|
-
end
|
193
|
-
|
194
|
-
sig { params(name: String).returns(T::Boolean) }
|
195
|
-
def valid_parameter_name?(name)
|
196
|
-
name.match?(/^[[[:alnum:]]_]+$/)
|
197
|
-
end
|
198
|
-
|
199
183
|
sig { params(constant: Module).returns(T.nilable(UnboundMethod)) }
|
200
184
|
def initialize_method_for(constant)
|
201
185
|
constant.instance_method(:initialize)
|
202
186
|
rescue
|
203
187
|
nil
|
204
188
|
end
|
189
|
+
|
190
|
+
sig { override.params(event: NodeAdded).returns(T::Boolean) }
|
191
|
+
def ignore?(event)
|
192
|
+
event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
|
193
|
+
end
|
205
194
|
end
|
206
195
|
end
|
207
196
|
end
|
@@ -26,19 +26,20 @@ module Tapioca
|
|
26
26
|
end
|
27
27
|
|
28
28
|
node = event.node
|
29
|
-
add_mixins(node, prepends.reverse, Runtime::Trackers::Mixin::Type::Prepend)
|
30
|
-
add_mixins(node, includes.reverse, Runtime::Trackers::Mixin::Type::Include)
|
31
|
-
add_mixins(node, extends.reverse, Runtime::Trackers::Mixin::Type::Extend)
|
29
|
+
add_mixins(node, constant, prepends.reverse, Runtime::Trackers::Mixin::Type::Prepend)
|
30
|
+
add_mixins(node, constant, includes.reverse, Runtime::Trackers::Mixin::Type::Include)
|
31
|
+
add_mixins(node, constant, extends.reverse, Runtime::Trackers::Mixin::Type::Extend)
|
32
32
|
end
|
33
33
|
|
34
34
|
sig do
|
35
35
|
params(
|
36
36
|
tree: RBI::Tree,
|
37
|
+
constant: Module,
|
37
38
|
mods: T::Array[Module],
|
38
39
|
mixin_type: Runtime::Trackers::Mixin::Type
|
39
40
|
).void
|
40
41
|
end
|
41
|
-
def add_mixins(tree, mods, mixin_type)
|
42
|
+
def add_mixins(tree, constant, mods, mixin_type)
|
42
43
|
mods
|
43
44
|
.select do |mod|
|
44
45
|
name = @pipeline.name_of(mod)
|
@@ -46,6 +47,8 @@ module Tapioca
|
|
46
47
|
name && !filtered_mixin?(name)
|
47
48
|
end
|
48
49
|
.map do |mod|
|
50
|
+
next unless mixed_in_by_gem?(constant, mod, mixin_type)
|
51
|
+
|
49
52
|
name = @pipeline.name_of(mod)
|
50
53
|
@pipeline.push_symbol(name) if name
|
51
54
|
|
@@ -62,6 +65,25 @@ module Tapioca
|
|
62
65
|
end
|
63
66
|
end
|
64
67
|
|
68
|
+
sig do
|
69
|
+
params(
|
70
|
+
constant: Module,
|
71
|
+
mixin: Module,
|
72
|
+
mixin_type: Runtime::Trackers::Mixin::Type
|
73
|
+
).returns(T::Boolean)
|
74
|
+
end
|
75
|
+
def mixed_in_by_gem?(constant, mixin, mixin_type)
|
76
|
+
mixin_location =
|
77
|
+
T.cast(
|
78
|
+
Runtime::Trackers::Mixin.constants_with_mixin(mixin).dig(mixin_type, constant),
|
79
|
+
T.nilable(String)
|
80
|
+
)
|
81
|
+
|
82
|
+
return true if mixin_location.nil?
|
83
|
+
|
84
|
+
@pipeline.gem.contains_path?(mixin_location)
|
85
|
+
end
|
86
|
+
|
65
87
|
sig { params(mixin_name: String).returns(T::Boolean) }
|
66
88
|
def filtered_mixin?(mixin_name)
|
67
89
|
# filter T:: namespace mixins that aren't T::Props
|
@@ -71,9 +93,8 @@ module Tapioca
|
|
71
93
|
|
72
94
|
sig { params(constant: Module).returns(T::Array[Module]) }
|
73
95
|
def interesting_ancestors_of(constant)
|
74
|
-
|
75
|
-
|
76
|
-
)
|
96
|
+
inherited_ancestors = Set.new.compare_by_identity.merge(inherited_ancestors_of(constant))
|
97
|
+
|
77
98
|
# TODO: There is actually a bug here where this will drop modules that
|
78
99
|
# may be included twice. For example:
|
79
100
|
#
|
@@ -91,9 +112,9 @@ module Tapioca
|
|
91
112
|
#
|
92
113
|
# Instead, we should only drop the tail matches of the ancestors and
|
93
114
|
# inherited ancestors, past the location of the constant itself.
|
94
|
-
|
95
|
-
|
96
|
-
|
115
|
+
ancestors = Set.new.compare_by_identity.merge(ancestors_of(constant))
|
116
|
+
|
117
|
+
(ancestors - inherited_ancestors).to_a
|
97
118
|
end
|
98
119
|
end
|
99
120
|
end
|
@@ -15,6 +15,11 @@ module Tapioca
|
|
15
15
|
def on_scope(event)
|
16
16
|
event.node.detach if @pipeline.symbol_in_payload?(event.symbol) && event.node.empty?
|
17
17
|
end
|
18
|
+
|
19
|
+
sig { override.params(event: NodeAdded).returns(T::Boolean) }
|
20
|
+
def ignore?(event)
|
21
|
+
event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
|
22
|
+
end
|
18
23
|
end
|
19
24
|
end
|
20
25
|
end
|
@@ -23,6 +23,11 @@ module Tapioca
|
|
23
23
|
node << RBI::Helper.new("final") if T::Private::Final.final_module?(constant)
|
24
24
|
node << RBI::Helper.new("sealed") if T::Private::Sealed.sealed_module?(constant)
|
25
25
|
end
|
26
|
+
|
27
|
+
sig { override.params(event: NodeAdded).returns(T::Boolean) }
|
28
|
+
def ignore?(event)
|
29
|
+
event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
|
30
|
+
end
|
26
31
|
end
|
27
32
|
end
|
28
33
|
end
|