tapioca 0.4.27 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +15 -15
  3. data/README.md +2 -2
  4. data/Rakefile +5 -7
  5. data/exe/tapioca +2 -2
  6. data/lib/tapioca/cli.rb +172 -2
  7. data/lib/tapioca/compilers/dsl/aasm.rb +122 -0
  8. data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +52 -12
  9. data/lib/tapioca/compilers/dsl/action_mailer.rb +6 -9
  10. data/lib/tapioca/compilers/dsl/active_job.rb +8 -12
  11. data/lib/tapioca/compilers/dsl/active_model_attributes.rb +131 -0
  12. data/lib/tapioca/compilers/dsl/active_model_secure_password.rb +101 -0
  13. data/lib/tapioca/compilers/dsl/active_record_associations.rb +33 -54
  14. data/lib/tapioca/compilers/dsl/active_record_columns.rb +10 -105
  15. data/lib/tapioca/compilers/dsl/active_record_enum.rb +8 -10
  16. data/lib/tapioca/compilers/dsl/active_record_fixtures.rb +86 -0
  17. data/lib/tapioca/compilers/dsl/active_record_scope.rb +7 -10
  18. data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +5 -8
  19. data/lib/tapioca/compilers/dsl/active_resource.rb +9 -37
  20. data/lib/tapioca/compilers/dsl/active_storage.rb +98 -0
  21. data/lib/tapioca/compilers/dsl/active_support_concern.rb +106 -0
  22. data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +13 -8
  23. data/lib/tapioca/compilers/dsl/base.rb +108 -82
  24. data/lib/tapioca/compilers/dsl/config.rb +111 -0
  25. data/lib/tapioca/compilers/dsl/frozen_record.rb +5 -7
  26. data/lib/tapioca/compilers/dsl/identity_cache.rb +66 -29
  27. data/lib/tapioca/compilers/dsl/mixed_in_class_attributes.rb +74 -0
  28. data/lib/tapioca/compilers/dsl/protobuf.rb +19 -69
  29. data/lib/tapioca/compilers/dsl/sidekiq_worker.rb +25 -12
  30. data/lib/tapioca/compilers/dsl/smart_properties.rb +21 -33
  31. data/lib/tapioca/compilers/dsl/state_machines.rb +56 -78
  32. data/lib/tapioca/compilers/dsl/url_helpers.rb +7 -10
  33. data/lib/tapioca/compilers/dsl_compiler.rb +25 -40
  34. data/lib/tapioca/compilers/dynamic_mixin_compiler.rb +198 -0
  35. data/lib/tapioca/compilers/requires_compiler.rb +2 -2
  36. data/lib/tapioca/compilers/sorbet.rb +25 -5
  37. data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +122 -206
  38. data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +4 -4
  39. data/lib/tapioca/compilers/symbol_table_compiler.rb +5 -11
  40. data/lib/tapioca/compilers/todos_compiler.rb +1 -1
  41. data/lib/tapioca/config.rb +3 -0
  42. data/lib/tapioca/config_builder.rb +5 -2
  43. data/lib/tapioca/constant_locator.rb +6 -8
  44. data/lib/tapioca/gemfile.rb +14 -11
  45. data/lib/tapioca/generators/base.rb +61 -0
  46. data/lib/tapioca/generators/dsl.rb +362 -0
  47. data/lib/tapioca/generators/gem.rb +345 -0
  48. data/lib/tapioca/generators/init.rb +79 -0
  49. data/lib/tapioca/generators/require.rb +52 -0
  50. data/lib/tapioca/generators/todo.rb +76 -0
  51. data/lib/tapioca/generators.rb +9 -0
  52. data/lib/tapioca/generic_type_registry.rb +25 -98
  53. data/lib/tapioca/helpers/active_record_column_type_helper.rb +98 -0
  54. data/lib/tapioca/internal.rb +2 -10
  55. data/lib/tapioca/loader.rb +11 -31
  56. data/lib/tapioca/rbi_ext/model.rb +166 -0
  57. data/lib/tapioca/reflection.rb +138 -0
  58. data/lib/tapioca/sorbet_ext/fixed_hash_patch.rb +1 -1
  59. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +72 -4
  60. data/lib/tapioca/sorbet_ext/name_patch.rb +1 -1
  61. data/lib/tapioca/version.rb +1 -1
  62. data/lib/tapioca.rb +3 -0
  63. metadata +45 -23
  64. data/lib/tapioca/cli/main.rb +0 -146
  65. data/lib/tapioca/core_ext/class.rb +0 -28
  66. data/lib/tapioca/core_ext/string.rb +0 -18
  67. data/lib/tapioca/generator.rb +0 -633
  68. data/lib/tapioca/rbi/model.rb +0 -405
  69. data/lib/tapioca/rbi/printer.rb +0 -410
  70. data/lib/tapioca/rbi/rewriters/group_nodes.rb +0 -106
  71. data/lib/tapioca/rbi/rewriters/nest_non_public_methods.rb +0 -65
  72. data/lib/tapioca/rbi/rewriters/nest_singleton_methods.rb +0 -42
  73. data/lib/tapioca/rbi/rewriters/sort_nodes.rb +0 -86
  74. data/lib/tapioca/rbi/visitor.rb +0 -21
