tapioca 0.10.2 → 0.10.3
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/README.md +5 -0
- data/lib/tapioca/cli.rb +15 -2
- data/lib/tapioca/commands/check_shims.rb +11 -19
- data/lib/tapioca/commands/dsl.rb +6 -1
- data/lib/tapioca/dsl/compilers/active_record_associations.rb +35 -0
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +3 -9
- data/lib/tapioca/dsl/compilers/protobuf.rb +12 -1
- data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +19 -0
- data/lib/tapioca/dsl/helpers/graphql_type_helper.rb +1 -1
- data/lib/tapioca/gem/pipeline.rb +4 -6
- data/lib/tapioca/helpers/rbi_helper.rb +4 -12
- data/lib/tapioca/helpers/sorbet_helper.rb +1 -3
- data/lib/tapioca/loaders/dsl.rb +8 -6
- data/lib/tapioca/loaders/loader.rb +5 -5
- data/lib/tapioca/rbi_ext/model.rb +5 -2
- data/lib/tapioca/runtime/reflection.rb +55 -0
- data/lib/tapioca/static/symbol_loader.rb +3 -3
- data/lib/tapioca/static/symbol_table_parser.rb +6 -0
- data/lib/tapioca/version.rb +1 -1
- metadata +6 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c5b81fee880c497fca1e34c644d6da53e4f155e45f564c95eb886f0f6c30d69
|
4
|
+
data.tar.gz: d0973ab750b577064e5891c0fbd9dd71ddeb82b54d7d8dfcabad4841052e8d6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 105ab9194d3e62657fedff6d0fd78b187980b5084af80be294690c00a86ac1544b29bd9d86951f50072c895516ce1541251ac2ff05cbb3a2acbbee5d0e103b51
|
7
|
+
data.tar.gz: 612f856fd4b36301dbfee4cdd80615ee4a684447ea077037c5a72e1c7c216be7c465aae13a5b4462a8db9889929765703293d2935036d7ac1e94b8d21d4ee5fb
|
data/README.md
CHANGED
@@ -473,6 +473,8 @@ Options:
|
|
473
473
|
-e, [--environment=ENVIRONMENT] # The Rack/Rails environment to use when generating RBIs
|
474
474
|
# Default: development
|
475
475
|
-l, [--list-compilers], [--no-list-compilers] # List all loaded compilers
|
476
|
+
[--app-root=APP_ROOT] # The path to the Rails application
|
477
|
+
# Default: .
|
476
478
|
-c, [--config=<config file path>] # Path to the Tapioca configuration file
|
477
479
|
# Default: sorbet/tapioca/config.yml
|
478
480
|
-V, [--verbose], [--no-verbose] # Verbose output for debugging purposes
|
@@ -635,6 +637,8 @@ There are two main parts to the DSL compiler API: `gather_constants` and `decora
|
|
635
637
|
* The `gather_constants` class method collects all classes (or modules) that should be processed by this specific DSL compiler.
|
636
638
|
* The `decorate` method defines how to generate the necessary RBI definitions for the gathered constants.
|
637
639
|
|
640
|
+
Every compiler must declare the type member `ConstantType` in order for Sorbet to understand what the return type of the `constant` attribute reader is. It needs to be assigned the correct type variable matching the type of constants that `gather_constants` returns. This generic variable allows Sorbet to type-check method calls on the `constant` reader in your `decorate` method. See the Sorbet documentation on [generics](https://sorbet.org/docs/generics) for more information.
|
641
|
+
|
638
642
|
You can now run the new RBI compiler through the normal DSL generation process (your custom compiler will be loaded automatically by Tapioca):
|
639
643
|
|
640
644
|
```shell
|
@@ -822,6 +826,7 @@ dsl:
|
|
822
826
|
rbi_max_line_length: 120
|
823
827
|
environment: development
|
824
828
|
list_compilers: false
|
829
|
+
app_root: "."
|
825
830
|
gem:
|
826
831
|
outdir: sorbet/rbi/gems
|
827
832
|
file_header: true
|
data/lib/tapioca/cli.rb
CHANGED
@@ -9,6 +9,8 @@ module Tapioca
|
|
9
9
|
|
10
10
|
FILE_HEADER_OPTION_DESC = "Add a \"This file is generated\" header on top of each generated RBI file"
|
11
11
|
|
12
|
+
check_unknown_options!
|
13
|
+
|
12
14
|
class_option :config,
|
13
15
|
aliases: ["-c"],
|
14
16
|
banner: "<config file path>",
|
@@ -121,6 +123,10 @@ module Tapioca
|
|
121
123
|
type: :boolean,
|
122
124
|
desc: "List all loaded compilers",
|
123
125
|
default: false
|
126
|
+
option :app_root,
|
127
|
+
type: :string,
|
128
|
+
desc: "The path to the Rails application",
|
129
|
+
default: "."
|
124
130
|
def dsl(*constants)
|
125
131
|
set_environment(options)
|
126
132
|
|
@@ -136,6 +142,7 @@ module Tapioca
|
|
136
142
|
verbose: options[:verbose],
|
137
143
|
number_of_workers: options[:workers],
|
138
144
|
rbi_formatter: rbi_formatter(options),
|
145
|
+
app_root: options[:app_root],
|
139
146
|
)
|
140
147
|
|
141
148
|
Tapioca.silence_warnings do
|
@@ -279,7 +286,10 @@ module Tapioca
|
|
279
286
|
payload: options[:payload],
|
280
287
|
number_of_workers: options[:workers],
|
281
288
|
)
|
282
|
-
|
289
|
+
|
290
|
+
Tapioca.silence_warnings do
|
291
|
+
command.execute
|
292
|
+
end
|
283
293
|
end
|
284
294
|
|
285
295
|
desc "annotations", "Pull gem RBI annotations from remote sources"
|
@@ -305,7 +315,10 @@ module Tapioca
|
|
305
315
|
netrc_file: netrc_file(options),
|
306
316
|
typed_overrides: options[:typed_overrides],
|
307
317
|
)
|
308
|
-
|
318
|
+
|
319
|
+
Tapioca.silence_warnings do
|
320
|
+
command.execute
|
321
|
+
end
|
309
322
|
end
|
310
323
|
|
311
324
|
map ["--version", "-v"] => :__print_version
|
@@ -51,26 +51,18 @@ module Tapioca
|
|
51
51
|
payload_path = T.let(nil, T.nilable(String))
|
52
52
|
|
53
53
|
if @payload
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
ERROR
|
64
|
-
end
|
65
|
-
|
66
|
-
index_rbis(index, "payload", payload_path, number_of_workers: @number_of_workers)
|
54
|
+
Dir.mktmpdir do |dir|
|
55
|
+
payload_path = dir
|
56
|
+
result = sorbet("--no-config --print=payload-sources:#{payload_path}")
|
57
|
+
|
58
|
+
unless result.status
|
59
|
+
raise Thor::Error, <<~ERROR
|
60
|
+
"Sorbet failed to dump payload"
|
61
|
+
#{result.err}
|
62
|
+
ERROR
|
67
63
|
end
|
68
|
-
|
69
|
-
|
70
|
-
The version of Sorbet used in your Gemfile.lock does not support `--print=payload-sources`
|
71
|
-
Current: v#{SORBET_GEM_SPEC.version}
|
72
|
-
Required: #{FEATURE_REQUIREMENTS[:print_payload_sources]}
|
73
|
-
ERROR
|
64
|
+
|
65
|
+
index_rbis(index, "payload", payload_path, number_of_workers: @number_of_workers)
|
74
66
|
end
|
75
67
|
end
|
76
68
|
|
data/lib/tapioca/commands/dsl.rb
CHANGED
@@ -22,6 +22,7 @@ module Tapioca
|
|
22
22
|
auto_strictness: T::Boolean,
|
23
23
|
gem_dir: String,
|
24
24
|
rbi_formatter: RBIFormatter,
|
25
|
+
app_root: String,
|
25
26
|
).void
|
26
27
|
end
|
27
28
|
def initialize(
|
@@ -37,7 +38,8 @@ module Tapioca
|
|
37
38
|
number_of_workers: nil,
|
38
39
|
auto_strictness: true,
|
39
40
|
gem_dir: DEFAULT_GEM_DIR,
|
40
|
-
rbi_formatter: DEFAULT_RBI_FORMATTER
|
41
|
+
rbi_formatter: DEFAULT_RBI_FORMATTER,
|
42
|
+
app_root: "."
|
41
43
|
)
|
42
44
|
@requested_constants = requested_constants
|
43
45
|
@outpath = outpath
|
@@ -52,6 +54,7 @@ module Tapioca
|
|
52
54
|
@auto_strictness = auto_strictness
|
53
55
|
@gem_dir = gem_dir
|
54
56
|
@rbi_formatter = rbi_formatter
|
57
|
+
@app_root = app_root
|
55
58
|
|
56
59
|
super()
|
57
60
|
end
|
@@ -61,6 +64,7 @@ module Tapioca
|
|
61
64
|
Loaders::Dsl.load_application(
|
62
65
|
tapioca_path: @tapioca_path,
|
63
66
|
eager_load: @requested_constants.empty?,
|
67
|
+
app_root: @app_root,
|
64
68
|
)
|
65
69
|
|
66
70
|
pipeline = create_pipeline
|
@@ -87,6 +91,7 @@ module Tapioca
|
|
87
91
|
Loaders::Dsl.load_application(
|
88
92
|
tapioca_path: @tapioca_path,
|
89
93
|
eager_load: @requested_constants.empty?,
|
94
|
+
app_root: @app_root,
|
90
95
|
)
|
91
96
|
|
92
97
|
if @should_verify
|
@@ -241,6 +241,7 @@ module Tapioca
|
|
241
241
|
|
242
242
|
klass.create_method(
|
243
243
|
association_name.to_s,
|
244
|
+
comments: association_comments(reflection),
|
244
245
|
return_type: relation_class,
|
245
246
|
)
|
246
247
|
klass.create_method(
|
@@ -320,6 +321,40 @@ module Tapioca
|
|
320
321
|
end
|
321
322
|
end
|
322
323
|
|
324
|
+
sig { params(reflection: ReflectionType).returns(T::Array[RBI::Comment]) }
|
325
|
+
def association_comments(reflection)
|
326
|
+
anchor_name = case reflection
|
327
|
+
when ActiveRecord::Reflection::HasOneReflection
|
328
|
+
"the-has-one-association"
|
329
|
+
when ActiveRecord::Reflection::HasManyReflection
|
330
|
+
"the-has-many-association"
|
331
|
+
when ActiveRecord::Reflection::HasAndBelongsToManyReflection
|
332
|
+
"the-has-and-belongs-to-many-association"
|
333
|
+
when ActiveRecord::Reflection::BelongsToReflection
|
334
|
+
"the-belongs-to-association"
|
335
|
+
when ActiveRecord::Reflection::ThroughReflection
|
336
|
+
delegate_reflection = reflection.send(:delegate_reflection)
|
337
|
+
declaration = declaration(delegate_reflection)
|
338
|
+
if T.must(declaration).match?("has_one")
|
339
|
+
"the-has-one-through-association"
|
340
|
+
else
|
341
|
+
"the-has-many-through-association"
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
if anchor_name
|
346
|
+
url = "https://guides.rubyonrails.org/association_basics.html##{anchor_name}"
|
347
|
+
association_name = anchor_name.sub(/^the-(.*)-association$/, '\1')
|
348
|
+
comment = <<~MSG
|
349
|
+
This method is created by ActiveRecord on the `#{reflection.active_record.name}` class because it declared `#{declaration(reflection)}`.
|
350
|
+
🔗 [Rails guide for `#{association_name.gsub("-", "_")}` association](#{url})
|
351
|
+
MSG
|
352
|
+
[RBI::Comment.new(comment)]
|
353
|
+
else
|
354
|
+
[]
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
323
358
|
sig do
|
324
359
|
params(
|
325
360
|
reflection: ReflectionType,
|
@@ -243,15 +243,9 @@ module Tapioca
|
|
243
243
|
# The model always extends the generated relation module
|
244
244
|
model.create_extend(RelationMethodsModuleName)
|
245
245
|
|
246
|
-
#
|
247
|
-
#
|
248
|
-
|
249
|
-
# `T::Array[NilClass]`, otherwise.
|
250
|
-
if sorbet_supports?(:to_ary_nil_support)
|
251
|
-
# Type the `to_ary` method as returning `NilClass` so that flatten stops recursing
|
252
|
-
# See https://github.com/sorbet/sorbet/pull/4706 for details
|
253
|
-
model.create_method("to_ary", return_type: "NilClass", visibility: RBI::Private.new)
|
254
|
-
end
|
246
|
+
# Type the `to_ary` method as returning `NilClass` so that flatten stops recursing
|
247
|
+
# See https://github.com/sorbet/sorbet/pull/4706 for details
|
248
|
+
model.create_method("to_ary", return_type: "NilClass", visibility: RBI::Private.new)
|
255
249
|
|
256
250
|
create_relation_class(model)
|
257
251
|
create_association_relation_class(model)
|
@@ -95,7 +95,18 @@ module Tapioca
|
|
95
95
|
case descriptor
|
96
96
|
when Google::Protobuf::EnumDescriptor
|
97
97
|
descriptor.to_h.each do |sym, val|
|
98
|
-
|
98
|
+
# For each enum value, create a namespaced constant on the root rather than an un-namespaced
|
99
|
+
# constant within the class. This is because un-namespaced constants might conflict with reserved
|
100
|
+
# Ruby words, such as "BEGIN." By namespacing them, we avoid this problem.
|
101
|
+
#
|
102
|
+
# Invalid syntax:
|
103
|
+
# class Foo
|
104
|
+
# BEGIN = 3
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# Valid syntax:
|
108
|
+
# Foo::BEGIN = 3
|
109
|
+
root.create_constant("#{constant}::#{sym}", value: val.to_s)
|
99
110
|
end
|
100
111
|
|
101
112
|
klass.create_method(
|
@@ -41,6 +41,8 @@ module Tapioca
|
|
41
41
|
"::ActiveSupport::TimeWithZone"
|
42
42
|
when ActiveRecord::Enum::EnumType
|
43
43
|
"::String"
|
44
|
+
when ActiveRecord::Type::Serialized
|
45
|
+
serialized_column_type(column_type)
|
44
46
|
else
|
45
47
|
handle_unknown_type(column_type)
|
46
48
|
end
|
@@ -119,6 +121,23 @@ module Tapioca
|
|
119
121
|
"T.any(::String, ::Symbol)"
|
120
122
|
end
|
121
123
|
end
|
124
|
+
|
125
|
+
sig { params(column_type: ActiveRecord::Type::Serialized).returns(String) }
|
126
|
+
def serialized_column_type(column_type)
|
127
|
+
case column_type.coder
|
128
|
+
when ActiveRecord::Coders::YAMLColumn
|
129
|
+
case column_type.coder.object_class
|
130
|
+
when Array.singleton_class
|
131
|
+
"T::Array[T.untyped]"
|
132
|
+
when Hash.singleton_class
|
133
|
+
"T::Hash[T.untyped, T.untyped]"
|
134
|
+
else
|
135
|
+
"T.untyped"
|
136
|
+
end
|
137
|
+
else
|
138
|
+
"T.untyped"
|
139
|
+
end
|
140
|
+
end
|
122
141
|
end
|
123
142
|
end
|
124
143
|
end
|
@@ -25,7 +25,7 @@ module Tapioca
|
|
25
25
|
when GraphQL::Types::ISO8601Date.singleton_class
|
26
26
|
type_for_constant(Date)
|
27
27
|
when GraphQL::Types::ISO8601DateTime.singleton_class
|
28
|
-
type_for_constant(
|
28
|
+
type_for_constant(Time)
|
29
29
|
when GraphQL::Types::JSON.singleton_class
|
30
30
|
"T::Hash[::String, T.untyped]"
|
31
31
|
when GraphQL::Schema::Enum.singleton_class
|
data/lib/tapioca/gem/pipeline.rb
CHANGED
@@ -342,7 +342,7 @@ module Tapioca
|
|
342
342
|
|
343
343
|
sig { params(constant: Module, strict: T::Boolean).returns(T::Boolean) }
|
344
344
|
def defined_in_gem?(constant, strict: true)
|
345
|
-
files =
|
345
|
+
files = get_file_candidates(constant)
|
346
346
|
.merge(Runtime::Trackers::ConstantDefinition.files_for(constant))
|
347
347
|
|
348
348
|
return !strict if files.empty?
|
@@ -352,13 +352,11 @@ module Tapioca
|
|
352
352
|
end
|
353
353
|
end
|
354
354
|
|
355
|
-
sig { params(constant: Module).returns(T::
|
355
|
+
sig { params(constant: Module).returns(T::Set[String]) }
|
356
356
|
def get_file_candidates(constant)
|
357
|
-
|
358
|
-
|
359
|
-
wrapped_module.send(:method_candidates).flatten.filter_map(&:source_file).uniq
|
357
|
+
file_candidates_for(constant)
|
360
358
|
rescue ArgumentError, NameError
|
361
|
-
|
359
|
+
Set.new
|
362
360
|
end
|
363
361
|
|
364
362
|
sig { params(name: String).void }
|
@@ -23,22 +23,14 @@ module Tapioca
|
|
23
23
|
def serialize_type_variable(type, variance, fixed, upper, lower)
|
24
24
|
variance = nil if variance == :invariant
|
25
25
|
|
26
|
-
bounds = []
|
27
|
-
bounds << "fixed: #{fixed}" if fixed
|
28
|
-
bounds << "lower: #{lower}" if lower
|
29
|
-
bounds << "upper: #{upper}" if upper
|
30
|
-
|
31
|
-
parameters = []
|
32
26
|
block = []
|
27
|
+
block << "fixed: #{fixed}" if fixed
|
28
|
+
block << "lower: #{lower}" if lower
|
29
|
+
block << "upper: #{upper}" if upper
|
33
30
|
|
31
|
+
parameters = []
|
34
32
|
parameters << ":#{variance}" if variance
|
35
33
|
|
36
|
-
if sorbet_supports?(:type_variable_block_syntax)
|
37
|
-
block = bounds
|
38
|
-
else
|
39
|
-
parameters.concat(bounds)
|
40
|
-
end
|
41
|
-
|
42
34
|
serialized = type.dup
|
43
35
|
serialized << "(#{parameters.join(", ")})" unless parameters.empty?
|
44
36
|
serialized << " { { #{block.join(", ")} } }" unless block.empty?
|
@@ -20,9 +20,7 @@ module Tapioca
|
|
20
20
|
SORBET_PAYLOAD_URL = "https://github.com/sorbet/sorbet/tree/master/rbi"
|
21
21
|
|
22
22
|
FEATURE_REQUIREMENTS = T.let({
|
23
|
-
|
24
|
-
print_payload_sources: ::Gem::Requirement.new(">= 0.5.9818"), # https://github.com/sorbet/sorbet/pull/5504
|
25
|
-
type_variable_block_syntax: ::Gem::Requirement.new(">= 0.5.9892"), # https://github.com/sorbet/sorbet/pull/5639
|
23
|
+
# feature_name: ::Gem::Requirement.new(">= ___"), # https://github.com/sorbet/sorbet/pull/___
|
26
24
|
}.freeze, T::Hash[Symbol, ::Gem::Requirement])
|
27
25
|
|
28
26
|
sig { params(sorbet_args: String).returns(Spoom::ExecResult) }
|
data/lib/tapioca/loaders/dsl.rb
CHANGED
@@ -9,9 +9,9 @@ module Tapioca
|
|
9
9
|
class << self
|
10
10
|
extend T::Sig
|
11
11
|
|
12
|
-
sig { params(tapioca_path: String, eager_load: T::Boolean).void }
|
13
|
-
def load_application(tapioca_path:, eager_load: true)
|
14
|
-
loader = new(tapioca_path: tapioca_path)
|
12
|
+
sig { params(tapioca_path: String, eager_load: T::Boolean, app_root: String).void }
|
13
|
+
def load_application(tapioca_path:, eager_load: true, app_root: ".")
|
14
|
+
loader = new(tapioca_path: tapioca_path, app_root: app_root)
|
15
15
|
loader.load
|
16
16
|
end
|
17
17
|
end
|
@@ -26,12 +26,13 @@ module Tapioca
|
|
26
26
|
|
27
27
|
protected
|
28
28
|
|
29
|
-
sig { params(tapioca_path: String, eager_load: T::Boolean).void }
|
30
|
-
def initialize(tapioca_path:, eager_load: true)
|
29
|
+
sig { params(tapioca_path: String, eager_load: T::Boolean, app_root: String).void }
|
30
|
+
def initialize(tapioca_path:, eager_load: true, app_root: ".")
|
31
31
|
super()
|
32
32
|
|
33
33
|
@tapioca_path = tapioca_path
|
34
34
|
@eager_load = eager_load
|
35
|
+
@app_root = app_root
|
35
36
|
end
|
36
37
|
|
37
38
|
sig { void }
|
@@ -64,6 +65,7 @@ module Tapioca
|
|
64
65
|
load_rails_application(
|
65
66
|
environment_load: true,
|
66
67
|
eager_load: @eager_load,
|
68
|
+
app_root: @app_root,
|
67
69
|
)
|
68
70
|
|
69
71
|
say("Done", :green)
|
@@ -71,7 +73,7 @@ module Tapioca
|
|
71
73
|
|
72
74
|
sig { void }
|
73
75
|
def abort_if_pending_migrations!
|
74
|
-
return unless File.exist?("config/application.rb")
|
76
|
+
return unless File.exist?("#{@app_root}/config/application.rb")
|
75
77
|
return unless defined?(::Rake)
|
76
78
|
|
77
79
|
Rails.application.load_tasks
|
@@ -33,16 +33,16 @@ module Tapioca
|
|
33
33
|
load_rails_engines
|
34
34
|
end
|
35
35
|
|
36
|
-
sig { params(environment_load: T::Boolean, eager_load: T::Boolean).void }
|
37
|
-
def load_rails_application(environment_load: false, eager_load: false)
|
38
|
-
return unless File.exist?("config/application.rb")
|
36
|
+
sig { params(environment_load: T::Boolean, eager_load: T::Boolean, app_root: String).void }
|
37
|
+
def load_rails_application(environment_load: false, eager_load: false, app_root: ".")
|
38
|
+
return unless File.exist?("#{app_root}/config/application.rb")
|
39
39
|
|
40
40
|
silence_deprecations
|
41
41
|
|
42
42
|
if environment_load
|
43
|
-
require "
|
43
|
+
require "./#{app_root}/config/environment"
|
44
44
|
else
|
45
|
-
require "
|
45
|
+
require "./#{app_root}/config/application"
|
46
46
|
end
|
47
47
|
|
48
48
|
eager_load_rails_app if eager_load
|
@@ -83,13 +83,16 @@ module RBI
|
|
83
83
|
return_type: String,
|
84
84
|
class_method: T::Boolean,
|
85
85
|
visibility: RBI::Visibility,
|
86
|
+
comments: T::Array[RBI::Comment],
|
86
87
|
).void
|
87
88
|
end
|
88
|
-
def create_method(name, parameters: [], return_type: "T.untyped", class_method: false, visibility: RBI::Public.new
|
89
|
+
def create_method(name, parameters: [], return_type: "T.untyped", class_method: false, visibility: RBI::Public.new,
|
90
|
+
comments: [])
|
89
91
|
return unless Tapioca::RBIHelper.valid_method_name?(name)
|
90
92
|
|
91
93
|
sig = RBI::Sig.new(return_type: return_type)
|
92
|
-
method = RBI::Method.new(name, sigs: [sig], is_singleton: class_method, visibility: visibility
|
94
|
+
method = RBI::Method.new(name, sigs: [sig], is_singleton: class_method, visibility: visibility,
|
95
|
+
comments: comments)
|
93
96
|
parameters.each do |param|
|
94
97
|
method << param.param
|
95
98
|
sig << RBI::SigParam.new(param.param.name, param.type)
|
@@ -183,6 +183,61 @@ module Tapioca
|
|
183
183
|
|
184
184
|
T.cast(result, Module)
|
185
185
|
end
|
186
|
+
|
187
|
+
sig { params(constant: Module).returns(T::Set[String]) }
|
188
|
+
def file_candidates_for(constant)
|
189
|
+
relevant_methods_for(constant).filter_map do |method|
|
190
|
+
method.source_location&.first
|
191
|
+
end.to_set
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
sig { params(constant: Module).returns(T::Array[UnboundMethod]) }
|
197
|
+
def relevant_methods_for(constant)
|
198
|
+
methods = methods_for(constant).select(&:source_location)
|
199
|
+
.reject { |x| method_defined_by_forwardable_module?(x) }
|
200
|
+
|
201
|
+
return methods unless methods.empty?
|
202
|
+
|
203
|
+
constants_of(constant).flat_map do |const_name|
|
204
|
+
if (mod = child_module_for_parent_with_name(constant, const_name.to_s))
|
205
|
+
relevant_methods_for(mod)
|
206
|
+
else
|
207
|
+
[]
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
sig { params(constant: Module).returns(T::Array[UnboundMethod]) }
|
213
|
+
def methods_for(constant)
|
214
|
+
modules = [constant, singleton_class_of(constant)]
|
215
|
+
method_list_methods = [
|
216
|
+
PUBLIC_INSTANCE_METHODS_METHOD,
|
217
|
+
PROTECTED_INSTANCE_METHODS_METHOD,
|
218
|
+
PRIVATE_INSTANCE_METHODS_METHOD,
|
219
|
+
]
|
220
|
+
|
221
|
+
modules.product(method_list_methods).flat_map do |mod, method_list_method|
|
222
|
+
method_list_method.bind_call(mod, false).map { |name| mod.instance_method(name) }
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
sig { params(parent: Module, name: String).returns(T.nilable(Module)) }
|
227
|
+
def child_module_for_parent_with_name(parent, name)
|
228
|
+
return if parent.autoload?(name)
|
229
|
+
|
230
|
+
child = constantize(name, inherit: true, namespace: parent)
|
231
|
+
return unless Module === child
|
232
|
+
return unless name_of(child) == "#{name_of(parent)}::#{name}"
|
233
|
+
|
234
|
+
child
|
235
|
+
end
|
236
|
+
|
237
|
+
sig { params(method: UnboundMethod).returns(T::Boolean) }
|
238
|
+
def method_defined_by_forwardable_module?(method)
|
239
|
+
method.source_location&.first == Object.const_source_location(:Forwardable)&.first
|
240
|
+
end
|
186
241
|
end
|
187
242
|
end
|
188
243
|
end
|
@@ -62,14 +62,14 @@ module Tapioca
|
|
62
62
|
|
63
63
|
sig { params(paths: T::Array[Pathname]).returns(T::Set[String]) }
|
64
64
|
def symbols_from_paths(paths)
|
65
|
-
output =
|
65
|
+
output = Tempfile.create("sorbet") do |file|
|
66
66
|
file.write(Array(paths).join("\n"))
|
67
67
|
file.flush
|
68
68
|
|
69
69
|
symbol_table_json_from("@#{file.path.shellescape}")
|
70
|
-
end
|
70
|
+
end
|
71
71
|
|
72
|
-
return Set.new if output.
|
72
|
+
return Set.new if output.empty?
|
73
73
|
|
74
74
|
SymbolTableParser.parse_json(output)
|
75
75
|
end
|
@@ -43,6 +43,12 @@ module Tapioca
|
|
43
43
|
|
44
44
|
next if name.nil?
|
45
45
|
next unless SKIP_PARSE_KINDS.include?(kind)
|
46
|
+
|
47
|
+
# Turn singleton class names to attached class names
|
48
|
+
if (match_data = name.match(/<Class:(.*)>/))
|
49
|
+
name = match_data[1]
|
50
|
+
end
|
51
|
+
|
46
52
|
next if name.match?(/[<>()$]/)
|
47
53
|
next if name.match?(/^[0-9]+$/)
|
48
54
|
next if name == "T::Helpers"
|
data/lib/tapioca/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tapioca
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ufuk Kayserilioglu
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date: 2022-
|
14
|
+
date: 2022-11-10 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -55,20 +55,6 @@ dependencies:
|
|
55
55
|
- - ">="
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: 1.21.0
|
58
|
-
- !ruby/object:Gem::Dependency
|
59
|
-
name: pry
|
60
|
-
requirement: !ruby/object:Gem::Requirement
|
61
|
-
requirements:
|
62
|
-
- - ">="
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
version: 0.12.2
|
65
|
-
type: :runtime
|
66
|
-
prerelease: false
|
67
|
-
version_requirements: !ruby/object:Gem::Requirement
|
68
|
-
requirements:
|
69
|
-
- - ">="
|
70
|
-
- !ruby/object:Gem::Version
|
71
|
-
version: 0.12.2
|
72
58
|
- !ruby/object:Gem::Dependency
|
73
59
|
name: rbi
|
74
60
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,7 +64,7 @@ dependencies:
|
|
78
64
|
version: 0.0.0
|
79
65
|
- - ">="
|
80
66
|
- !ruby/object:Gem::Version
|
81
|
-
version: 0.0.
|
67
|
+
version: 0.0.16
|
82
68
|
type: :runtime
|
83
69
|
prerelease: false
|
84
70
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -88,21 +74,21 @@ dependencies:
|
|
88
74
|
version: 0.0.0
|
89
75
|
- - ">="
|
90
76
|
- !ruby/object:Gem::Version
|
91
|
-
version: 0.0.
|
77
|
+
version: 0.0.16
|
92
78
|
- !ruby/object:Gem::Dependency
|
93
79
|
name: sorbet-static-and-runtime
|
94
80
|
requirement: !ruby/object:Gem::Requirement
|
95
81
|
requirements:
|
96
82
|
- - ">="
|
97
83
|
- !ruby/object:Gem::Version
|
98
|
-
version: 0.5.
|
84
|
+
version: 0.5.9892
|
99
85
|
type: :runtime
|
100
86
|
prerelease: false
|
101
87
|
version_requirements: !ruby/object:Gem::Requirement
|
102
88
|
requirements:
|
103
89
|
- - ">="
|
104
90
|
- !ruby/object:Gem::Version
|
105
|
-
version: 0.5.
|
91
|
+
version: 0.5.9892
|
106
92
|
- !ruby/object:Gem::Dependency
|
107
93
|
name: spoom
|
108
94
|
requirement: !ruby/object:Gem::Requirement
|