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.
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