tapioca 0.4.27 → 0.5.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/Gemfile +15 -15
- data/README.md +2 -2
- data/Rakefile +5 -7
- data/exe/tapioca +2 -2
- data/lib/tapioca/cli.rb +172 -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_model_secure_password.rb +101 -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_fixtures.rb +86 -0
- 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 +106 -0
- data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +13 -8
- data/lib/tapioca/compilers/dsl/base.rb +108 -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/mixed_in_class_attributes.rb +74 -0
- 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 +21 -33
- 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 +25 -40
- data/lib/tapioca/compilers/dynamic_mixin_compiler.rb +198 -0
- data/lib/tapioca/compilers/requires_compiler.rb +2 -2
- data/lib/tapioca/compilers/sorbet.rb +25 -5
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +122 -206
- data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +4 -4
- data/lib/tapioca/compilers/symbol_table_compiler.rb +5 -11
- data/lib/tapioca/compilers/todos_compiler.rb +1 -1
- data/lib/tapioca/config.rb +3 -0
- data/lib/tapioca/config_builder.rb +5 -2
- data/lib/tapioca/constant_locator.rb +6 -8
- data/lib/tapioca/gemfile.rb +14 -11
- data/lib/tapioca/generators/base.rb +61 -0
- data/lib/tapioca/generators/dsl.rb +362 -0
- data/lib/tapioca/generators/gem.rb +345 -0
- data/lib/tapioca/generators/init.rb +79 -0
- data/lib/tapioca/generators/require.rb +52 -0
- data/lib/tapioca/generators/todo.rb +76 -0
- data/lib/tapioca/generators.rb +9 -0
- 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 -10
- data/lib/tapioca/loader.rb +11 -31
- data/lib/tapioca/rbi_ext/model.rb +166 -0
- data/lib/tapioca/reflection.rb +138 -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 +3 -0
- metadata +45 -23
- 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/generator.rb +0 -633
- 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
@@ -1,48 +1,56 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
include(Reflection)
|
12
|
+
|
13
|
+
IGNORED_SYMBOLS = T.let(["YAML", "MiniTest", "Mutex"], T::Array[String])
|
14
|
+
IGNORED_COMMENTS = T.let([
|
15
|
+
":doc:",
|
16
|
+
":nodoc:",
|
17
|
+
"typed:",
|
18
|
+
"frozen_string_literal:",
|
19
|
+
"encoding:",
|
20
|
+
"warn_indent:",
|
21
|
+
"shareable_constant_value:",
|
22
|
+
"rubocop:",
|
23
|
+
], T::Array[String])
|
24
|
+
|
25
|
+
sig { returns(Gemfile::GemSpec) }
|
26
|
+
attr_reader :gem
|
27
|
+
|
28
|
+
sig { returns(Integer) }
|
29
|
+
attr_reader :indent
|
30
|
+
|
31
|
+
sig { params(gem: Gemfile::GemSpec, indent: Integer, include_doc: T::Boolean).void }
|
32
|
+
def initialize(gem, indent = 0, include_doc = false)
|
22
33
|
@gem = gem
|
23
34
|
@indent = indent
|
24
|
-
@seen = Set.new
|
25
|
-
@alias_namespace
|
35
|
+
@seen = T.let(Set.new, T::Set[String])
|
36
|
+
@alias_namespace = T.let(Set.new, T::Set[String])
|
26
37
|
@symbol_queue = T.let(symbols.sort.dup, T::Array[String])
|
27
|
-
|
38
|
+
@symbols = T.let(nil, T.nilable(T::Set[String]))
|
39
|
+
@include_doc = include_doc
|
28
40
|
|
29
|
-
|
30
|
-
|
31
|
-
rbi = RBI::Tree.new
|
32
|
-
|
33
|
-
generate_from_symbol(rbi, T.must(@symbol_queue.shift)) until @symbol_queue.empty?
|
41
|
+
gem.parse_yard_docs if include_doc
|
42
|
+
end
|
34
43
|
|
35
|
-
|
36
|
-
|
37
|
-
rbi.
|
38
|
-
rbi.sort_nodes!
|
39
|
-
rbi.string
|
44
|
+
sig { params(rbi: RBI::File).void }
|
45
|
+
def generate(rbi)
|
46
|
+
generate_from_symbol(rbi.root, T.must(@symbol_queue.shift)) until @symbol_queue.empty?
|
40
47
|
end
|
41
48
|
|
42
49
|
private
|
43
50
|
|
51
|
+
sig { params(name: T.nilable(String)).void }
|
44
52
|
def add_to_symbol_queue(name)
|
45
|
-
@symbol_queue << name unless symbols.include?(name) || symbol_ignored?(name)
|
53
|
+
@symbol_queue << name unless name.nil? || symbols.include?(name) || symbol_ignored?(name)
|
46
54
|
end
|
47
55
|
|
48
56
|
sig { returns(T::Set[String]) }
|
@@ -57,8 +65,8 @@ module Tapioca
|
|
57
65
|
def engine_symbols(symbols)
|
58
66
|
return Set.new unless Object.const_defined?("Rails::Engine")
|
59
67
|
|
60
|
-
engine = Object.const_get("Rails::Engine")
|
61
|
-
.
|
68
|
+
engine = descendants_of(Object.const_get("Rails::Engine"))
|
69
|
+
.reject(&:abstract_railtie?)
|
62
70
|
.find do |klass|
|
63
71
|
name = name_of(klass)
|
64
72
|
!name.nil? && symbols.include?(name)
|
@@ -102,7 +110,7 @@ module Tapioca
|
|
102
110
|
return unless constant
|
103
111
|
return unless name
|
104
112
|
return if name.strip.empty?
|
105
|
-
return if name.start_with?(
|
113
|
+
return if name.start_with?("#<")
|
106
114
|
return if name.downcase == name
|
107
115
|
return if alias_namespaced?(name)
|
108
116
|
return if seen?(name)
|
@@ -144,7 +152,9 @@ module Tapioca
|
|
144
152
|
sig { params(tree: RBI::Tree, name: String, value: BasicObject).void.checked(:never) }
|
145
153
|
def compile_object(tree, name, value)
|
146
154
|
return if symbol_ignored?(name)
|
155
|
+
|
147
156
|
klass = class_of(value)
|
157
|
+
return if klass == TypeMember || klass == TypeTemplate
|
148
158
|
|
149
159
|
klass_name = if klass == ObjectSpace::WeakMap
|
150
160
|
# WeakMap is an implicit generic with one type variable
|
@@ -155,28 +165,33 @@ module Tapioca
|
|
155
165
|
name_of(klass)
|
156
166
|
end
|
157
167
|
|
168
|
+
comments = documentation_comments(name)
|
169
|
+
|
158
170
|
if klass_name == "T::Private::Types::TypeAlias"
|
159
|
-
|
171
|
+
constant = RBI::Const.new(name, "T.type_alias { #{T.unsafe(value).aliased_type} }", comments: comments)
|
172
|
+
tree << constant
|
160
173
|
return
|
161
174
|
end
|
162
175
|
|
163
176
|
return if klass_name&.start_with?("T::Types::", "T::Private::")
|
164
177
|
|
165
178
|
type_name = klass_name || "T.untyped"
|
179
|
+
constant = RBI::Const.new(name, "T.let(T.unsafe(nil), #{type_name})", comments: comments)
|
166
180
|
|
167
|
-
tree <<
|
181
|
+
tree << constant
|
168
182
|
end
|
169
183
|
|
170
184
|
sig { params(tree: RBI::Tree, name: String, constant: Module).void }
|
171
185
|
def compile_module(tree, name, constant)
|
172
186
|
return unless defined_in_gem?(constant, strict: false)
|
173
187
|
|
188
|
+
comments = documentation_comments(name)
|
174
189
|
scope =
|
175
190
|
if constant.is_a?(Class)
|
176
191
|
superclass = compile_superclass(constant)
|
177
|
-
RBI::Class.new(name, superclass_name: superclass)
|
192
|
+
RBI::Class.new(name, superclass_name: superclass, comments: comments)
|
178
193
|
else
|
179
|
-
RBI::Module.new(name)
|
194
|
+
RBI::Module.new(name, comments: comments)
|
180
195
|
end
|
181
196
|
|
182
197
|
compile_body(scope, name, constant)
|
@@ -189,13 +204,27 @@ module Tapioca
|
|
189
204
|
|
190
205
|
sig { params(tree: RBI::Tree, name: String, constant: Module).void }
|
191
206
|
def compile_body(tree, name, constant)
|
207
|
+
# Compiling type variables must happen first to populate generic names
|
208
|
+
compile_type_variables(tree, constant)
|
192
209
|
compile_methods(tree, name, constant)
|
193
210
|
compile_module_helpers(tree, constant)
|
194
|
-
compile_type_variables(tree, constant)
|
195
211
|
compile_mixins(tree, constant)
|
196
|
-
compile_mixes_in_class_methods(tree, constant)
|
197
212
|
compile_props(tree, constant)
|
198
213
|
compile_enums(tree, constant)
|
214
|
+
compile_dynamic_mixins(tree, constant)
|
215
|
+
end
|
216
|
+
|
217
|
+
sig { params(tree: RBI::Tree, constant: Module).void }
|
218
|
+
def compile_dynamic_mixins(tree, constant)
|
219
|
+
return if constant.is_a?(Class)
|
220
|
+
|
221
|
+
mixin_compiler = DynamicMixinCompiler.new(constant)
|
222
|
+
mixin_compiler.compile_class_attributes(tree)
|
223
|
+
dynamic_extends, dynamic_includes = mixin_compiler.compile_mixes_in_class_methods(tree)
|
224
|
+
|
225
|
+
(dynamic_includes + dynamic_extends).each do |mod|
|
226
|
+
add_to_symbol_queue(name_of(mod))
|
227
|
+
end
|
199
228
|
end
|
200
229
|
|
201
230
|
sig { params(tree: RBI::Tree, constant: Module).void }
|
@@ -267,12 +296,10 @@ module Tapioca
|
|
267
296
|
# Create a map of subconstants (via their object ids) to their names.
|
268
297
|
# We need this later when we want to lookup the name of the registered type
|
269
298
|
# 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
|
299
|
+
subconstant_to_name_lookup = constants_of(constant)
|
300
|
+
.each_with_object({}.compare_by_identity) do |constant_name, table|
|
301
|
+
table[resolve_constant(constant_name.to_s, namespace: constant)] = constant_name.to_s
|
302
|
+
end
|
276
303
|
|
277
304
|
# Map each type variable to its string representation.
|
278
305
|
#
|
@@ -283,12 +310,13 @@ module Tapioca
|
|
283
310
|
# By looping over these entries and then getting the actual constant name
|
284
311
|
# from the `subconstant_to_name_lookup` we defined above, gives us all the
|
285
312
|
# information we need to serialize type variable definitions.
|
286
|
-
type_variable_declarations = type_variables.map do |
|
287
|
-
constant_name = subconstant_to_name_lookup[
|
313
|
+
type_variable_declarations = type_variables.map do |type_variable, serialized_type_variable|
|
314
|
+
constant_name = subconstant_to_name_lookup[type_variable]
|
315
|
+
type_variable.name = constant_name
|
288
316
|
# Here, we know that constant_value will be an instance of
|
289
317
|
# T::Types::CustomTypeVariable, which knows how to serialize
|
290
318
|
# itself to a type_member/type_template
|
291
|
-
tree << RBI::TypeMember.new(constant_name
|
319
|
+
tree << RBI::TypeMember.new(constant_name, serialized_type_variable)
|
292
320
|
end
|
293
321
|
|
294
322
|
return if type_variable_declarations.empty?
|
@@ -392,71 +420,6 @@ module Tapioca
|
|
392
420
|
end
|
393
421
|
end
|
394
422
|
|
395
|
-
sig { params(tree: RBI::Tree, constant: Module).void }
|
396
|
-
def compile_mixes_in_class_methods(tree, constant)
|
397
|
-
return if constant.is_a?(Class)
|
398
|
-
|
399
|
-
mixins_from_modules = {}
|
400
|
-
|
401
|
-
Class.new do
|
402
|
-
# rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
|
403
|
-
def method_missing(symbol, *args)
|
404
|
-
end
|
405
|
-
|
406
|
-
define_singleton_method(:include) do |mod|
|
407
|
-
begin
|
408
|
-
before = singleton_class.ancestors
|
409
|
-
super(mod).tap do
|
410
|
-
mixins_from_modules[mod] = singleton_class.ancestors - before
|
411
|
-
end
|
412
|
-
rescue Exception # rubocop:disable Lint/RescueException
|
413
|
-
# this is a best effort, bail if we can't perform this
|
414
|
-
end
|
415
|
-
end
|
416
|
-
|
417
|
-
class << self
|
418
|
-
def method_missing(symbol, *args)
|
419
|
-
end
|
420
|
-
end
|
421
|
-
# rubocop:enable Style/MethodMissingSuper, Style/MissingRespondToMissing
|
422
|
-
end.include(constant)
|
423
|
-
|
424
|
-
all_dynamic_extends = mixins_from_modules.delete(constant)
|
425
|
-
all_dynamic_includes = mixins_from_modules.keys
|
426
|
-
dynamic_extends_from_dynamic_includes = mixins_from_modules.values.flatten
|
427
|
-
dynamic_extends = all_dynamic_extends - dynamic_extends_from_dynamic_includes
|
428
|
-
|
429
|
-
all_dynamic_includes
|
430
|
-
.select { |mod| (name = name_of(mod)) && !name.start_with?("T::") }
|
431
|
-
.map do |mod|
|
432
|
-
add_to_symbol_queue(name_of(mod))
|
433
|
-
|
434
|
-
qname = qualified_name_of(mod)
|
435
|
-
tree << RBI::Include.new(T.must(qname))
|
436
|
-
end.join("\n")
|
437
|
-
|
438
|
-
ancestors = singleton_class_of(constant).ancestors
|
439
|
-
extends_as_concern = ancestors.any? do |mod|
|
440
|
-
qualified_name_of(mod) == "::ActiveSupport::Concern"
|
441
|
-
end
|
442
|
-
class_methods_module = resolve_constant("#{name_of(constant)}::ClassMethods")
|
443
|
-
|
444
|
-
mixed_in_module = if extends_as_concern && Module === class_methods_module
|
445
|
-
class_methods_module
|
446
|
-
else
|
447
|
-
dynamic_extends.find { |mod| mod != constant }
|
448
|
-
end
|
449
|
-
|
450
|
-
return if mixed_in_module.nil?
|
451
|
-
|
452
|
-
qualified_name = qualified_name_of(mixed_in_module)
|
453
|
-
return if qualified_name.nil? || qualified_name == ""
|
454
|
-
|
455
|
-
tree << RBI::MixesInClassMethods.new(qualified_name)
|
456
|
-
rescue
|
457
|
-
nil # silence errors
|
458
|
-
end
|
459
|
-
|
460
423
|
sig { params(tree: RBI::Tree, name: String, constant: Module).void }
|
461
424
|
def compile_methods(tree, name, constant)
|
462
425
|
compile_method(
|
@@ -486,11 +449,11 @@ module Tapioca
|
|
486
449
|
next if name == :initialize
|
487
450
|
vis = case visibility
|
488
451
|
when :protected
|
489
|
-
RBI::
|
452
|
+
RBI::Protected.new
|
490
453
|
when :private
|
491
|
-
RBI::
|
454
|
+
RBI::Private.new
|
492
455
|
else
|
493
|
-
RBI::
|
456
|
+
RBI::Public.new
|
494
457
|
end
|
495
458
|
compile_method(tree, module_name, mod, mod.instance_method(name), vis)
|
496
459
|
end
|
@@ -500,9 +463,9 @@ module Tapioca
|
|
500
463
|
sig { params(mod: Module).returns(T::Hash[Symbol, T::Array[Symbol]]) }
|
501
464
|
def method_names_by_visibility(mod)
|
502
465
|
{
|
503
|
-
public:
|
504
|
-
protected:
|
505
|
-
private:
|
466
|
+
public: public_instance_methods_of(mod),
|
467
|
+
protected: protected_instance_methods_of(mod),
|
468
|
+
private: private_instance_methods_of(mod),
|
506
469
|
}
|
507
470
|
end
|
508
471
|
|
@@ -513,7 +476,7 @@ module Tapioca
|
|
513
476
|
constant
|
514
477
|
.props
|
515
478
|
.keys
|
516
|
-
.include?(method_name.gsub(/=$/,
|
479
|
+
.include?(method_name.gsub(/=$/, "").to_sym)
|
517
480
|
end
|
518
481
|
|
519
482
|
sig do
|
@@ -525,7 +488,7 @@ module Tapioca
|
|
525
488
|
visibility: RBI::Visibility
|
526
489
|
).void
|
527
490
|
end
|
528
|
-
def compile_method(tree, symbol_name, constant, method, visibility = RBI::
|
491
|
+
def compile_method(tree, symbol_name, constant, method, visibility = RBI::Public.new)
|
529
492
|
return unless method
|
530
493
|
return unless method.owner == constant
|
531
494
|
return if symbol_ignored?(symbol_name) && !method_in_gem?(method)
|
@@ -572,7 +535,15 @@ module Tapioca
|
|
572
535
|
[type, name]
|
573
536
|
end
|
574
537
|
|
575
|
-
|
538
|
+
separator = constant.singleton_class? ? "." : "#"
|
539
|
+
comments = documentation_comments("#{symbol_name}#{separator}#{method_name}")
|
540
|
+
rbi_method = RBI::Method.new(
|
541
|
+
method_name,
|
542
|
+
is_singleton: constant.singleton_class?,
|
543
|
+
visibility: visibility,
|
544
|
+
comments: comments
|
545
|
+
)
|
546
|
+
|
576
547
|
rbi_method.sigs << compile_signature(signature, sanitized_parameters) if signature
|
577
548
|
|
578
549
|
sanitized_parameters.each do |type, name|
|
@@ -615,7 +586,7 @@ module Tapioca
|
|
615
586
|
sig << RBI::SigParam.new(name, type)
|
616
587
|
end
|
617
588
|
|
618
|
-
return_type =
|
589
|
+
return_type = name_of_type(signature.return_type)
|
619
590
|
sig.return_type = sanitize_signature_types(return_type)
|
620
591
|
add_to_symbol_queue(sig.return_type)
|
621
592
|
|
@@ -638,12 +609,24 @@ module Tapioca
|
|
638
609
|
sig
|
639
610
|
end
|
640
611
|
|
612
|
+
sig { params(sig_string: String).returns(String) }
|
613
|
+
def sanitize_signature_types(sig_string)
|
614
|
+
sig_string
|
615
|
+
.gsub(".returns(<VOID>)", ".void")
|
616
|
+
.gsub("<VOID>", "void")
|
617
|
+
.gsub("<NOT-TYPED>", "T.untyped")
|
618
|
+
.gsub(".params()", "")
|
619
|
+
end
|
620
|
+
|
641
621
|
sig { params(symbol_name: String).returns(T::Boolean) }
|
642
622
|
def symbol_ignored?(symbol_name)
|
643
623
|
SymbolLoader.ignore_symbol?(symbol_name)
|
644
624
|
end
|
645
625
|
|
646
|
-
SPECIAL_METHOD_NAMES =
|
626
|
+
SPECIAL_METHOD_NAMES = T.let([
|
627
|
+
"!", "~", "+@", "**", "-@", "*", "/", "%", "+", "-", "<<", ">>", "&", "|", "^",
|
628
|
+
"<", "<=", "=>", ">", ">=", "==", "===", "!=", "=~", "!~", "<=>", "[]", "[]=", "`"
|
629
|
+
], T::Array[String])
|
647
630
|
|
648
631
|
sig { params(name: String).returns(T::Boolean) }
|
649
632
|
def valid_method_name?(name)
|
@@ -702,46 +685,13 @@ module Tapioca
|
|
702
685
|
@seen.include?(name)
|
703
686
|
end
|
704
687
|
|
688
|
+
sig { params(constant: Module).returns(T.nilable(UnboundMethod)) }
|
705
689
|
def initialize_method_for(constant)
|
706
690
|
constant.instance_method(:initialize)
|
707
691
|
rescue
|
708
692
|
nil
|
709
693
|
end
|
710
694
|
|
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
695
|
sig { params(constant: Module).returns(T::Array[Module]) }
|
746
696
|
def interesting_ancestors_of(constant)
|
747
697
|
inherited_ancestors_ids = Set.new(
|
@@ -771,9 +721,9 @@ module Tapioca
|
|
771
721
|
|
772
722
|
sig { params(constant: Module).returns(T.nilable(String)) }
|
773
723
|
def name_of(constant)
|
774
|
-
name = name_of_proxy_target(constant)
|
724
|
+
name = name_of_proxy_target(constant, super(class_of(constant)))
|
775
725
|
return name if name
|
776
|
-
name =
|
726
|
+
name = super(constant)
|
777
727
|
return if name.nil?
|
778
728
|
return unless are_equal?(constant, resolve_constant(name, inherit: true))
|
779
729
|
name = "Struct" if name =~ /^(::)?Struct::[^:]+$/
|
@@ -793,67 +743,33 @@ module Tapioca
|
|
793
743
|
"#{type_name}[#{type_variable_names}]"
|
794
744
|
end
|
795
745
|
|
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"
|
746
|
+
sig { params(constant: Module, class_name: T.nilable(String)).returns(T.nilable(String)) }
|
747
|
+
def name_of_proxy_target(constant, class_name)
|
748
|
+
return unless class_name == "ActiveSupport::Deprecation::DeprecatedConstantProxy"
|
800
749
|
# We are dealing with a ActiveSupport::Deprecation::DeprecatedConstantProxy
|
801
750
|
# so try to get the name of the target class
|
802
751
|
begin
|
803
|
-
target =
|
752
|
+
target = constant.__send__(:target)
|
804
753
|
rescue NoMethodError
|
805
754
|
return
|
806
755
|
end
|
807
756
|
|
808
|
-
|
757
|
+
name_of(target)
|
809
758
|
end
|
810
759
|
|
811
|
-
sig { params(
|
812
|
-
def
|
813
|
-
|
814
|
-
return if name.nil?
|
760
|
+
sig { params(name: String).returns(T::Array[RBI::Comment]) }
|
761
|
+
def documentation_comments(name)
|
762
|
+
return [] unless @include_doc
|
815
763
|
|
816
|
-
|
817
|
-
|
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
|
764
|
+
yard_docs = YARD::Registry.at(name)
|
765
|
+
return [] unless yard_docs
|
834
766
|
|
835
|
-
|
836
|
-
|
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
|
767
|
+
docstring = yard_docs.docstring
|
768
|
+
return [] if /(copyright|license)/i.match?(docstring)
|
853
769
|
|
854
|
-
|
855
|
-
|
856
|
-
|
770
|
+
docstring.lines
|
771
|
+
.reject { |line| IGNORED_COMMENTS.any? { |comment| line.include?(comment) } }
|
772
|
+
.map! { |line| RBI::Comment.new(line) }
|
857
773
|
end
|
858
774
|
end
|
859
775
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
4
|
+
require "json"
|
5
|
+
require "tempfile"
|
6
6
|
|
7
7
|
module Tapioca
|
8
8
|
module Compilers
|
@@ -25,7 +25,7 @@ module Tapioca
|
|
25
25
|
|
26
26
|
sig { params(paths: T::Array[String]).returns(T::Set[String]) }
|
27
27
|
def load_symbols(paths)
|
28
|
-
output = T.cast(Tempfile.create(
|
28
|
+
output = T.cast(Tempfile.create("sorbet") do |file|
|
29
29
|
file.write(Array(paths).join("\n"))
|
30
30
|
file.flush
|
31
31
|
|
@@ -69,7 +69,7 @@ module Tapioca
|
|
69
69
|
# TODO: CLASS is removed since v0.4.4730 of Sorbet
|
70
70
|
# but keeping here for backward compatibility. Remove
|
71
71
|
# once the minimum version is moved past that.
|
72
|
-
next unless
|
72
|
+
next unless ["CLASS", "CLASS_OR_MODULE", "STATIC_FIELD"].include?(kind)
|
73
73
|
next if name =~ /[<>()$]/
|
74
74
|
next if name =~ /^[0-9]+$/
|
75
75
|
next if name == "T::Helpers"
|
@@ -6,17 +6,11 @@ module Tapioca
|
|
6
6
|
class SymbolTableCompiler
|
7
7
|
extend(T::Sig)
|
8
8
|
|
9
|
-
sig
|
10
|
-
|
11
|
-
|
12
|
-
indent
|
13
|
-
|
14
|
-
end
|
15
|
-
def compile(
|
16
|
-
gem,
|
17
|
-
indent = 0
|
18
|
-
)
|
19
|
-
Tapioca::Compilers::SymbolTable::SymbolGenerator.new(gem, indent).generate
|
9
|
+
sig { params(gem: Gemfile::GemSpec, rbi: RBI::File, indent: Integer, include_docs: T::Boolean).void }
|
10
|
+
def compile(gem, rbi, indent = 0, include_docs = false)
|
11
|
+
Tapioca::Compilers::SymbolTable::SymbolGenerator
|
12
|
+
.new(gem, indent, include_docs)
|
13
|
+
.generate(rbi)
|
20
14
|
end
|
21
15
|
end
|
22
16
|
end
|
@@ -13,7 +13,7 @@ module Tapioca
|
|
13
13
|
def compile
|
14
14
|
list_todos.each_line.map do |line|
|
15
15
|
next if line.include?("<") || line.include?("class_of")
|
16
|
-
"module #{line.strip.gsub(
|
16
|
+
"module #{line.strip.gsub("T.untyped::", "")}; end"
|
17
17
|
end.compact.join("\n")
|
18
18
|
end
|
19
19
|
|
data/lib/tapioca/config.rb
CHANGED
@@ -9,9 +9,12 @@ module Tapioca
|
|
9
9
|
const(:prerequire, T.nilable(String))
|
10
10
|
const(:postrequire, String)
|
11
11
|
const(:exclude, T::Array[String])
|
12
|
+
const(:exclude_generators, T::Array[String])
|
12
13
|
const(:typed_overrides, T::Hash[String, String])
|
13
14
|
const(:todos_path, String)
|
14
15
|
const(:generators, T::Array[String])
|
16
|
+
const(:file_header, T::Boolean, default: true)
|
17
|
+
const(:doc, T::Boolean, default: false)
|
15
18
|
|
16
19
|
sig { returns(Pathname) }
|
17
20
|
def outpath
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
4
|
+
require "yaml"
|
5
5
|
|
6
6
|
module Tapioca
|
7
7
|
class ConfigBuilder
|
@@ -33,7 +33,7 @@ module Tapioca
|
|
33
33
|
sig { params(command: Symbol).returns(T::Hash[String, T.untyped]) }
|
34
34
|
def default_options(command)
|
35
35
|
default_outdir = case command
|
36
|
-
when :sync, :generate
|
36
|
+
when :sync, :generate, :gem
|
37
37
|
Config::DEFAULT_GEMDIR
|
38
38
|
when :dsl
|
39
39
|
Config::DEFAULT_DSLDIR
|
@@ -62,9 +62,12 @@ module Tapioca
|
|
62
62
|
"postrequire" => Config::DEFAULT_POSTREQUIRE,
|
63
63
|
"outdir" => nil,
|
64
64
|
"exclude" => [],
|
65
|
+
"exclude_generators" => [],
|
65
66
|
"typed_overrides" => Config::DEFAULT_OVERRIDES,
|
66
67
|
"todos_path" => Config::DEFAULT_TODOSPATH,
|
67
68
|
"generators" => [],
|
69
|
+
"file_header" => true,
|
70
|
+
"doc" => false,
|
68
71
|
}.freeze, T::Hash[String, T.untyped])
|
69
72
|
end
|
70
73
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
4
|
+
require "set"
|
5
5
|
|
6
6
|
module Tapioca
|
7
7
|
# Registers a TracePoint immediately upon load to track points at which
|
@@ -9,15 +9,14 @@ module Tapioca
|
|
9
9
|
# correspondence between classes/modules and files, as this information isn't
|
10
10
|
# available in the ruby runtime without extra accounting.
|
11
11
|
module ConstantLocator
|
12
|
-
|
12
|
+
extend Reflection
|
13
13
|
|
14
|
-
|
15
|
-
private_constant :NAME
|
14
|
+
@class_files = {}
|
16
15
|
|
17
16
|
# Immediately activated upon load. Observes class/module definition.
|
18
17
|
TracePoint.trace(:class) do |tp|
|
19
18
|
unless tp.self.singleton_class?
|
20
|
-
key =
|
19
|
+
key = name_of(tp.self)
|
21
20
|
@class_files[key] ||= Set.new
|
22
21
|
@class_files[key] << tp.path
|
23
22
|
end
|
@@ -26,11 +25,10 @@ module Tapioca
|
|
26
25
|
# Returns the files in which this class or module was opened. Doesn't know
|
27
26
|
# about situations where the class was opened prior to +require+ing,
|
28
27
|
# or where metaprogramming was used via +eval+, etc.
|
29
|
-
def files_for(klass)
|
30
|
-
name = String === klass ? klass :
|
28
|
+
def self.files_for(klass)
|
29
|
+
name = String === klass ? klass : name_of(klass)
|
31
30
|
files = @class_files[name]
|
32
31
|
files || Set.new
|
33
32
|
end
|
34
|
-
module_function :files_for
|
35
33
|
end
|
36
34
|
end
|