tapioca 0.4.27 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +14 -14
- data/README.md +2 -2
- data/Rakefile +5 -7
- data/exe/tapioca +2 -2
- data/lib/tapioca/cli.rb +256 -2
- data/lib/tapioca/compilers/dsl/aasm.rb +122 -0
- data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +52 -12
- data/lib/tapioca/compilers/dsl/action_mailer.rb +6 -9
- data/lib/tapioca/compilers/dsl/active_job.rb +8 -12
- data/lib/tapioca/compilers/dsl/active_model_attributes.rb +131 -0
- data/lib/tapioca/compilers/dsl/active_record_associations.rb +33 -54
- data/lib/tapioca/compilers/dsl/active_record_columns.rb +10 -105
- data/lib/tapioca/compilers/dsl/active_record_enum.rb +8 -10
- data/lib/tapioca/compilers/dsl/active_record_scope.rb +7 -10
- data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +5 -8
- data/lib/tapioca/compilers/dsl/active_resource.rb +9 -37
- data/lib/tapioca/compilers/dsl/active_storage.rb +98 -0
- data/lib/tapioca/compilers/dsl/active_support_concern.rb +108 -0
- data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +13 -8
- data/lib/tapioca/compilers/dsl/base.rb +96 -82
- data/lib/tapioca/compilers/dsl/config.rb +111 -0
- data/lib/tapioca/compilers/dsl/frozen_record.rb +5 -7
- data/lib/tapioca/compilers/dsl/identity_cache.rb +66 -29
- data/lib/tapioca/compilers/dsl/protobuf.rb +19 -69
- data/lib/tapioca/compilers/dsl/sidekiq_worker.rb +25 -12
- data/lib/tapioca/compilers/dsl/smart_properties.rb +19 -31
- data/lib/tapioca/compilers/dsl/state_machines.rb +56 -78
- data/lib/tapioca/compilers/dsl/url_helpers.rb +7 -10
- data/lib/tapioca/compilers/dsl_compiler.rb +22 -38
- data/lib/tapioca/compilers/requires_compiler.rb +2 -2
- data/lib/tapioca/compilers/sorbet.rb +26 -5
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +138 -153
- data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +4 -4
- data/lib/tapioca/compilers/todos_compiler.rb +1 -1
- data/lib/tapioca/config.rb +2 -0
- data/lib/tapioca/config_builder.rb +4 -2
- data/lib/tapioca/constant_locator.rb +6 -8
- data/lib/tapioca/gemfile.rb +2 -4
- data/lib/tapioca/generator.rb +124 -40
- data/lib/tapioca/generic_type_registry.rb +25 -98
- data/lib/tapioca/helpers/active_record_column_type_helper.rb +98 -0
- data/lib/tapioca/internal.rb +2 -9
- data/lib/tapioca/loader.rb +13 -33
- data/lib/tapioca/rbi_ext/model.rb +122 -0
- data/lib/tapioca/reflection.rb +131 -0
- data/lib/tapioca/sorbet_ext/fixed_hash_patch.rb +1 -1
- data/lib/tapioca/sorbet_ext/generic_name_patch.rb +72 -4
- data/lib/tapioca/sorbet_ext/name_patch.rb +1 -1
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +2 -1
- metadata +34 -22
- data/lib/tapioca/cli/main.rb +0 -146
- data/lib/tapioca/core_ext/class.rb +0 -28
- data/lib/tapioca/core_ext/string.rb +0 -18
- data/lib/tapioca/rbi/model.rb +0 -405
- data/lib/tapioca/rbi/printer.rb +0 -410
- data/lib/tapioca/rbi/rewriters/group_nodes.rb +0 -106
- data/lib/tapioca/rbi/rewriters/nest_non_public_methods.rb +0 -65
- data/lib/tapioca/rbi/rewriters/nest_singleton_methods.rb +0 -42
- data/lib/tapioca/rbi/rewriters/sort_nodes.rb +0 -86
- data/lib/tapioca/rbi/visitor.rb +0 -21
@@ -20,13 +20,14 @@ module Tapioca
|
|
20
20
|
sig do
|
21
21
|
params(
|
22
22
|
requested_constants: T::Array[Module],
|
23
|
-
requested_generators: T::Array[
|
23
|
+
requested_generators: T::Array[T.class_of(Dsl::Base)],
|
24
|
+
excluded_generators: T::Array[T.class_of(Dsl::Base)],
|
24
25
|
error_handler: T.nilable(T.proc.params(error: String).void)
|
25
26
|
).void
|
26
27
|
end
|
27
|
-
def initialize(requested_constants:, requested_generators: [], error_handler: nil)
|
28
|
+
def initialize(requested_constants:, requested_generators: [], excluded_generators: [], error_handler: nil)
|
28
29
|
@generators = T.let(
|
29
|
-
gather_generators(requested_generators),
|
30
|
+
gather_generators(requested_generators, excluded_generators),
|
30
31
|
T::Enumerable[Dsl::Base]
|
31
32
|
)
|
32
33
|
@requested_constants = requested_constants
|
@@ -54,23 +55,19 @@ module Tapioca
|
|
54
55
|
|
55
56
|
private
|
56
57
|
|
57
|
-
sig
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
proc do |klass|
|
64
|
-
generator = klass.name&.sub(/^Tapioca::Compilers::Dsl::/, '')&.downcase
|
65
|
-
generators.include?(generator)
|
66
|
-
end
|
58
|
+
sig do
|
59
|
+
params(
|
60
|
+
requested_generators: T::Array[T.class_of(Dsl::Base)],
|
61
|
+
excluded_generators: T::Array[T.class_of(Dsl::Base)]
|
62
|
+
).returns(T::Enumerable[Dsl::Base])
|
67
63
|
end
|
64
|
+
def gather_generators(requested_generators, excluded_generators)
|
65
|
+
generator_klasses = ::Tapioca::Reflection.descendants_of(Dsl::Base).select do |klass|
|
66
|
+
(requested_generators.empty? || requested_generators.include?(klass)) &&
|
67
|
+
!excluded_generators.include?(klass)
|
68
|
+
end.sort_by { |klass| T.must(klass.name) }
|
68
69
|
|
69
|
-
|
70
|
-
def gather_generators(requested_generators)
|
71
|
-
generator_filter = generator_filter(requested_generators)
|
72
|
-
|
73
|
-
T.cast(Dsl::Base.descendants.select(&generator_filter).map(&:new), T::Enumerable[Dsl::Base])
|
70
|
+
generator_klasses.map(&:new)
|
74
71
|
end
|
75
72
|
|
76
73
|
sig { params(requested_constants: T::Array[Module]).returns(T::Set[Module]) }
|
@@ -82,32 +79,19 @@ module Tapioca
|
|
82
79
|
|
83
80
|
sig { params(constant: Module).returns(T.nilable(String)) }
|
84
81
|
def rbi_for_constant(constant)
|
85
|
-
|
82
|
+
file = RBI::File.new(strictness: "true")
|
86
83
|
|
87
84
|
generators.each do |generator|
|
88
85
|
next unless generator.handles?(constant)
|
89
|
-
generator.decorate(
|
86
|
+
generator.decorate(file.root, constant)
|
90
87
|
end
|
91
88
|
|
92
|
-
return if
|
93
|
-
|
94
|
-
resolve_conflicts(parlour)
|
89
|
+
return if file.root.empty?
|
95
90
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
91
|
+
file.root.nest_non_public_methods!
|
92
|
+
file.root.group_nodes!
|
93
|
+
file.root.sort_nodes!
|
94
|
+
file.string
|
111
95
|
end
|
112
96
|
|
113
97
|
sig { params(error: String).returns(T.noreturn) }
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
4
|
+
require "spoom"
|
5
5
|
|
6
6
|
module Tapioca
|
7
7
|
module Compilers
|
@@ -87,7 +87,7 @@ module Tapioca
|
|
87
87
|
sig { params(files: T::Enumerable[String], name: String).returns(T::Boolean) }
|
88
88
|
def name_in_project?(files, name)
|
89
89
|
files.any? do |file|
|
90
|
-
File.basename(file,
|
90
|
+
File.basename(file, ".rb") == name
|
91
91
|
end
|
92
92
|
end
|
93
93
|
end
|
@@ -1,15 +1,26 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
4
|
+
require "pathname"
|
5
|
+
require "shellwords"
|
6
6
|
|
7
7
|
module Tapioca
|
8
8
|
module Compilers
|
9
9
|
module Sorbet
|
10
|
-
|
10
|
+
SORBET_GEM_SPEC = T.let(
|
11
|
+
Gem::Specification.find_by_name("sorbet-static"),
|
12
|
+
Gem::Specification
|
13
|
+
)
|
14
|
+
SORBET = T.let(
|
15
|
+
Pathname.new(SORBET_GEM_SPEC.full_gem_path) / "libexec" / "sorbet",
|
16
|
+
Pathname
|
17
|
+
)
|
11
18
|
EXE_PATH_ENV_VAR = "TAPIOCA_SORBET_EXE"
|
12
19
|
|
20
|
+
FEATURE_REQUIREMENTS = T.let({
|
21
|
+
mixes_in_class_methods_multiple_args: Gem::Requirement.new("> 0.5.6200"),
|
22
|
+
}.freeze, T::Hash[Symbol, Gem::Requirement])
|
23
|
+
|
13
24
|
class << self
|
14
25
|
extend(T::Sig)
|
15
26
|
|
@@ -20,7 +31,7 @@ module Tapioca
|
|
20
31
|
sorbet_path,
|
21
32
|
"--quiet",
|
22
33
|
*args,
|
23
|
-
].join(
|
34
|
+
].join(" "),
|
24
35
|
err: "/dev/null"
|
25
36
|
).read
|
26
37
|
end
|
@@ -31,6 +42,16 @@ module Tapioca
|
|
31
42
|
sorbet_path = SORBET if sorbet_path.empty?
|
32
43
|
sorbet_path.to_s.shellescape
|
33
44
|
end
|
45
|
+
|
46
|
+
sig { params(feature: Symbol, version: T.nilable(Gem::Version)).returns(T::Boolean) }
|
47
|
+
def supports?(feature, version: nil)
|
48
|
+
version = SORBET_GEM_SPEC.version unless version
|
49
|
+
requirement = FEATURE_REQUIREMENTS[feature]
|
50
|
+
|
51
|
+
raise "Invalid Sorbet feature #{feature}" unless requirement
|
52
|
+
|
53
|
+
requirement.satisfied_by?(version)
|
54
|
+
end
|
34
55
|
end
|
35
56
|
end
|
36
57
|
end
|
@@ -1,19 +1,16 @@
|
|
1
1
|
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
4
|
+
require "pathname"
|
5
5
|
|
6
6
|
module Tapioca
|
7
7
|
module Compilers
|
8
8
|
module SymbolTable
|
9
9
|
class SymbolGenerator
|
10
10
|
extend(T::Sig)
|
11
|
+
include(Reflection)
|
11
12
|
|
12
|
-
IGNORED_SYMBOLS =
|
13
|
-
YAML
|
14
|
-
MiniTest
|
15
|
-
Mutex
|
16
|
-
}
|
13
|
+
IGNORED_SYMBOLS = ["YAML", "MiniTest", "Mutex"]
|
17
14
|
|
18
15
|
attr_reader(:gem, :indent)
|
19
16
|
|
@@ -57,8 +54,8 @@ module Tapioca
|
|
57
54
|
def engine_symbols(symbols)
|
58
55
|
return Set.new unless Object.const_defined?("Rails::Engine")
|
59
56
|
|
60
|
-
engine = Object.const_get("Rails::Engine")
|
61
|
-
.
|
57
|
+
engine = descendants_of(Object.const_get("Rails::Engine"))
|
58
|
+
.reject(&:abstract_railtie?)
|
62
59
|
.find do |klass|
|
63
60
|
name = name_of(klass)
|
64
61
|
!name.nil? && symbols.include?(name)
|
@@ -102,7 +99,7 @@ module Tapioca
|
|
102
99
|
return unless constant
|
103
100
|
return unless name
|
104
101
|
return if name.strip.empty?
|
105
|
-
return if name.start_with?(
|
102
|
+
return if name.start_with?("#<")
|
106
103
|
return if name.downcase == name
|
107
104
|
return if alias_namespaced?(name)
|
108
105
|
return if seen?(name)
|
@@ -144,7 +141,9 @@ module Tapioca
|
|
144
141
|
sig { params(tree: RBI::Tree, name: String, value: BasicObject).void.checked(:never) }
|
145
142
|
def compile_object(tree, name, value)
|
146
143
|
return if symbol_ignored?(name)
|
144
|
+
|
147
145
|
klass = class_of(value)
|
146
|
+
return if klass == TypeMember || klass == TypeTemplate
|
148
147
|
|
149
148
|
klass_name = if klass == ObjectSpace::WeakMap
|
150
149
|
# WeakMap is an implicit generic with one type variable
|
@@ -189,9 +188,10 @@ module Tapioca
|
|
189
188
|
|
190
189
|
sig { params(tree: RBI::Tree, name: String, constant: Module).void }
|
191
190
|
def compile_body(tree, name, constant)
|
191
|
+
# Compiling type variables must happen first to populate generic names
|
192
|
+
compile_type_variables(tree, constant)
|
192
193
|
compile_methods(tree, name, constant)
|
193
194
|
compile_module_helpers(tree, constant)
|
194
|
-
compile_type_variables(tree, constant)
|
195
195
|
compile_mixins(tree, constant)
|
196
196
|
compile_mixes_in_class_methods(tree, constant)
|
197
197
|
compile_props(tree, constant)
|
@@ -267,12 +267,10 @@ module Tapioca
|
|
267
267
|
# Create a map of subconstants (via their object ids) to their names.
|
268
268
|
# We need this later when we want to lookup the name of the registered type
|
269
269
|
# variable via the value of the type variable constant.
|
270
|
-
subconstant_to_name_lookup = constants_of(constant)
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
]
|
275
|
-
end.to_h
|
270
|
+
subconstant_to_name_lookup = constants_of(constant)
|
271
|
+
.each_with_object({}.compare_by_identity) do |constant_name, table|
|
272
|
+
table[resolve_constant(constant_name.to_s, namespace: constant)] = constant_name.to_s
|
273
|
+
end
|
276
274
|
|
277
275
|
# Map each type variable to its string representation.
|
278
276
|
#
|
@@ -283,12 +281,13 @@ module Tapioca
|
|
283
281
|
# By looping over these entries and then getting the actual constant name
|
284
282
|
# from the `subconstant_to_name_lookup` we defined above, gives us all the
|
285
283
|
# information we need to serialize type variable definitions.
|
286
|
-
type_variable_declarations = type_variables.map do |
|
287
|
-
constant_name = subconstant_to_name_lookup[
|
284
|
+
type_variable_declarations = type_variables.map do |type_variable, serialized_type_variable|
|
285
|
+
constant_name = subconstant_to_name_lookup[type_variable]
|
286
|
+
type_variable.name = constant_name
|
288
287
|
# Here, we know that constant_value will be an instance of
|
289
288
|
# T::Types::CustomTypeVariable, which knows how to serialize
|
290
289
|
# itself to a type_member/type_template
|
291
|
-
tree << RBI::TypeMember.new(constant_name
|
290
|
+
tree << RBI::TypeMember.new(constant_name, serialized_type_variable)
|
292
291
|
end
|
293
292
|
|
294
293
|
return if type_variable_declarations.empty?
|
@@ -392,49 +391,80 @@ module Tapioca
|
|
392
391
|
end
|
393
392
|
end
|
394
393
|
|
395
|
-
sig { params(
|
396
|
-
def
|
397
|
-
|
398
|
-
|
399
|
-
mixins_from_modules = {}
|
394
|
+
sig { params(constant: Module).returns([T::Array[Module], T::Array[Module]]) }
|
395
|
+
def collect_dynamic_mixins_of(constant)
|
396
|
+
mixins_from_modules = {}.compare_by_identity
|
400
397
|
|
401
398
|
Class.new do
|
402
|
-
#
|
403
|
-
|
399
|
+
# Override the `self.include` method
|
400
|
+
define_singleton_method(:include) do |mod|
|
401
|
+
# Take a snapshot of the list of singleton class ancestors
|
402
|
+
# before the actual include
|
403
|
+
before = singleton_class.ancestors
|
404
|
+
# Call the actual `include` method with the supplied module
|
405
|
+
include_result = super(mod)
|
406
|
+
# Take a snapshot of the list of singleton class ancestors
|
407
|
+
# after the actual include
|
408
|
+
after = singleton_class.ancestors
|
409
|
+
# The difference is the modules that are added to the list
|
410
|
+
# of ancestors of the singleton class. Those are all the
|
411
|
+
# modules that were `extend`ed due to the `include` call.
|
412
|
+
#
|
413
|
+
# We record those modules on our lookup table keyed by
|
414
|
+
# the included module with the values being all the modules
|
415
|
+
# that that module pulls into the singleton class.
|
416
|
+
#
|
417
|
+
# We need to reverse the order, since the extend order should
|
418
|
+
# be the inverse of the ancestor order. That is, earlier
|
419
|
+
# extended modules would be later in the ancestor chain.
|
420
|
+
mixins_from_modules[mod] = (after - before).reverse!
|
421
|
+
|
422
|
+
include_result
|
423
|
+
rescue Exception # rubocop:disable Lint/RescueException
|
424
|
+
# this is a best effort, bail if we can't perform this
|
404
425
|
end
|
405
426
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
end
|
412
|
-
rescue Exception # rubocop:disable Lint/RescueException
|
413
|
-
# this is a best effort, bail if we can't perform this
|
414
|
-
end
|
427
|
+
# rubocop:disable Style/MissingRespondToMissing
|
428
|
+
def method_missing(symbol, *args)
|
429
|
+
# We need this here so that we can handle any random instance
|
430
|
+
# method calls on the fake including class that may be done by
|
431
|
+
# the included module during the `self.included` hook.
|
415
432
|
end
|
416
433
|
|
417
434
|
class << self
|
418
435
|
def method_missing(symbol, *args)
|
436
|
+
# Similarly, we need this here so that we can handle any
|
437
|
+
# random class method calls on the fake including class
|
438
|
+
# that may be done by the included module during the
|
439
|
+
# `self.included` hook.
|
419
440
|
end
|
420
441
|
end
|
421
|
-
# rubocop:enable Style/
|
442
|
+
# rubocop:enable Style/MissingRespondToMissing
|
422
443
|
end.include(constant)
|
423
444
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
445
|
+
[
|
446
|
+
# The value that corresponds to the original included constant
|
447
|
+
# is the list of all dynamically extended modules because of that
|
448
|
+
# constant. We grab that value by deleting the key for the original
|
449
|
+
# constant.
|
450
|
+
T.must(mixins_from_modules.delete(constant)),
|
451
|
+
# Since we deleted the original constant from the list of keys, all
|
452
|
+
# the keys that remain are the ones that are dynamically included modules
|
453
|
+
# during the include of the original constant.
|
454
|
+
mixins_from_modules.keys,
|
455
|
+
]
|
456
|
+
end
|
457
|
+
|
458
|
+
sig { params(constant: Module, dynamic_extends: T::Array[Module]).returns(T::Array[Module]) }
|
459
|
+
def collect_mixed_in_class_methods(constant, dynamic_extends)
|
460
|
+
if Tapioca::Compilers::Sorbet.supports?(:mixes_in_class_methods_multiple_args)
|
461
|
+
# If we can generate multiple mixes_in_class_methods, then
|
462
|
+
# we want to use all dynamic extends that are not the constant itself
|
463
|
+
return dynamic_extends.select { |mod| mod != constant }
|
464
|
+
end
|
437
465
|
|
466
|
+
# For older Sorbet version, we do an explicit check for an AS::Concern
|
467
|
+
# related ClassMethods module.
|
438
468
|
ancestors = singleton_class_of(constant).ancestors
|
439
469
|
extends_as_concern = ancestors.any? do |mod|
|
440
470
|
qualified_name_of(mod) == "::ActiveSupport::Concern"
|
@@ -442,17 +472,45 @@ module Tapioca
|
|
442
472
|
class_methods_module = resolve_constant("#{name_of(constant)}::ClassMethods")
|
443
473
|
|
444
474
|
mixed_in_module = if extends_as_concern && Module === class_methods_module
|
475
|
+
# If this module is a concern and the ClassMethods module exists
|
476
|
+
# then, we prefer to generate a mixes_in_class_methods call for
|
477
|
+
# that module only, since we only have a single shot.
|
445
478
|
class_methods_module
|
446
479
|
else
|
480
|
+
# Otherwise, we use the first dynamic extend module that is not
|
481
|
+
# the constant itself. We don't have a better heuristic in the
|
482
|
+
# absence of being able to supply multiple arguments.
|
447
483
|
dynamic_extends.find { |mod| mod != constant }
|
448
484
|
end
|
449
485
|
|
450
|
-
|
486
|
+
Array(mixed_in_module)
|
487
|
+
end
|
488
|
+
|
489
|
+
sig { params(tree: RBI::Tree, constant: Module).void }
|
490
|
+
def compile_mixes_in_class_methods(tree, constant)
|
491
|
+
return if constant.is_a?(Class)
|
492
|
+
|
493
|
+
dynamic_extends, dynamic_includes = collect_dynamic_mixins_of(constant)
|
494
|
+
|
495
|
+
dynamic_includes
|
496
|
+
.select { |mod| (name = name_of(mod)) && !name.start_with?("T::") }
|
497
|
+
.map do |mod|
|
498
|
+
add_to_symbol_queue(name_of(mod))
|
451
499
|
|
452
|
-
|
453
|
-
|
500
|
+
qname = qualified_name_of(mod)
|
501
|
+
tree << RBI::Include.new(T.must(qname))
|
502
|
+
end
|
454
503
|
|
455
|
-
|
504
|
+
mixed_in_class_methods = collect_mixed_in_class_methods(constant, dynamic_extends)
|
505
|
+
return if mixed_in_class_methods.empty?
|
506
|
+
|
507
|
+
mixed_in_class_methods.each do |mod|
|
508
|
+
add_to_symbol_queue(name_of(mod))
|
509
|
+
|
510
|
+
qualified_name = qualified_name_of(mod)
|
511
|
+
next if qualified_name.nil? || qualified_name.empty?
|
512
|
+
tree << RBI::MixesInClassMethods.new(qualified_name)
|
513
|
+
end
|
456
514
|
rescue
|
457
515
|
nil # silence errors
|
458
516
|
end
|
@@ -486,11 +544,11 @@ module Tapioca
|
|
486
544
|
next if name == :initialize
|
487
545
|
vis = case visibility
|
488
546
|
when :protected
|
489
|
-
RBI::
|
547
|
+
RBI::Protected.new
|
490
548
|
when :private
|
491
|
-
RBI::
|
549
|
+
RBI::Private.new
|
492
550
|
else
|
493
|
-
RBI::
|
551
|
+
RBI::Public.new
|
494
552
|
end
|
495
553
|
compile_method(tree, module_name, mod, mod.instance_method(name), vis)
|
496
554
|
end
|
@@ -500,9 +558,9 @@ module Tapioca
|
|
500
558
|
sig { params(mod: Module).returns(T::Hash[Symbol, T::Array[Symbol]]) }
|
501
559
|
def method_names_by_visibility(mod)
|
502
560
|
{
|
503
|
-
public:
|
504
|
-
protected:
|
505
|
-
private:
|
561
|
+
public: public_instance_methods_of(mod),
|
562
|
+
protected: protected_instance_methods_of(mod),
|
563
|
+
private: private_instance_methods_of(mod),
|
506
564
|
}
|
507
565
|
end
|
508
566
|
|
@@ -513,7 +571,7 @@ module Tapioca
|
|
513
571
|
constant
|
514
572
|
.props
|
515
573
|
.keys
|
516
|
-
.include?(method_name.gsub(/=$/,
|
574
|
+
.include?(method_name.gsub(/=$/, "").to_sym)
|
517
575
|
end
|
518
576
|
|
519
577
|
sig do
|
@@ -525,7 +583,7 @@ module Tapioca
|
|
525
583
|
visibility: RBI::Visibility
|
526
584
|
).void
|
527
585
|
end
|
528
|
-
def compile_method(tree, symbol_name, constant, method, visibility = RBI::
|
586
|
+
def compile_method(tree, symbol_name, constant, method, visibility = RBI::Public.new)
|
529
587
|
return unless method
|
530
588
|
return unless method.owner == constant
|
531
589
|
return if symbol_ignored?(symbol_name) && !method_in_gem?(method)
|
@@ -615,7 +673,7 @@ module Tapioca
|
|
615
673
|
sig << RBI::SigParam.new(name, type)
|
616
674
|
end
|
617
675
|
|
618
|
-
return_type =
|
676
|
+
return_type = name_of_type(signature.return_type)
|
619
677
|
sig.return_type = sanitize_signature_types(return_type)
|
620
678
|
add_to_symbol_queue(sig.return_type)
|
621
679
|
|
@@ -638,12 +696,22 @@ module Tapioca
|
|
638
696
|
sig
|
639
697
|
end
|
640
698
|
|
699
|
+
sig { params(sig_string: String).returns(String) }
|
700
|
+
def sanitize_signature_types(sig_string)
|
701
|
+
sig_string
|
702
|
+
.gsub(".returns(<VOID>)", ".void")
|
703
|
+
.gsub("<VOID>", "void")
|
704
|
+
.gsub("<NOT-TYPED>", "T.untyped")
|
705
|
+
.gsub(".params()", "")
|
706
|
+
end
|
707
|
+
|
641
708
|
sig { params(symbol_name: String).returns(T::Boolean) }
|
642
709
|
def symbol_ignored?(symbol_name)
|
643
710
|
SymbolLoader.ignore_symbol?(symbol_name)
|
644
711
|
end
|
645
712
|
|
646
|
-
SPECIAL_METHOD_NAMES =
|
713
|
+
SPECIAL_METHOD_NAMES = ["!", "~", "+@", "**", "-@", "*", "/", "%", "+", "-", "<<", ">>", "&", "|", "^", "<",
|
714
|
+
"<=", "=>", ">", ">=", "==", "===", "!=", "=~", "!~", "<=>", "[]", "[]=", "`"]
|
647
715
|
|
648
716
|
sig { params(name: String).returns(T::Boolean) }
|
649
717
|
def valid_method_name?(name)
|
@@ -708,40 +776,6 @@ module Tapioca
|
|
708
776
|
nil
|
709
777
|
end
|
710
778
|
|
711
|
-
sig { params(constant: BasicObject).returns(Class).checked(:never) }
|
712
|
-
def class_of(constant)
|
713
|
-
Kernel.instance_method(:class).bind(constant).call
|
714
|
-
end
|
715
|
-
|
716
|
-
sig { params(constant: Module).returns(T::Array[Symbol]) }
|
717
|
-
def constants_of(constant)
|
718
|
-
Module.instance_method(:constants).bind(constant).call(false)
|
719
|
-
end
|
720
|
-
|
721
|
-
sig { params(constant: Module).returns(T.nilable(String)) }
|
722
|
-
def raw_name_of(constant)
|
723
|
-
Module.instance_method(:name).bind(constant).call
|
724
|
-
end
|
725
|
-
|
726
|
-
sig { params(constant: Module).returns(Class) }
|
727
|
-
def singleton_class_of(constant)
|
728
|
-
Object.instance_method(:singleton_class).bind(constant).call
|
729
|
-
end
|
730
|
-
|
731
|
-
sig { params(constant: Module).returns(T::Array[Module]) }
|
732
|
-
def ancestors_of(constant)
|
733
|
-
Module.instance_method(:ancestors).bind(constant).call
|
734
|
-
end
|
735
|
-
|
736
|
-
sig { params(constant: Module).returns(T::Array[Module]) }
|
737
|
-
def inherited_ancestors_of(constant)
|
738
|
-
if Class === constant
|
739
|
-
ancestors_of(superclass_of(constant) || Object)
|
740
|
-
else
|
741
|
-
Module.ancestors
|
742
|
-
end
|
743
|
-
end
|
744
|
-
|
745
779
|
sig { params(constant: Module).returns(T::Array[Module]) }
|
746
780
|
def interesting_ancestors_of(constant)
|
747
781
|
inherited_ancestors_ids = Set.new(
|
@@ -771,9 +805,9 @@ module Tapioca
|
|
771
805
|
|
772
806
|
sig { params(constant: Module).returns(T.nilable(String)) }
|
773
807
|
def name_of(constant)
|
774
|
-
name = name_of_proxy_target(constant)
|
808
|
+
name = name_of_proxy_target(constant, super(class_of(constant)))
|
775
809
|
return name if name
|
776
|
-
name =
|
810
|
+
name = super(constant)
|
777
811
|
return if name.nil?
|
778
812
|
return unless are_equal?(constant, resolve_constant(name, inherit: true))
|
779
813
|
name = "Struct" if name =~ /^(::)?Struct::[^:]+$/
|
@@ -793,67 +827,18 @@ module Tapioca
|
|
793
827
|
"#{type_name}[#{type_variable_names}]"
|
794
828
|
end
|
795
829
|
|
796
|
-
sig { params(constant: Module).returns(T.nilable(String)) }
|
797
|
-
def name_of_proxy_target(constant)
|
798
|
-
|
799
|
-
return unless raw_name_of(klass) == "ActiveSupport::Deprecation::DeprecatedConstantProxy"
|
830
|
+
sig { params(constant: Module, class_name: T.nilable(String)).returns(T.nilable(String)) }
|
831
|
+
def name_of_proxy_target(constant, class_name)
|
832
|
+
return unless class_name == "ActiveSupport::Deprecation::DeprecatedConstantProxy"
|
800
833
|
# We are dealing with a ActiveSupport::Deprecation::DeprecatedConstantProxy
|
801
834
|
# so try to get the name of the target class
|
802
835
|
begin
|
803
|
-
target =
|
836
|
+
target = constant.__send__(:target)
|
804
837
|
rescue NoMethodError
|
805
838
|
return
|
806
839
|
end
|
807
840
|
|
808
|
-
|
809
|
-
end
|
810
|
-
|
811
|
-
sig { params(constant: Module).returns(T.nilable(String)) }
|
812
|
-
def qualified_name_of(constant)
|
813
|
-
name = name_of(constant)
|
814
|
-
return if name.nil?
|
815
|
-
|
816
|
-
if name.start_with?("::")
|
817
|
-
name
|
818
|
-
else
|
819
|
-
"::#{name}"
|
820
|
-
end
|
821
|
-
end
|
822
|
-
|
823
|
-
sig { params(constant: Class).returns(T.nilable(Class)) }
|
824
|
-
def superclass_of(constant)
|
825
|
-
Class.instance_method(:superclass).bind(constant).call
|
826
|
-
end
|
827
|
-
|
828
|
-
sig { params(method: T.any(UnboundMethod, Method)).returns(T.untyped) }
|
829
|
-
def signature_of(method)
|
830
|
-
T::Private::Methods.signature_for_method(method)
|
831
|
-
rescue LoadError, StandardError
|
832
|
-
nil
|
833
|
-
end
|
834
|
-
|
835
|
-
sig { params(sig_string: String).returns(String) }
|
836
|
-
def sanitize_signature_types(sig_string)
|
837
|
-
sig_string
|
838
|
-
.gsub(".returns(<VOID>)", ".void")
|
839
|
-
.gsub("<VOID>", "void")
|
840
|
-
.gsub("<NOT-TYPED>", "T.untyped")
|
841
|
-
.gsub(".params()", "")
|
842
|
-
end
|
843
|
-
|
844
|
-
sig { params(constant: T::Types::Base).returns(String) }
|
845
|
-
def type_of(constant)
|
846
|
-
constant.to_s.gsub(/\bAttachedClass\b/, "T.attached_class")
|
847
|
-
end
|
848
|
-
|
849
|
-
sig { params(object: BasicObject).returns(Integer).checked(:never) }
|
850
|
-
def object_id_of(object)
|
851
|
-
Object.instance_method(:object_id).bind(object).call
|
852
|
-
end
|
853
|
-
|
854
|
-
sig { params(constant: Module, other: BasicObject).returns(T::Boolean).checked(:never) }
|
855
|
-
def are_equal?(constant, other)
|
856
|
-
BasicObject.instance_method(:equal?).bind(constant).call(other)
|
841
|
+
name_of(target)
|
857
842
|
end
|
858
843
|
end
|
859
844
|
end
|