Apologies for the poorly worded question title - no idea how to put it better!
In the following code, when I execute ruby bar.rb
, how can I make it output bar.rb
, rather than foo.rb
?
In foo.rb
:
module Foo
def filename
__FILE__
end
end
In bar.rb
:
require_relative 'foo'
include Foo
puts filename # outputs 'foo.rb'
This is for a library function that, each time some code is executed, records the location (and git ref) of that code.
Your question stimulated me to crack open the Ruby interpreter source and see how __FILE__
actually works. The answer is pretty interesting: it's implemented right inside the parser. The lexer has a special token type for __FILE__
. When the parser sees that token, it converts it to a string constant, which contains the name of the file the parser is working on.
From line 14948 of ext/ripper/ripper.c:
case keyword__FILE__:
return NEW_STR(rb_external_str_new_with_enc(ruby_sourcefile, strlen(ruby_sourcefile),
rb_filesystem_encoding()));
I think this should make it clear that trying to make __FILE__
return the name of the including file is completely impossible, unless you hack the Ruby interpreter source, or write your own preprocessor which transforms __FILE__
to something else before passing the Ruby source to the interpreter!
There is a trick you might be a able to use. If you pass a block to the method you could use the blocks closure to determine it's source. Something like:
def filename(&blk)
blk.eval "__FILE__"
end
But again, that means you have to pass a block.
Honestly I wonder what you are trying to accomplish, b/c outside of make some common core extension method, this is probably something you really don't want to do.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With