2012-10-15 23 views
9

貧弱な言葉の質問のタイトルの謝罪 - それをより良いものにする方法はありません!次のコードでインクルードファイルから、インクルードするファイルのファイル名を取得するにはどうすればよいですか?

、私はruby bar.rbを実行すると、どのように私はむしろfoo.rbよりも、bar.rbそれを出力することができますか?

foo.rbにおいて:

module Foo 
    def filename 
    __FILE__ 
    end 
end 

bar.rbにおいて:

require_relative 'foo' 
include Foo 

puts filename # outputs 'foo.rb' 

これはそのコードの(とGitのREF)いくつかのコードが実行されるたびに、位置を記録し、ライブラリ関数のためのものです。

+3

これはまったくハックですが、['caller'](http://www.ruby-doc.org/core-1.9.3/Kernel.html#method-i-caller)メソッドは、途中で。 'def filename;ファイル=呼び出し元[0] .split( ':');ファイル[0];終わり。 – Telemachus

+0

hah :)それが唯一の解決策だったら私は驚かないでしょう。 – seb

+0

かもしれませんが、まだ*地獄のようなハッキーを感じています。そのように出力を解析することはちょうどファウルです。 'caller'は文字列の配列を返し、各文字列の最初の部分はあなたが望むものです。あなたが何をしているかによって、スタック内のどこを見たいかを検討する必要があります。つまり、配列内の最初のエントリが常に必要なわけではありません。 – Telemachus

答えて

4

Rubyインタプリタのソースを開けて、__FILE__が実際にどのように動作するかわかりました。答えはかなり面白いです:それはパーサの内部で実装されています。レクサーには__FILE__の特別なトークンタイプがあります。パーザは、そのトークンを見ると、パーザが処理しているファイルの名前を含む文字列定数に変換します。

EXT /リッパー/ ripper.cのライン14948から

:私は、これはそれを明確にあなたがハックしない限り含むファイルの名前を返す__FILE__にしようとすると、完全に不可能であることを確認すべきだと思う

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

Rubyインタプリタのソースを入手するか、Rubyソースをインタプリタに渡す前に__FILE__を別のものに変換する独自のプリプロセッサを作成してください!

1

あなたが使用できるかもしれないトリックがあります。メソッドにブロックを渡すと、ブロックのクロージャを使用してソースを特定できます。何かのように:

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

もう一度、それはブロックを渡す必要があることを意味します。

正直私はあなたが達成しようとしているものは何か、b/cはいくつかの一般的なコア拡張メソッドを作るのだろうか、これはおそらくあなたがしたくないものです。

関連する問題