9

为措辞不佳的问题标题道歉 - 不知道如何更好地表达!

在下面的代码中,当我执行时ruby bar.rb,我怎样才能让它输出bar.rb,而不是foo.rb

foo.rb

module Foo
  def filename
    __FILE__
  end
end

bar.rb

require_relative 'foo'
include Foo

puts filename # outputs 'foo.rb'

这是一个库函数,每次执行某些代码时,都会记录该代码的位置(和 git ref)。

4

2 回答 2

4

您的问题促使我打开 Ruby 解释器源代码,看看__FILE__实际是如何工作的。答案很有趣:它是在解析器内部实现的。词法分析器有一个特殊的标记类型__FILE__。当解析器看到该标记时,它将其转换为字符串常量,其中包含解析器正在处理的文件的名称。

从 ext/ripper/ripper.c 的第 14948 行开始:

case keyword__FILE__:
return NEW_STR(rb_external_str_new_with_enc(ruby_sourcefile, strlen(ruby_sourcefile),
                        rb_filesystem_encoding()));

我认为这应该清楚地表明,尝试__FILE__返回包含文件的名称是完全不可能的,除非您破解 Ruby 解释器源代码,或者编写自己的预处理器,__FILE__在将 Ruby 源代码传递给解释器之前转换为其他东西!

于 2012-10-15T15:05:28.760 回答
1

您可能会使用一个技巧。如果将块传递给方法,则可以使用块闭包来确定它的来源。就像是:

def filename(&blk)
  blk.eval "__FILE__"
end

但同样,这意味着你必须通过一个街区。

老实说,我想知道您要完成什么,在制作一些常见的核心扩展方法之外的 b/c,这可能是您真正不想做的事情。

于 2012-10-21T12:36:26.143 回答