tapioca 0.4.24 → 0.5.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 +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 +139 -154
- data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +4 -4
- data/lib/tapioca/compilers/symbol_table_compiler.rb +1 -1
- 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 +26 -19
- data/lib/tapioca/generator.rb +127 -43
- 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 +1 -9
- data/lib/tapioca/loader.rb +14 -48
- 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 -0
- 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,23 +1,20 @@
|
|
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
|
|
20
|
-
sig { params(gem: Gemfile::
|
17
|
+
sig { params(gem: Gemfile::GemSpec, indent: Integer).void }
|
21
18
|
def initialize(gem, indent = 0)
|
22
19
|
@gem = gem
|
23
20
|
@indent = indent
|
@@ -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
|