tapioca 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) 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 +84 -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 +10 -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 +11 -11
  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 +10 -8
  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 +10 -8
  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 +16 -14
  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 +2 -2
  46. data/lib/tapioca/{compilers/dsl_compiler.rb → dsl/pipeline.rb} +41 -33
  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/rbi_helper.rb +17 -0
  66. data/lib/tapioca/helpers/shims_helper.rb +87 -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/internal.rb +17 -10
  72. data/lib/tapioca/rbi_ext/model.rb +2 -48
  73. data/lib/tapioca/rbi_formatter.rb +37 -0
  74. data/lib/tapioca/runtime/dynamic_mixin_compiler.rb +227 -0
  75. data/lib/tapioca/runtime/generic_type_registry.rb +166 -0
  76. data/lib/tapioca/runtime/loader.rb +123 -0
  77. data/lib/tapioca/runtime/reflection.rb +153 -0
  78. data/lib/tapioca/runtime/trackers/autoload.rb +72 -0
  79. data/lib/tapioca/runtime/trackers/constant_definition.rb +44 -0
  80. data/lib/tapioca/runtime/trackers/mixin.rb +80 -0
  81. data/lib/tapioca/runtime/trackers/required_ancestor.rb +50 -0
  82. data/lib/tapioca/{trackers.rb → runtime/trackers.rb} +4 -3
  83. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +33 -15
  84. data/lib/tapioca/sorbet_ext/name_patch.rb +7 -1
  85. data/lib/tapioca/{compilers → static}/requires_compiler.rb +2 -2
  86. data/lib/tapioca/static/symbol_loader.rb +83 -0
  87. data/lib/tapioca/static/symbol_table_parser.rb +63 -0
  88. data/lib/tapioca/version.rb +1 -1
  89. data/lib/tapioca.rb +2 -7
  90. metadata +80 -60
  91. data/lib/tapioca/compilers/dsl/active_record_relations.rb +0 -720
  92. data/lib/tapioca/compilers/dsl/base.rb +0 -195
  93. data/lib/tapioca/compilers/dsl/helper/active_record_constants.rb +0 -27
  94. data/lib/tapioca/compilers/dynamic_mixin_compiler.rb +0 -223
  95. data/lib/tapioca/compilers/sorbet.rb +0 -59
  96. data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +0 -780
  97. data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +0 -90
  98. data/lib/tapioca/compilers/symbol_table_compiler.rb +0 -17
  99. data/lib/tapioca/compilers/todos_compiler.rb +0 -32
  100. data/lib/tapioca/generators/todo.rb +0 -76
  101. data/lib/tapioca/generators.rb +0 -9
  102. data/lib/tapioca/generic_type_registry.rb +0 -164
  103. data/lib/tapioca/helpers/active_record_column_type_helper.rb +0 -108
  104. data/lib/tapioca/loader.rb +0 -119
  105. data/lib/tapioca/reflection.rb +0 -151
  106. data/lib/tapioca/trackers/autoload.rb +0 -70
  107. data/lib/tapioca/trackers/constant_definition.rb +0 -42
  108. 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