我知道有函数“method(:instance_exec).source_location”来查找源代码,但只适用于gems中的代码。
那不是真的。 Method#source_location 适用于不在 gems 中的方法:
module Foo
def bar; end
end
p Foo.instance_method(:bar).source_location
#=> ['test.rb', 2]
这里没有宝石。事实上,如果我根本不使用任何文件,它甚至可以工作,只需在命令行上使用ruby -e;在这种情况下,结果将是 ['-e', 2]。
另一方面,如果没有 Ruby 源代码,那么它会返回 nil 即使对于 gems。
Method#source_location 的返回值与方法是否来自 gem 无关,唯一重要的是是否有 Ruby 源可以定位。 p>
但在这种特殊情况下它返回 null,因为该方法来自原生 ruby。
它不应该返回null,它应该返回一个二元素数组或nil,但绝不应该返回null。如果真的是这样的话,您的 Ruby 安装似乎出现了严重问题。
我在谷歌上搜索,但找不到写在哪里。
它将位于您正在使用的 Ruby 实现的源代码中。你还没有指定你使用的是哪个实现,所以我不能确切地告诉你,但这里有一些例子:
在Rubinius中,在core/basic_object.rb中实现:
def instance_exec(*args, &prc)
raise ::LocalJumpError, "Missing block" unless block_given?
env = prc.block
return prc.ruby_method.call(*args) if prc.ruby_method
lexical_scope = env.lexical_scope
if ::ImmediateValue === self
lexical_scope = lexical_scope.using_disabled_scope
else
sc = ::Rubinius::Type.object_singleton_class(self)
lexical_scope = lexical_scope.using_current_as(sc)
end
return env.call_under(self, lexical_scope, true, *args)
end
在TruffleRuby中,在src/main/java/org/truffleruby/core/basicobject/BasicObjectNodes.java中实现:
@CoreMethod(names = "instance_exec", needsBlock = true, rest = true)
public abstract static class InstanceExecNode extends CoreMethodArrayArgumentsNode {
public static InstanceExecNode create() {
return InstanceExecNodeFactory.create(null);
}
@Child private CallBlockNode callBlockNode = CallBlockNode.create();
abstract Object executeInstanceExec(Object self, Object[] args, RubyProc block);
@Specialization
protected Object instanceExec(Object receiver, Object[] arguments, RubyProc block) {
final DeclarationContext declarationContext = new DeclarationContext(
Visibility.PUBLIC,
new SingletonClassOfSelfDefaultDefinee(receiver),
block.declarationContext.getRefinements());
return callBlockNode
.executeCallBlock(declarationContext, block, receiver, block.block, arguments);
}
@Specialization
protected Object instanceExec(Object receiver, Object[] arguments, NotProvided block) {
throw new RaiseException(getContext(), coreExceptions().localJumpError("no block given", this));
}
}