tapioca 0.4.0 → 0.4.1
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 +25 -1
- data/README.md +12 -0
- data/Rakefile +15 -4
- data/lib/tapioca.rb +2 -0
- data/lib/tapioca/cli.rb +24 -2
- data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +129 -0
- data/lib/tapioca/compilers/dsl/action_mailer.rb +65 -0
- data/lib/tapioca/compilers/dsl/active_record_associations.rb +285 -0
- data/lib/tapioca/compilers/dsl/active_record_columns.rb +379 -0
- data/lib/tapioca/compilers/dsl/active_record_enum.rb +112 -0
- data/lib/tapioca/compilers/dsl/active_record_identity_cache.rb +213 -0
- data/lib/tapioca/compilers/dsl/active_record_scope.rb +100 -0
- data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +170 -0
- data/lib/tapioca/compilers/dsl/active_resource.rb +140 -0
- data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +126 -0
- data/lib/tapioca/compilers/dsl/base.rb +163 -0
- data/lib/tapioca/compilers/dsl/frozen_record.rb +96 -0
- data/lib/tapioca/compilers/dsl/protobuf.rb +144 -0
- data/lib/tapioca/compilers/dsl/smart_properties.rb +173 -0
- data/lib/tapioca/compilers/dsl/state_machines.rb +378 -0
- data/lib/tapioca/compilers/dsl/url_helpers.rb +83 -0
- data/lib/tapioca/compilers/dsl_compiler.rb +121 -0
- data/lib/tapioca/compilers/requires_compiler.rb +67 -0
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +141 -24
- data/lib/tapioca/config.rb +11 -6
- data/lib/tapioca/config_builder.rb +19 -9
- data/lib/tapioca/constant_locator.rb +1 -0
- data/lib/tapioca/core_ext/class.rb +23 -0
- data/lib/tapioca/generator.rb +187 -21
- data/lib/tapioca/loader.rb +20 -9
- data/lib/tapioca/sorbet_config_parser.rb +77 -0
- data/lib/tapioca/version.rb +1 -1
- metadata +29 -51
@@ -0,0 +1,83 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "parlour"
|
5
|
+
|
6
|
+
begin
|
7
|
+
require "rails"
|
8
|
+
require "action_controller"
|
9
|
+
rescue LoadError
|
10
|
+
return
|
11
|
+
end
|
12
|
+
|
13
|
+
module Tapioca
|
14
|
+
module Compilers
|
15
|
+
module Dsl
|
16
|
+
class UrlHelpers < Base
|
17
|
+
extend T::Sig
|
18
|
+
|
19
|
+
sig { override.params(root: Parlour::RbiGenerator::Namespace, constant: T.class_of(Module)).void }
|
20
|
+
def decorate(root, constant)
|
21
|
+
case constant
|
22
|
+
when GeneratedPathHelpersModule.singleton_class, GeneratedUrlHelpersModule.singleton_class
|
23
|
+
generate_module_for(root, constant)
|
24
|
+
else
|
25
|
+
root.path(constant) do |mod|
|
26
|
+
create_mixins_for(mod, constant, GeneratedUrlHelpersModule)
|
27
|
+
create_mixins_for(mod, constant, GeneratedPathHelpersModule)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
sig { override.returns(T::Enumerable[T.untyped]) }
|
33
|
+
def gather_constants
|
34
|
+
Object.const_set(:GeneratedUrlHelpersModule, Rails.application.routes.named_routes.url_helpers_module)
|
35
|
+
Object.const_set(:GeneratedPathHelpersModule, Rails.application.routes.named_routes.path_helpers_module)
|
36
|
+
|
37
|
+
constants = ObjectSpace.each_object(Module).select do |mod|
|
38
|
+
mod = T.cast(mod, T.class_of(Module))
|
39
|
+
next unless Module.instance_method(:name).bind(mod).call
|
40
|
+
|
41
|
+
includes_helper?(mod, GeneratedUrlHelpersModule) ||
|
42
|
+
includes_helper?(mod, GeneratedPathHelpersModule) ||
|
43
|
+
includes_helper?(mod.singleton_class, GeneratedUrlHelpersModule) ||
|
44
|
+
includes_helper?(mod.singleton_class, GeneratedPathHelpersModule)
|
45
|
+
end
|
46
|
+
|
47
|
+
constants << ActionDispatch::IntegrationTest
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
sig { params(root: Parlour::RbiGenerator::Namespace, constant: T.class_of(Module)).void }
|
53
|
+
def generate_module_for(root, constant)
|
54
|
+
root.create_module(T.must(constant.name)) do |mod|
|
55
|
+
mod.create_include("ActionDispatch::Routing::UrlFor")
|
56
|
+
mod.create_include("ActionDispatch::Routing::PolymorphicRoutes")
|
57
|
+
|
58
|
+
constant.instance_methods(false).each do |method|
|
59
|
+
mod.create_method(
|
60
|
+
method.to_s,
|
61
|
+
parameters: [Parlour::RbiGenerator::Parameter.new("*args", type: "T.untyped")],
|
62
|
+
return_type: "String"
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
sig { params(mod: Parlour::RbiGenerator::Namespace, constant: T.class_of(Module), helper_module: Module).void }
|
69
|
+
def create_mixins_for(mod, constant, helper_module)
|
70
|
+
mod.create_include(T.must(helper_module.name)) if constant.ancestors.include?(helper_module)
|
71
|
+
mod.create_extend(T.must(helper_module.name)) if constant.singleton_class.ancestors.include?(helper_module)
|
72
|
+
end
|
73
|
+
|
74
|
+
sig { params(mod: Module, helper: Module).returns(T::Boolean) }
|
75
|
+
def includes_helper?(mod, helper)
|
76
|
+
superclass_ancestors = mod.superclass&.ancestors if Class === mod
|
77
|
+
superclass_ancestors ||= []
|
78
|
+
(mod.ancestors - superclass_ancestors).include?(helper)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
require "tapioca/compilers/dsl/base"
|
5
|
+
|
6
|
+
module Tapioca
|
7
|
+
module Compilers
|
8
|
+
class DslCompiler
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
sig { returns(T::Enumerable[Dsl::Base]) }
|
12
|
+
attr_reader :generators
|
13
|
+
|
14
|
+
sig { returns(T::Array[Module]) }
|
15
|
+
attr_reader :requested_constants
|
16
|
+
|
17
|
+
sig { returns(T.proc.params(error: String).void) }
|
18
|
+
attr_reader :error_handler
|
19
|
+
|
20
|
+
sig do
|
21
|
+
params(
|
22
|
+
requested_constants: T::Array[Module],
|
23
|
+
requested_generators: T::Array[String],
|
24
|
+
error_handler: T.nilable(T.proc.params(error: String).void)
|
25
|
+
).void
|
26
|
+
end
|
27
|
+
def initialize(requested_constants:, requested_generators: [], error_handler: nil)
|
28
|
+
@generators = T.let(
|
29
|
+
gather_generators(requested_generators),
|
30
|
+
T::Enumerable[Dsl::Base]
|
31
|
+
)
|
32
|
+
@requested_constants = requested_constants
|
33
|
+
@error_handler = error_handler || $stderr.method(:puts)
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { params(blk: T.proc.params(constant: Module, rbi: String).void).void }
|
37
|
+
def run(&blk)
|
38
|
+
constants_to_process = gather_constants(requested_constants)
|
39
|
+
|
40
|
+
if constants_to_process.empty?
|
41
|
+
report_error(<<~ERROR)
|
42
|
+
No classes/modules can be matched for RBI generation.
|
43
|
+
Please check that the requested classes/modules include processable DSL methods.
|
44
|
+
ERROR
|
45
|
+
end
|
46
|
+
|
47
|
+
constants_to_process.sort_by { |c| c.name.to_s }.each do |constant|
|
48
|
+
rbi = rbi_for_constant(constant)
|
49
|
+
next if rbi.nil?
|
50
|
+
|
51
|
+
blk.call(constant, rbi)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
sig { params(requested_generators: T::Array[String]).returns(Proc) }
|
58
|
+
def generator_filter(requested_generators)
|
59
|
+
return proc { true } if requested_generators.empty?
|
60
|
+
|
61
|
+
generators = requested_generators.map(&:downcase)
|
62
|
+
|
63
|
+
proc do |klass|
|
64
|
+
generator = klass.name&.sub(/^Tapioca::Compilers::Dsl::/, '')&.downcase
|
65
|
+
generators.include?(generator)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
sig { params(requested_generators: T::Array[String]).returns(T::Enumerable[Dsl::Base]) }
|
70
|
+
def gather_generators(requested_generators)
|
71
|
+
generator_filter = generator_filter(requested_generators)
|
72
|
+
|
73
|
+
Dsl::Base.descendants.select(&generator_filter).map(&:new)
|
74
|
+
end
|
75
|
+
|
76
|
+
sig { params(requested_constants: T::Array[Module]).returns(T::Set[Module]) }
|
77
|
+
def gather_constants(requested_constants)
|
78
|
+
constants = generators.map(&:processable_constants).reduce(Set.new, :union)
|
79
|
+
constants &= requested_constants unless requested_constants.empty?
|
80
|
+
constants
|
81
|
+
end
|
82
|
+
|
83
|
+
sig { params(constant: Module).returns(T.nilable(String)) }
|
84
|
+
def rbi_for_constant(constant)
|
85
|
+
parlour = Parlour::RbiGenerator.new(sort_namespaces: true)
|
86
|
+
|
87
|
+
generators.each do |generator|
|
88
|
+
next unless generator.handles?(constant)
|
89
|
+
generator.decorate(parlour.root, constant)
|
90
|
+
end
|
91
|
+
|
92
|
+
return if parlour.root.children.empty?
|
93
|
+
|
94
|
+
resolve_conflicts(parlour)
|
95
|
+
|
96
|
+
parlour.rbi("true").strip
|
97
|
+
end
|
98
|
+
|
99
|
+
sig { params(parlour: Parlour::RbiGenerator).void }
|
100
|
+
def resolve_conflicts(parlour)
|
101
|
+
Parlour::ConflictResolver.new.resolve_conflicts(parlour.root) do |msg, candidates|
|
102
|
+
error = StringIO.new
|
103
|
+
error.puts "=== Error ==="
|
104
|
+
error.puts msg
|
105
|
+
error.puts "# Candidates"
|
106
|
+
candidates.each_with_index do |candidate, index|
|
107
|
+
error.puts " #{index}. #{candidate.describe}"
|
108
|
+
end
|
109
|
+
report_error(error.string)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
sig { params(error: String).returns(T.noreturn) }
|
114
|
+
def report_error(error)
|
115
|
+
handler = error_handler
|
116
|
+
handler.call(error)
|
117
|
+
exit(1)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: strict
|
3
|
+
|
4
|
+
require_relative '../sorbet_config_parser'
|
5
|
+
|
6
|
+
module Tapioca
|
7
|
+
module Compilers
|
8
|
+
class RequiresCompiler
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
sig { params(sorbet_path: String).void }
|
12
|
+
def initialize(sorbet_path)
|
13
|
+
@sorbet_path = sorbet_path
|
14
|
+
end
|
15
|
+
|
16
|
+
sig { returns(String) }
|
17
|
+
def compile
|
18
|
+
config = SorbetConfig.parse_file(@sorbet_path)
|
19
|
+
files = collect_files(config)
|
20
|
+
files.flat_map do |file|
|
21
|
+
collect_requires(file).reject do |req|
|
22
|
+
name_in_project?(files, req)
|
23
|
+
end
|
24
|
+
end.sort.uniq.map do |name|
|
25
|
+
"require '#{name}'\n"
|
26
|
+
end.join
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
sig { params(config: SorbetConfig).returns(T::Array[String]) }
|
32
|
+
def collect_files(config)
|
33
|
+
config.paths.flat_map do |path|
|
34
|
+
path = (Pathname.new(@sorbet_path) / "../.." / path).cleanpath
|
35
|
+
if path.directory?
|
36
|
+
Dir.glob("#{path}/**/*.rb", File::FNM_EXTGLOB).reject do |file|
|
37
|
+
file_ignored_by_sorbet?(config, file)
|
38
|
+
end
|
39
|
+
else
|
40
|
+
[path.to_s]
|
41
|
+
end
|
42
|
+
end.sort.uniq
|
43
|
+
end
|
44
|
+
|
45
|
+
sig { params(file_path: String).returns(T::Enumerable[String]) }
|
46
|
+
def collect_requires(file_path)
|
47
|
+
File.read(file_path).lines.map do |line|
|
48
|
+
/^\s*require\s*(\(\s*)?['"](?<name>[^'"]+)['"](\s*\))?/.match(line) { |m| m["name"] }
|
49
|
+
end.compact
|
50
|
+
end
|
51
|
+
|
52
|
+
sig { params(config: SorbetConfig, file: String).returns(T::Boolean) }
|
53
|
+
def file_ignored_by_sorbet?(config, file)
|
54
|
+
config.ignore.any? do |path|
|
55
|
+
Regexp.new(Regexp.escape(path)) =~ file
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
sig { params(files: T::Enumerable[String], name: String).returns(T::Boolean) }
|
60
|
+
def name_in_project?(files, name)
|
61
|
+
files.any? do |file|
|
62
|
+
File.basename(file, '.rb') == name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -176,13 +176,43 @@ module Tapioca
|
|
176
176
|
return if symbol_ignored?(name) && methods.nil?
|
177
177
|
|
178
178
|
[
|
179
|
+
compile_module_helpers(constant),
|
179
180
|
compile_mixins(constant),
|
180
181
|
compile_mixes_in_class_methods(constant),
|
182
|
+
compile_props(constant),
|
181
183
|
methods,
|
182
184
|
].select { |b| b != "" }.join("\n\n")
|
183
185
|
end
|
184
186
|
end
|
185
187
|
|
188
|
+
sig { params(constant: Module).returns(String) }
|
189
|
+
def compile_module_helpers(constant)
|
190
|
+
abstract_type = T::Private::Abstract::Data.get(constant, :abstract_type)
|
191
|
+
|
192
|
+
if abstract_type
|
193
|
+
indented("#{abstract_type}!")
|
194
|
+
elsif T::Private::Final.final_module?(constant)
|
195
|
+
indented("final!")
|
196
|
+
elsif T::Private::Sealed.sealed_module?(constant)
|
197
|
+
indented("sealed!")
|
198
|
+
else
|
199
|
+
""
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
sig { params(constant: Module).returns(String) }
|
204
|
+
def compile_props(constant)
|
205
|
+
return "" unless T::Props::ClassMethods === constant
|
206
|
+
|
207
|
+
constant.props.map do |name, prop|
|
208
|
+
method = "prop"
|
209
|
+
method = "const" if prop.fetch(:immutable, false)
|
210
|
+
type = prop.fetch(:type_object, "T.untyped")
|
211
|
+
|
212
|
+
indented("#{method} :#{name}, #{type}")
|
213
|
+
end.join("\n")
|
214
|
+
end
|
215
|
+
|
186
216
|
sig { params(name: String, constant: Module).returns(T.nilable(String)) }
|
187
217
|
def compile_subconstants(name, constant)
|
188
218
|
output = constants_of(constant).sort.uniq.map do |constant_name|
|
@@ -379,7 +409,7 @@ module Tapioca
|
|
379
409
|
)
|
380
410
|
|
381
411
|
instance_methods = compile_directly_owned_methods(name, constant)
|
382
|
-
singleton_methods = compile_directly_owned_methods(name, singleton_class_of(constant)
|
412
|
+
singleton_methods = compile_directly_owned_methods(name, singleton_class_of(constant))
|
383
413
|
|
384
414
|
return if symbol_ignored?(name) && instance_methods.empty? && singleton_methods.empty?
|
385
415
|
|
@@ -392,24 +422,44 @@ module Tapioca
|
|
392
422
|
|
393
423
|
sig { params(module_name: String, mod: Module, for_visibility: T::Array[Symbol]).returns(String) }
|
394
424
|
def compile_directly_owned_methods(module_name, mod, for_visibility = [:public, :protected, :private])
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
425
|
+
indent_step = 0
|
426
|
+
preamble = nil
|
427
|
+
postamble = nil
|
428
|
+
|
429
|
+
if mod.singleton_class?
|
430
|
+
indent_step = 1
|
431
|
+
preamble = indented("class << self")
|
432
|
+
postamble = indented("end")
|
433
|
+
end
|
403
434
|
|
404
|
-
|
405
|
-
|
406
|
-
|
435
|
+
methods = with_indentation(indent_step) do
|
436
|
+
method_names_by_visibility(mod)
|
437
|
+
.delete_if { |visibility, _method_list| !for_visibility.include?(visibility) }
|
438
|
+
.flat_map do |visibility, method_list|
|
439
|
+
compiled = method_list.sort!.map do |name|
|
440
|
+
next if name == :initialize
|
441
|
+
compile_method(module_name, mod, mod.instance_method(name))
|
442
|
+
end
|
443
|
+
compiled.compact!
|
444
|
+
|
445
|
+
unless compiled.empty? || visibility == :public
|
446
|
+
# add visibility badge
|
447
|
+
compiled.unshift('', indented(visibility.to_s), '')
|
448
|
+
end
|
449
|
+
|
450
|
+
compiled
|
407
451
|
end
|
452
|
+
.compact
|
453
|
+
.join("\n")
|
454
|
+
end
|
408
455
|
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
456
|
+
return "" if methods.strip == ""
|
457
|
+
|
458
|
+
[
|
459
|
+
preamble,
|
460
|
+
methods,
|
461
|
+
postamble,
|
462
|
+
].compact.join("\n")
|
413
463
|
end
|
414
464
|
|
415
465
|
sig { params(mod: Module).returns(T::Hash[Symbol, T::Array[Symbol]]) }
|
@@ -421,6 +471,16 @@ module Tapioca
|
|
421
471
|
}
|
422
472
|
end
|
423
473
|
|
474
|
+
sig { params(constant: Module, method_name: String).returns(T::Boolean) }
|
475
|
+
def struct_method?(constant, method_name)
|
476
|
+
return false unless T::Props::ClassMethods === constant
|
477
|
+
|
478
|
+
constant
|
479
|
+
.props
|
480
|
+
.keys
|
481
|
+
.include?(method_name.gsub(/=$/, '').to_sym)
|
482
|
+
end
|
483
|
+
|
424
484
|
sig do
|
425
485
|
params(
|
426
486
|
symbol_name: String,
|
@@ -433,8 +493,13 @@ module Tapioca
|
|
433
493
|
return unless method.owner == constant
|
434
494
|
return if symbol_ignored?(symbol_name) && !method_in_gem?(method)
|
435
495
|
|
496
|
+
signature = signature_of(method)
|
497
|
+
method = signature.method if signature
|
498
|
+
|
436
499
|
method_name = method.name.to_s
|
437
500
|
return unless valid_method_name?(method_name)
|
501
|
+
return if struct_method?(constant, method_name)
|
502
|
+
return if method_name.start_with?("__t_props_generated_")
|
438
503
|
|
439
504
|
params = T.let(method.parameters, T::Array[T::Array[Symbol]])
|
440
505
|
parameters = params.map do |(type, name)|
|
@@ -447,13 +512,13 @@ module Tapioca
|
|
447
512
|
when :req
|
448
513
|
name
|
449
514
|
when :opt
|
450
|
-
"#{name} =
|
515
|
+
"#{name} = T.unsafe(nil)"
|
451
516
|
when :rest
|
452
517
|
"*#{name}"
|
453
518
|
when :keyreq
|
454
519
|
"#{name}:"
|
455
520
|
when :key
|
456
|
-
"#{name}:
|
521
|
+
"#{name}: T.unsafe(nil)"
|
457
522
|
when :keyrest
|
458
523
|
"**#{name}"
|
459
524
|
when :block
|
@@ -461,10 +526,54 @@ module Tapioca
|
|
461
526
|
end
|
462
527
|
end.join(', ')
|
463
528
|
|
464
|
-
method_name = "#{'self.' if constant.singleton_class?}#{method_name}"
|
465
529
|
parameters = "(#{parameters})" if parameters != ""
|
466
530
|
|
467
|
-
indented(
|
531
|
+
signature_str = indented(compile_signature(signature)) if signature
|
532
|
+
[
|
533
|
+
signature_str,
|
534
|
+
indented("def #{method_name}#{parameters}; end"),
|
535
|
+
].compact.join("\n")
|
536
|
+
end
|
537
|
+
|
538
|
+
TYPE_PARAMETER_MATCHER = /T\.type_parameter\(:?([[:word:]]+)\)/
|
539
|
+
|
540
|
+
sig { params(signature: T.untyped).returns(String) }
|
541
|
+
def compile_signature(signature)
|
542
|
+
params = signature.arg_types
|
543
|
+
params += signature.kwarg_types.to_a
|
544
|
+
params << [signature.rest_name, signature.rest_type] if signature.has_rest
|
545
|
+
params << [signature.block_name, signature.block_type] if signature.block_name
|
546
|
+
|
547
|
+
params = params.compact.map { |name, type| "#{name}: #{type}" }.join(", ")
|
548
|
+
returns = signature.return_type.to_s
|
549
|
+
|
550
|
+
type_parameters = (params + returns).scan(TYPE_PARAMETER_MATCHER).flatten.uniq.map { |p| ":#{p}" }.join(", ")
|
551
|
+
type_parameters = ".type_parameters(#{type_parameters})" unless type_parameters.empty?
|
552
|
+
|
553
|
+
mode = case signature.mode
|
554
|
+
when "abstract"
|
555
|
+
".abstract"
|
556
|
+
when "override"
|
557
|
+
".override"
|
558
|
+
when "overridable_override"
|
559
|
+
".overridable.override"
|
560
|
+
when "overridable"
|
561
|
+
".overridable"
|
562
|
+
else
|
563
|
+
""
|
564
|
+
end
|
565
|
+
|
566
|
+
signature_body = +""
|
567
|
+
signature_body << mode
|
568
|
+
signature_body << type_parameters
|
569
|
+
signature_body << ".params(#{params})" unless params.empty?
|
570
|
+
signature_body << ".returns(#{returns})"
|
571
|
+
signature_body = signature_body
|
572
|
+
.gsub(".returns(<VOID>)", ".void")
|
573
|
+
.gsub("<NOT-TYPED>", "T.untyped")
|
574
|
+
.gsub(TYPE_PARAMETER_MATCHER, "T.type_parameter(:\\1)")[1..-1]
|
575
|
+
|
576
|
+
"sig { #{signature_body} }"
|
468
577
|
end
|
469
578
|
|
470
579
|
sig { params(symbol_name: String).returns(T::Boolean) }
|
@@ -483,16 +592,17 @@ module Tapioca
|
|
483
592
|
sig do
|
484
593
|
type_parameters(:U)
|
485
594
|
.params(
|
595
|
+
step: Integer,
|
486
596
|
_blk: T.proc
|
487
597
|
.returns(T.type_parameter(:U))
|
488
598
|
)
|
489
599
|
.returns(T.type_parameter(:U))
|
490
600
|
end
|
491
|
-
def with_indentation(&_blk)
|
492
|
-
@indent += 2
|
601
|
+
def with_indentation(step = 1, &_blk)
|
602
|
+
@indent += 2 * step
|
493
603
|
yield
|
494
604
|
ensure
|
495
|
-
@indent -= 2
|
605
|
+
@indent -= 2 * step
|
496
606
|
end
|
497
607
|
|
498
608
|
sig { params(str: String).returns(String) }
|
@@ -627,7 +737,7 @@ module Tapioca
|
|
627
737
|
return nil
|
628
738
|
end
|
629
739
|
|
630
|
-
|
740
|
+
raw_name_of(target)
|
631
741
|
end
|
632
742
|
|
633
743
|
sig { params(constant: Module).returns(T.nilable(String)) }
|
@@ -647,6 +757,13 @@ module Tapioca
|
|
647
757
|
Class.instance_method(:superclass).bind(constant).call
|
648
758
|
end
|
649
759
|
|
760
|
+
sig { params(method: T.any(UnboundMethod, Method)).returns(T.untyped) }
|
761
|
+
def signature_of(method)
|
762
|
+
T::Private::Methods.signature_for_method(method)
|
763
|
+
rescue LoadError, StandardError
|
764
|
+
nil
|
765
|
+
end
|
766
|
+
|
650
767
|
sig { params(constant: Module, other: BasicObject).returns(T::Boolean).checked(:never) }
|
651
768
|
def are_equal?(constant, other)
|
652
769
|
BasicObject.instance_method(:equal?).bind(constant).call(other)
|