lib/tapioca/runtime/reflection.rb in tapioca-0.8.3 vs lib/tapioca/runtime/reflection.rb in tapioca-0.9.0

- old
+ new

@@ -18,10 +18,12 @@ PUBLIC_INSTANCE_METHODS_METHOD = T.let(Module.instance_method(:public_instance_methods), UnboundMethod) PROTECTED_INSTANCE_METHODS_METHOD = T.let(Module.instance_method(:protected_instance_methods), UnboundMethod) PRIVATE_INSTANCE_METHODS_METHOD = T.let(Module.instance_method(:private_instance_methods), UnboundMethod) METHOD_METHOD = T.let(Kernel.instance_method(:method), UnboundMethod) + REQUIRED_FROM_LABELS = T.let(["<top (required)>", "<main>"].freeze, T::Array[String]) + sig do params( symbol: String, inherit: T::Boolean, namespace: Module @@ -149,9 +151,34 @@ result = ObjectSpace.each_object(klass.singleton_class).reject do |k| T.cast(k, Module).singleton_class? || T.unsafe(k) == klass end T.unsafe(result) + end + + # Examines the call stack to identify the closest location where a "require" is performed + # by searching for the label "<top (required)>". If none is found, it returns the location + # labeled "<main>", which is the original call site. + sig { returns(String) } + def required_from_location + locations = Kernel.caller_locations + return "" unless locations + + required_location = locations.find { |loc| REQUIRED_FROM_LABELS.include?(loc.label) } + return "" unless required_location + + required_location.absolute_path || "" + end + + sig { params(constant: Module).returns(T.nilable(String)) } + def constant_name_from_singleton_class(constant) + constant.to_s.match("#<Class:(.+)>")&.captures&.first + end + + sig { params(constant: Module).returns(T.nilable(BasicObject)) } + def constant_from_singleton_class(constant) + constant_name = constant_name_from_singleton_class(constant) + constantize(constant_name) if constant_name end end end end