Module: Tapioca::Runtime::Reflection
- Extended by:
- Reflection
- Included in:
- Dsl::Compiler, Dsl::Compiler, Gem::Listeners::DynamicMixins, Gem::Listeners::ForeignConstants, Gem::Listeners::Methods, Gem::Listeners::Mixins, Gem::Listeners::RemoveEmptyPayloadScopes, Gem::Listeners::SorbetHelpers, Gem::Listeners::SorbetSignatures, Gem::Listeners::SorbetTypeVariables, Gem::Listeners::Subconstants, Gem::Pipeline, DynamicMixinCompiler, Reflection, Trackers::ConstantDefinition, Static::SymbolLoader
- Defined in:
- lib/tapioca/runtime/reflection.rb
Constant Summary collapse
- CLASS_METHOD =
: UnboundMethod
Kernel.instance_method(:class)
- CONSTANTS_METHOD =
: UnboundMethod
Module.instance_method(:constants)
- NAME_METHOD =
: UnboundMethod
Module.instance_method(:name)
- SINGLETON_CLASS_METHOD =
: UnboundMethod
Object.instance_method(:singleton_class)
- ANCESTORS_METHOD =
: UnboundMethod
Module.instance_method(:ancestors)
- SUPERCLASS_METHOD =
: UnboundMethod
Class.instance_method(:superclass)
- OBJECT_ID_METHOD =
: UnboundMethod
BasicObject.instance_method(:__id__)
- EQUAL_METHOD =
: UnboundMethod
BasicObject.instance_method(:equal?)
- PUBLIC_INSTANCE_METHODS_METHOD =
: UnboundMethod
Module.instance_method(:public_instance_methods)
- PROTECTED_INSTANCE_METHODS_METHOD =
: UnboundMethod
Module.instance_method(:protected_instance_methods)
- PRIVATE_INSTANCE_METHODS_METHOD =
: UnboundMethod
Module.instance_method(:private_instance_methods)
- METHOD_METHOD =
: UnboundMethod
Kernel.instance_method(:method)
- UNDEFINED_CONSTANT =
Module.new.freeze
- REQUIRED_FROM_LABELS =
: Array
["<top (required)>", "<main>", "<compiled>"].freeze
- SignatureBlockError =
Class.new(Tapioca::Error)
Instance Method Summary collapse
-
#abstract_type_of(constant) ⇒ Object
: (T::Module constant) -> untyped.
-
#ancestors_of(constant) ⇒ Object
: (T::Module constant) -> Array[T::Module].
-
#are_equal?(object, other) ⇒ Boolean
: (BasicObject object, BasicObject other) -> bool.
- #attached_class_of(singleton_class) ⇒ Object
-
#class_of(object) ⇒ Object
: (BasicObject object) -> Class.
-
#const_source_location(constant_name) ⇒ Object
: ((String | Symbol) constant_name) -> SourceLocation?.
-
#constant_defined?(constant) ⇒ Boolean
: (BasicObject constant) -> bool.
-
#constantize(symbol, inherit: false, namespace: Object) ⇒ Object
: (String symbol, ?inherit: bool, ?namespace: T::Module) -> BasicObject.
- #constants_of(constant) ⇒ Object
-
#descendants_of(klass) ⇒ Object
Returns an array with all classes that are < than the supplied class.
- #file_candidates_for(constant) ⇒ Object
-
#final_module?(constant) ⇒ Boolean
: (T::Module constant) -> bool.
-
#inherited_ancestors_of(constant) ⇒ Object
: (T::Module constant) -> Array[T::Module].
-
#method_of(constant, method) ⇒ Object
: (T::Module constant, Symbol method) -> Method.
-
#name_of(constant) ⇒ Object
: (T::Module constant) -> String?.
-
#name_of_type(type) ⇒ Object
: (T::Types::Base type) -> String.
-
#object_id_of(object) ⇒ Object
: (BasicObject object) -> Integer.
- #private_instance_methods_of(constant) ⇒ Object
- #protected_instance_methods_of(constant) ⇒ Object
- #public_instance_methods_of(constant) ⇒ Object
-
#qualified_name_of(constant) ⇒ Object
: (T::Module constant) -> String?.
-
#resolve_loc(locations) ⇒ Object
Examines the call stack to identify the closest location where a “require” is performed by searching for the label “<top (required)>” or “block in <class:…>” in the case of an ActiveSupport.on_load hook.
-
#sealed_module?(constant) ⇒ Boolean
: (T::Module constant) -> bool.
-
#signature_of(method) ⇒ Object
: ((UnboundMethod | Method) method) -> untyped.
-
#signature_of!(method) ⇒ Object
: ((UnboundMethod | Method) method) -> untyped.
- #singleton_class_of(constant) ⇒ Object
- #superclass_of(constant) ⇒ Object
Instance Method Details
#abstract_type_of(constant) ⇒ Object
: (T::Module constant) -> untyped
222 223 224 225 |
# File 'lib/tapioca/runtime/reflection.rb', line 222 def abstract_type_of(constant) T::Private::Abstract::Data.get(constant, :abstract_type) || T::Private::Abstract::Data.get(singleton_class_of(constant), :abstract_type) end |
#ancestors_of(constant) ⇒ Object
: (T::Module constant) -> Array[T::Module]
63 64 65 |
# File 'lib/tapioca/runtime/reflection.rb', line 63 def ancestors_of(constant) ANCESTORS_METHOD.bind_call(constant) end |
#are_equal?(object, other) ⇒ Boolean
: (BasicObject object, BasicObject other) -> bool
84 85 86 |
# File 'lib/tapioca/runtime/reflection.rb', line 84 def are_equal?(object, other) EQUAL_METHOD.bind_call(object, other) end |
#attached_class_of(singleton_class) ⇒ Object
73 74 75 76 |
# File 'lib/tapioca/runtime/reflection.rb', line 73 def attached_class_of(singleton_class) result = singleton_class.attached_object Module === result ? result : nil end |
#class_of(object) ⇒ Object
: (BasicObject object) -> Class
42 43 44 |
# File 'lib/tapioca/runtime/reflection.rb', line 42 def class_of(object) CLASS_METHOD.bind_call(object) end |
#const_source_location(constant_name) ⇒ Object
: ((String | Symbol) constant_name) -> SourceLocation?
173 174 175 176 177 178 179 |
# File 'lib/tapioca/runtime/reflection.rb', line 173 def const_source_location(constant_name) return unless Object.respond_to?(:const_source_location) file, line = Object.const_source_location(constant_name) SourceLocation.from_loc([file, line]) if file && line end |
#constant_defined?(constant) ⇒ Boolean
: (BasicObject constant) -> bool
29 30 31 |
# File 'lib/tapioca/runtime/reflection.rb', line 29 def constant_defined?(constant) !UNDEFINED_CONSTANT.eql?(constant) end |
#constantize(symbol, inherit: false, namespace: Object) ⇒ Object
: (String symbol, ?inherit: bool, ?namespace: T::Module) -> BasicObject
35 36 37 38 39 |
# File 'lib/tapioca/runtime/reflection.rb', line 35 def constantize(symbol, inherit: false, namespace: Object) namespace.const_get(symbol, inherit) rescue NameError, LoadError, RuntimeError, ArgumentError, TypeError UNDEFINED_CONSTANT end |
#constants_of(constant) ⇒ Object
47 48 49 |
# File 'lib/tapioca/runtime/reflection.rb', line 47 def constants_of(constant) CONSTANTS_METHOD.bind_call(constant, false) end |
#descendants_of(klass) ⇒ Object
164 165 166 167 168 169 170 |
# File 'lib/tapioca/runtime/reflection.rb', line 164 def descendants_of(klass) result = ObjectSpace.each_object(klass.singleton_class).reject do |k| k.singleton_class? || k == klass end T.unsafe(result) end |
#file_candidates_for(constant) ⇒ Object
215 216 217 218 219 |
# File 'lib/tapioca/runtime/reflection.rb', line 215 def file_candidates_for(constant) relevant_methods_for(constant).filter_map do |method| method.source_location&.first end.to_set end |
#final_module?(constant) ⇒ Boolean
: (T::Module constant) -> bool
228 229 230 |
# File 'lib/tapioca/runtime/reflection.rb', line 228 def final_module?(constant) T::Private::Final.final_module?(constant) end |
#inherited_ancestors_of(constant) ⇒ Object
: (T::Module constant) -> Array[T::Module]
104 105 106 107 108 109 110 |
# File 'lib/tapioca/runtime/reflection.rb', line 104 def inherited_ancestors_of(constant) if Class === constant ancestors_of(superclass_of(constant) || Object) else Module.new.ancestors end end |
#method_of(constant, method) ⇒ Object
: (T::Module constant, Symbol method) -> Method
146 147 148 |
# File 'lib/tapioca/runtime/reflection.rb', line 146 def method_of(constant, method) METHOD_METHOD.bind_call(constant, method) end |
#name_of(constant) ⇒ Object
: (T::Module constant) -> String?
52 53 54 55 |
# File 'lib/tapioca/runtime/reflection.rb', line 52 def name_of(constant) name = NAME_METHOD.bind_call(constant) name&.start_with?("#<") ? nil : name end |
#name_of_type(type) ⇒ Object
: (T::Types::Base type) -> String
141 142 143 |
# File 'lib/tapioca/runtime/reflection.rb', line 141 def name_of_type(type) type.to_s end |
#object_id_of(object) ⇒ Object
: (BasicObject object) -> Integer
79 80 81 |
# File 'lib/tapioca/runtime/reflection.rb', line 79 def object_id_of(object) OBJECT_ID_METHOD.bind_call(object) end |
#private_instance_methods_of(constant) ⇒ Object
99 100 101 |
# File 'lib/tapioca/runtime/reflection.rb', line 99 def private_instance_methods_of(constant) PRIVATE_INSTANCE_METHODS_METHOD.bind_call(constant) end |
#protected_instance_methods_of(constant) ⇒ Object
94 95 96 |
# File 'lib/tapioca/runtime/reflection.rb', line 94 def protected_instance_methods_of(constant) PROTECTED_INSTANCE_METHODS_METHOD.bind_call(constant) end |
#public_instance_methods_of(constant) ⇒ Object
89 90 91 |
# File 'lib/tapioca/runtime/reflection.rb', line 89 def public_instance_methods_of(constant) PUBLIC_INSTANCE_METHODS_METHOD.bind_call(constant) end |
#qualified_name_of(constant) ⇒ Object
: (T::Module constant) -> String?
113 114 115 116 117 118 119 120 121 122 |
# File 'lib/tapioca/runtime/reflection.rb', line 113 def qualified_name_of(constant) name = name_of(constant) return if name.nil? if name.start_with?("::") name else "::#{name}" end end |
#resolve_loc(locations) ⇒ Object
Examines the call stack to identify the closest location where a “require” is performed by searching for the label “<top (required)>” or “block in <class:…>” in the case of an ActiveSupport.on_load hook. If none is found, it returns the location labeled “<main>”, which is the original call site. : (Array? locations) -> SourceLocation?
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/tapioca/runtime/reflection.rb', line 186 def resolve_loc(locations) return unless locations # Find the location of the closest file load, which should give us the location of the file that # triggered the definition. resolved_loc = locations.find do |loc| label = loc.label next unless label REQUIRED_FROM_LABELS.include?(label) || label.start_with?("block in <class:") end return unless resolved_loc resolved_loc_path = resolved_loc.absolute_path || resolved_loc.path # Find the location of the last frame in this file to get the most accurate line number. resolved_loc = locations.find { |loc| loc.absolute_path == resolved_loc_path } return unless resolved_loc # If the last operation was a `require`, and we have no more frames, # we are probably dealing with a C-method. return if locations.first&.label == "require" file = resolved_loc.absolute_path || resolved_loc.path || "" SourceLocation.from_loc([file, resolved_loc.lineno]) end |
#sealed_module?(constant) ⇒ Boolean
: (T::Module constant) -> bool
233 234 235 |
# File 'lib/tapioca/runtime/reflection.rb', line 233 def sealed_module?(constant) T::Private::Sealed.sealed_module?(constant) end |
#signature_of(method) ⇒ Object
: ((UnboundMethod | Method) method) -> untyped
134 135 136 137 138 |
# File 'lib/tapioca/runtime/reflection.rb', line 134 def signature_of(method) signature_of!(method) rescue SignatureBlockError nil end |
#signature_of!(method) ⇒ Object
: ((UnboundMethod | Method) method) -> untyped
127 128 129 130 131 |
# File 'lib/tapioca/runtime/reflection.rb', line 127 def signature_of!(method) T::Utils.signature_for_method(method) rescue LoadError, StandardError Kernel.raise SignatureBlockError end |
#singleton_class_of(constant) ⇒ Object
58 59 60 |
# File 'lib/tapioca/runtime/reflection.rb', line 58 def singleton_class_of(constant) SINGLETON_CLASS_METHOD.bind_call(constant) end |
#superclass_of(constant) ⇒ Object
68 69 70 |
# File 'lib/tapioca/runtime/reflection.rb', line 68 def superclass_of(constant) SUPERCLASS_METHOD.bind_call(constant) end |