tapioca 0.8.3 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|