tapioca 0.6.4 → 0.7.2

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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +8 -2
  3. data/README.md +27 -15
  4. data/Rakefile +10 -14
  5. data/lib/tapioca/cli.rb +65 -80
  6. data/lib/tapioca/{generators/base.rb → commands/command.rb} +16 -9
  7. data/lib/tapioca/{generators → commands}/dsl.rb +59 -45
  8. data/lib/tapioca/{generators → commands}/gem.rb +93 -30
  9. data/lib/tapioca/{generators → commands}/init.rb +9 -13
  10. data/lib/tapioca/{generators → commands}/require.rb +8 -10
  11. data/lib/tapioca/commands/todo.rb +86 -0
  12. data/lib/tapioca/commands.rb +13 -0
  13. data/lib/tapioca/dsl/compiler.rb +185 -0
  14. data/lib/tapioca/{compilers/dsl → dsl/compilers}/aasm.rb +12 -9
  15. data/lib/tapioca/{compilers/dsl → dsl/compilers}/action_controller_helpers.rb +13 -20
  16. data/lib/tapioca/{compilers/dsl → dsl/compilers}/action_mailer.rb +10 -8
  17. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_job.rb +11 -9
  18. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_model_attributes.rb +13 -11
  19. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_model_secure_password.rb +10 -12
  20. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_associations.rb +28 -34
  21. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_columns.rb +18 -16
  22. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_enum.rb +14 -12
  23. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_fixtures.rb +12 -8
  24. data/lib/tapioca/dsl/compilers/active_record_relations.rb +712 -0
  25. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_scope.rb +21 -20
  26. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_record_typed_store.rb +11 -16
  27. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_resource.rb +10 -8
  28. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_storage.rb +14 -10
  29. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_support_concern.rb +19 -14
  30. data/lib/tapioca/{compilers/dsl → dsl/compilers}/active_support_current_attributes.rb +16 -21
  31. data/lib/tapioca/{compilers/dsl → dsl/compilers}/config.rb +11 -9
  32. data/lib/tapioca/{compilers/dsl → dsl/compilers}/frozen_record.rb +13 -11
  33. data/lib/tapioca/{compilers/dsl → dsl/compilers}/identity_cache.rb +23 -22
  34. data/lib/tapioca/{compilers/dsl → dsl/compilers}/mixed_in_class_attributes.rb +12 -10
  35. data/lib/tapioca/{compilers/dsl → dsl/compilers}/protobuf.rb +22 -10
  36. data/lib/tapioca/{compilers/dsl → dsl/compilers}/rails_generators.rb +12 -13
  37. data/lib/tapioca/{compilers/dsl → dsl/compilers}/sidekiq_worker.rb +14 -13
  38. data/lib/tapioca/{compilers/dsl → dsl/compilers}/smart_properties.rb +11 -9
  39. data/lib/tapioca/{compilers/dsl → dsl/compilers}/state_machines.rb +12 -10
  40. data/lib/tapioca/{compilers/dsl → dsl/compilers}/url_helpers.rb +20 -15
  41. data/lib/tapioca/dsl/compilers.rb +31 -0
  42. data/lib/tapioca/{compilers/dsl → dsl}/extensions/frozen_record.rb +2 -2
  43. data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +114 -0
  44. data/lib/tapioca/dsl/helpers/active_record_constants_helper.rb +29 -0
  45. data/lib/tapioca/{compilers/dsl → dsl/helpers}/param_helper.rb +6 -3
  46. data/lib/tapioca/dsl/pipeline.rb +169 -0
  47. data/lib/tapioca/gem/events.rb +120 -0
  48. data/lib/tapioca/gem/listeners/base.rb +48 -0
  49. data/lib/tapioca/gem/listeners/dynamic_mixins.rb +32 -0
  50. data/lib/tapioca/gem/listeners/methods.rb +183 -0
  51. data/lib/tapioca/gem/listeners/mixins.rb +101 -0
  52. data/lib/tapioca/gem/listeners/remove_empty_payload_scopes.rb +21 -0
  53. data/lib/tapioca/gem/listeners/sorbet_enums.rb +26 -0
  54. data/lib/tapioca/gem/listeners/sorbet_helpers.rb +29 -0
  55. data/lib/tapioca/gem/listeners/sorbet_props.rb +33 -0
  56. data/lib/tapioca/gem/listeners/sorbet_required_ancestors.rb +23 -0
  57. data/lib/tapioca/gem/listeners/sorbet_signatures.rb +79 -0
  58. data/lib/tapioca/gem/listeners/sorbet_type_variables.rb +51 -0
  59. data/lib/tapioca/gem/listeners/subconstants.rb +37 -0
  60. data/lib/tapioca/gem/listeners/yard_doc.rb +96 -0
  61. data/lib/tapioca/gem/listeners.rb +16 -0
  62. data/lib/tapioca/gem/pipeline.rb +365 -0
  63. data/lib/tapioca/helpers/cli_helper.rb +7 -0
  64. data/lib/tapioca/helpers/config_helper.rb +5 -8
  65. data/lib/tapioca/helpers/shims_helper.rb +87 -0
  66. data/lib/tapioca/helpers/signatures_helper.rb +17 -0
  67. data/lib/tapioca/helpers/sorbet_helper.rb +57 -0
  68. data/lib/tapioca/helpers/test/dsl_compiler.rb +118 -0
  69. data/lib/tapioca/helpers/test/isolation.rb +1 -1
  70. data/lib/tapioca/helpers/test/template.rb +13 -2
  71. data/lib/tapioca/helpers/type_variable_helper.rb +43 -0
  72. data/lib/tapioca/internal.rb +18 -10
  73. data/lib/tapioca/rbi_ext/model.rb +14 -50
  74. data/lib/tapioca/rbi_formatter.rb +37 -0
  75. data/lib/tapioca/runtime/dynamic_mixin_compiler.rb +227 -0
  76. data/lib/tapioca/runtime/generic_type_registry.rb +168 -0
  77. data/lib/tapioca/runtime/loader.rb +123 -0
  78. data/lib/tapioca/runtime/reflection.rb +157 -0
  79. data/lib/tapioca/runtime/trackers/autoload.rb +72 -0
  80. data/lib/tapioca/runtime/trackers/constant_definition.rb +44 -0
  81. data/lib/tapioca/runtime/trackers/mixin.rb +80 -0
  82. data/lib/tapioca/runtime/trackers/required_ancestor.rb +50 -0
  83. data/lib/tapioca/{trackers.rb → runtime/trackers.rb} +4 -3
  84. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +69 -34
  85. data/lib/tapioca/sorbet_ext/name_patch.rb +7 -1
  86. data/lib/tapioca/{compilers → static}/requires_compiler.rb +2 -2
  87. data/lib/tapioca/static/symbol_loader.rb +83 -0
  88. data/lib/tapioca/static/symbol_table_parser.rb +63 -0
  89. data/lib/tapioca/version.rb +1 -1
  90. data/lib/tapioca.rb +2 -7
  91. metadata +83 -62
  92. data/lib/tapioca/compilers/dsl/active_record_relations.rb +0 -720
  93. data/lib/tapioca/compilers/dsl/base.rb +0 -195
  94. data/lib/tapioca/compilers/dsl/helper/active_record_constants.rb +0 -27
  95. data/lib/tapioca/compilers/dsl_compiler.rb +0 -134
  96. data/lib/tapioca/compilers/dynamic_mixin_compiler.rb +0 -223
  97. data/lib/tapioca/compilers/sorbet.rb +0 -59
  98. data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +0 -780
  99. data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +0 -90
  100. data/lib/tapioca/compilers/symbol_table_compiler.rb +0 -17
  101. data/lib/tapioca/compilers/todos_compiler.rb +0 -32
  102. data/lib/tapioca/generators/todo.rb +0 -76
  103. data/lib/tapioca/generators.rb +0 -9
  104. data/lib/tapioca/generic_type_registry.rb +0 -164
  105. data/lib/tapioca/helpers/active_record_column_type_helper.rb +0 -108
  106. data/lib/tapioca/loader.rb +0 -119
  107. data/lib/tapioca/reflection.rb +0 -151
  108. data/lib/tapioca/trackers/autoload.rb +0 -70
  109. data/lib/tapioca/trackers/constant_definition.rb +0 -42
  110. data/lib/tapioca/trackers/mixin.rb +0 -78