@@ -1,48 +1,56 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'pathname'
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
- IGNORED_SYMBOLS = %w{
13
- YAML
14
- MiniTest
15
- Mutex
16
- }
17
-
18
- attr_reader(:gem, :indent)
19
-
20
- sig { params(gem: Gemfile::GemSpec, indent: Integer).void }
21
- def initialize(gem, indent = 0)
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 ||= Set.new
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
- end
38
+ @symbols = T.let(nil, T.nilable(T::Set[String]))
39
+ @include_doc = include_doc
28
40
 
29
- sig { returns(String) }
30
- def generate
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
- rbi.nest_singleton_methods!
36
- rbi.nest_non_public_methods!
37
- rbi.group_nodes!
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
- .descendants.reject(&:abstract_railtie?)
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
- tree << RBI::Const.new(name, "T.type_alias { #{T.unsafe(value).aliased_type} }")
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 << RBI::Const.new(name, "T.let(T.unsafe(nil), #{type_name})")
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).map do |constant_name|
271
- [
272
- object_id_of(resolve_constant(constant_name.to_s, namespace: constant)),
273
- constant_name,
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 |type_variable_id, serialized_type_variable|
287
- constant_name = subconstant_to_name_lookup[type_variable_id]
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.to_s, serialized_type_variable)
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::Visibility::Protected
452
+ RBI::Protected.new
490
453
  when :private
491
- RBI::Visibility::Private
454
+ RBI::Private.new
492
455
  else
493
- RBI::Visibility::Public
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: Module.instance_method(:public_instance_methods).bind(mod).call,
504
- protected: Module.instance_method(:protected_instance_methods).bind(mod).call,
505
- private: Module.instance_method(:private_instance_methods).bind(mod).call,
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(/=$/, '').to_sym)
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::Visibility::Public)
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
- rbi_method = RBI::Method.new(method_name, is_singleton: constant.singleton_class?, visibility: visibility)
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 = type_of(signature.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 = %w[! ~ +@ ** -@ * / % + - << >> & | ^ < <= => > >= == === != =~ !~ <=> [] []= `]
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 = raw_name_of(constant)
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
- klass = class_of(constant)
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 = Kernel.instance_method(:send).bind(constant).call(:target)
752
+ target = constant.__send__(:target)
804
753
  rescue NoMethodError
805
754
  return
806
755
  end
807
756
 
808
- raw_name_of(target)
757
+ name_of(target)
809
758
  end
810
759
 
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?
760
+ sig { params(name: String).returns(T::Array[RBI::Comment]) }
761
+ def documentation_comments(name)
762
+ return [] unless @include_doc
815
763
 
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
764
+ yard_docs = YARD::Registry.at(name)
765
+ return [] unless yard_docs
834
766
 
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
767
+ docstring = yard_docs.docstring
768
+ return [] if /(copyright|license)/i.match?(docstring)
853
769
 
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)
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 'json'
5
- require 'tempfile'
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('sorbet') do |file|
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 %w[CLASS CLASS_OR_MODULE STATIC_FIELD].include?(kind)
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 do
10
- params(
11
- gem: Gemfile::GemSpec,
12
- indent: Integer
13
- ).returns(String)
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('T.untyped::', '')}; end"
16
+ "module #{line.strip.gsub("T.untyped::", "")}; end"
17
17
  end.compact.join("\n")
18
18
  end
19
19
 
@@ -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 'yaml'
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 'set'
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
- @class_files = {}
12
+ extend Reflection
13
13
 
14
- NAME = Module.instance_method(:name)
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 = NAME.bind(tp.self).call
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 : NAME.bind(klass).call
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