@@ -1,151 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module Tapioca
5
- module Reflection
6
- extend T::Sig
7
- extend self
8
-
9
- CLASS_METHOD = T.let(Kernel.instance_method(:class), UnboundMethod)
10
- CONSTANTS_METHOD = T.let(Module.instance_method(:constants), UnboundMethod)
11
- NAME_METHOD = T.let(Module.instance_method(:name), UnboundMethod)
12
- SINGLETON_CLASS_METHOD = T.let(Object.instance_method(:singleton_class), UnboundMethod)
13
- ANCESTORS_METHOD = T.let(Module.instance_method(:ancestors), UnboundMethod)
14
- SUPERCLASS_METHOD = T.let(Class.instance_method(:superclass), UnboundMethod)
15
- OBJECT_ID_METHOD = T.let(BasicObject.instance_method(:__id__), UnboundMethod)
16
- EQUAL_METHOD = T.let(BasicObject.instance_method(:equal?), UnboundMethod)
17
- PUBLIC_INSTANCE_METHODS_METHOD = T.let(Module.instance_method(:public_instance_methods), UnboundMethod)
18
- PROTECTED_INSTANCE_METHODS_METHOD = T.let(Module.instance_method(:protected_instance_methods), UnboundMethod)
19
- PRIVATE_INSTANCE_METHODS_METHOD = T.let(Module.instance_method(:private_instance_methods), UnboundMethod)
20
- METHOD_METHOD = T.let(Kernel.instance_method(:method), UnboundMethod)
21
-
22
- sig do
23
- params(
24
- symbol: String,
25
- inherit: T::Boolean,
26
- namespace: Module
27
- ).returns(BasicObject).checked(:never)
28
- end
29
- def constantize(symbol, inherit: false, namespace: Object)
30
- namespace.const_get(symbol, inherit)
31
- rescue NameError, LoadError, RuntimeError, ArgumentError, TypeError
32
- nil
33
- end
34
-
35
- sig { params(object: BasicObject).returns(Class).checked(:never) }
36
- def class_of(object)
37
- CLASS_METHOD.bind(object).call
38
- end
39
-
40
- sig { params(constant: Module).returns(T::Array[Symbol]) }
41
- def constants_of(constant)
42
- CONSTANTS_METHOD.bind(constant).call(false)
43
- end
44
-
45
- sig { params(constant: Module).returns(T.nilable(String)) }
46
- def name_of(constant)
47
- name = NAME_METHOD.bind(constant).call
48
- name&.start_with?("#<") ? nil : name
49
- end
50
-
51
- sig { params(constant: Module).returns(Class) }
52
- def singleton_class_of(constant)
53
- SINGLETON_CLASS_METHOD.bind(constant).call
54
- end
55
-
56
- sig { params(constant: Module).returns(T::Array[Module]) }
57
- def ancestors_of(constant)
58
- ANCESTORS_METHOD.bind(constant).call
59
- end
60
-
61
- sig { params(constant: Class).returns(T.nilable(Class)) }
62
- def superclass_of(constant)
63
- SUPERCLASS_METHOD.bind(constant).call
64
- end
65
-
66
- sig { params(object: BasicObject).returns(Integer).checked(:never) }
67
- def object_id_of(object)
68
- OBJECT_ID_METHOD.bind(object).call
69
- end
70
-
71
- sig { params(object: BasicObject, other: BasicObject).returns(T::Boolean).checked(:never) }
72
- def are_equal?(object, other)
73
- EQUAL_METHOD.bind(object).call(other)
74
- end
75
-
76
- sig { params(constant: Module).returns(T::Array[Symbol]) }
77
- def public_instance_methods_of(constant)
78
- PUBLIC_INSTANCE_METHODS_METHOD.bind(constant).call
79
- end
80
-
81
- sig { params(constant: Module).returns(T::Array[Symbol]) }
82
- def protected_instance_methods_of(constant)
83
- PROTECTED_INSTANCE_METHODS_METHOD.bind(constant).call
84
- end
85
-
86
- sig { params(constant: Module).returns(T::Array[Symbol]) }
87
- def private_instance_methods_of(constant)
88
- PRIVATE_INSTANCE_METHODS_METHOD.bind(constant).call
89
- end
90
-
91
- sig { params(constant: Module).returns(T::Array[Module]) }
92
- def inherited_ancestors_of(constant)
93
- if Class === constant
94
- ancestors_of(superclass_of(constant) || Object)
95
- else
96
- Module.ancestors
97
- end
98
- end
99
-
100
- sig { params(constant: Module).returns(T.nilable(String)) }
101
- def qualified_name_of(constant)
102
- name = name_of(constant)
103
- return if name.nil?
104
-
105
- if name.start_with?("::")
106
- name
107
- else
108
- "::#{name}"
109
- end
110
- end
111
-
112
- sig { params(method: T.any(UnboundMethod, Method)).returns(T.untyped) }
113
- def signature_of(method)
114
- T::Private::Methods.signature_for_method(method)
115
- rescue LoadError, StandardError
116
- nil
117
- end
118
-
119
- sig { params(type: T::Types::Base).returns(String) }
120
- def name_of_type(type)
121
- type.to_s.gsub(/\bAttachedClass\b/, "T.attached_class")
122
- end
123
-
124
- sig { params(constant: Module, method: Symbol).returns(Method) }
125
- def method_of(constant, method)
126
- METHOD_METHOD.bind(constant).call(method)
127
- end
128
-
129
- # Returns an array with all classes that are < than the supplied class.
130
- #
131
- # class C; end
132
- # descendants_of(C) # => []
133
- #
134
- # class B < C; end
135
- # descendants_of(C) # => [B]
136
- #
137
- # class A < B; end
138
- # descendants_of(C) # => [B, A]
139
- #
140
- # class D < C; end
141
- # descendants_of(C) # => [B, A, D]
142
- sig { type_parameters(:U).params(klass: T.type_parameter(:U)).returns(T::Array[T.type_parameter(:U)]) }
143
- def descendants_of(klass)
144
- result = ObjectSpace.each_object(klass.singleton_class).reject do |k|
145
- T.cast(k, Module).singleton_class? || T.unsafe(k) == klass
146
- end
147
-
148
- T.unsafe(result)
149
- end
150
- end
151
- end
@@ -1,70 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- module Tapioca
5
- module Trackers
6
- module Autoload
7
- extend T::Sig
8
-
9
- NOOP_METHOD = -> (*_args, **_kwargs, &_block) {}
10
-
11
- @constant_names_registered_for_autoload = T.let([], T::Array[String])
12
-
13
- class << self
14
- extend T::Sig
15
-
16
- sig { void }
17
- def eager_load_all!
18
- with_disabled_exits do
19
- until @constant_names_registered_for_autoload.empty?
20
- # Grab the next constant name
21
- constant_name = T.must(@constant_names_registered_for_autoload.shift)
22
- # Trigger autoload by constantizing the registered name
23
- Reflection.constantize(constant_name, inherit: true)
24
- end
25
- end
26
- end
27
-
28
- sig { params(constant_name: String).void }
29
- def register(constant_name)
30
- @constant_names_registered_for_autoload << constant_name
31
- end
32
-
33
- sig do
34
- type_parameters(:Result)
35
- .params(block: T.proc.returns(T.type_parameter(:Result)))
36
- .returns(T.type_parameter(:Result))
37
- end
38
- def with_disabled_exits(&block)
39
- original_abort = Kernel.instance_method(:abort)
40
- original_exit = Kernel.instance_method(:exit)
41
-
42
- begin
43
- Kernel.define_method(:abort, NOOP_METHOD)
44
- Kernel.define_method(:exit, NOOP_METHOD)
45
-
46
- block.call
47
- ensure
48
- Kernel.define_method(:exit, original_exit)
49
- Kernel.define_method(:abort, original_abort)
50
- end
51
- end
52
- end
53
- end
54
- end
55
- end
56
-
57
- # We need to do the alias-method-chain dance since Bootsnap does the same,
58
- # and prepended modules and alias-method-chain don't play well together.
59
- #
60
- # So, why does Bootsnap do alias-method-chain and not prepend? Glad you asked!
61
- # That's because RubyGems does alias-method-chain for Kernel#require and such,
62
- # so, if Bootsnap were to do prepend, it might end up breaking RubyGems.
63
- class Module
64
- alias_method(:autoload_without_tapioca, :autoload)
65
-
66
- def autoload(const_name, path)
67
- Tapioca::Trackers::Autoload.register("#{self}::#{const_name}")
68
- autoload_without_tapioca(const_name, path)
69
- end
70
- end
@@ -1,42 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- require "set"
5
-
6
- module Tapioca
7
- module Trackers
8
- # Registers a TracePoint immediately upon load to track points at which
9
- # classes and modules are opened for definition. This is used to track
10
- # correspondence between classes/modules and files, as this information isn't
11
- # available in the ruby runtime without extra accounting.
12
- module ConstantDefinition
13
- extend Reflection
14
-
15
- @class_files = {}
16
-
17
- # Immediately activated upon load. Observes class/module definition.
18
- TracePoint.trace(:class) do |tp|
19
- unless tp.self.singleton_class?
20
- key = name_of(tp.self)
21
- file = tp.path
22
- if file == "(eval)"
23
- file = T.must(caller_locations)
24
- .drop_while { |loc| loc.path == "(eval)" }
25
- .first&.path
26
- end
27
- @class_files[key] ||= Set.new
28
- @class_files[key] << file
29
- end
30
- end
31
-
32
- # Returns the files in which this class or module was opened. Doesn't know
33
- # about situations where the class was opened prior to +require+ing,
34
- # or where metaprogramming was used via +eval+, etc.
35
- def self.files_for(klass)
36
- name = String === klass ? klass : name_of(klass)
37
- files = @class_files[name]
38
- files || Set.new
39
- end
40
- end
41
- end
42
- end
@@ -1,78 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- module Tapioca
5
- module Trackers
6
- module Mixin
7
- extend T::Sig
8
-
9
- @mixin_map = {}.compare_by_identity
10
-
11
- class Type < T::Enum
12
- enums do
13
- Prepend = new
14
- Include = new
15
- Extend = new
16
- end
17
- end
18
-
19
- sig do
20
- params(
21
- constant: Module,
22
- mod: Module,
23
- mixin_type: Type,
24
- locations: T.nilable(T::Array[Thread::Backtrace::Location])
25
- ).void
26
- end
27
- def self.register(constant, mod, mixin_type, locations)
28
- locations ||= []
29
- locations.map!(&:absolute_path).uniq!
30
- locs = mixin_locations_for(constant)
31
- locs.fetch(mixin_type).store(mod, T.cast(locations, T::Array[String]))
32
- end
33
-
34
- sig { params(constant: Module).returns(T::Hash[Type, T::Hash[Module, T::Array[String]]]) }
35
- def self.mixin_locations_for(constant)
36
- @mixin_map[constant] ||= {
37
- Type::Prepend => {}.compare_by_identity,
38
- Type::Include => {}.compare_by_identity,
39
- Type::Extend => {}.compare_by_identity,
40
- }
41
- end
42
- end
43
- end
44
- end
45
-
46
- class Module
47
- prepend(Module.new do
48
- def prepend_features(constant)
49
- Tapioca::Trackers::Mixin.register(
50
- constant,
51
- self,
52
- Tapioca::Trackers::Mixin::Type::Prepend,
53
- caller_locations
54
- )
55
- super
56
- end
57
-
58
- def append_features(constant)
59
- Tapioca::Trackers::Mixin.register(
60
- constant,
61
- self,
62
- Tapioca::Trackers::Mixin::Type::Include,
63
- caller_locations
64
- )
65
- super
66
- end
67
-
68
- def extend_object(obj)
69
- Tapioca::Trackers::Mixin.register(
70
- obj,
71
- self,
72
- Tapioca::Trackers::Mixin::Type::Extend,
73
- caller_locations
74
- ) if Module === obj
75
- super
76
- end
77
- end)
78
- end