呼び出しメソッドの名前を取得するにはどうすればよいですか?


161

Rubyの中でメソッド内の呼び出しメソッド名を見つける方法はありますか?

例えば:

class Test
  def self.foo
    Fooz.bar
  end
end

class Fooz
  def self.bar
    # get Test.foo or foo
  end
end



「Rubyで現在実行されているメソッドの名前を取得する」の複製ではありません。この質問は、現在のメソッドの名前ではなく、呼び出しメソッドの名前を尋ねます。
ウェインコンラッド

回答:


210
puts caller[0]

多分...

puts caller[0][/`.*'/][1..-2]


10
これにより、呼び出しメソッドの名前がわかりますが、メソッドがどのモジュールまたはクラスに属しているかはわかりません。それは可能ですか?
thomthom

@thomthomはい、可能です。self.class.nameを呼び出してクラス名を確認できます
Thorin

文字列インデックスとしての正規表現の優れた使用法!使用可能caller[0][/`(.*)'/,1]
aks

1
これはRails 5.2.1では機能しないようです。Railsコントローラでは、これはを返します"block in make_lambda"。これはRuby専用だと思います。
dcangulo 2018年

164

Ruby 2.0.0では、以下を使用できます。

caller_locations(1,1)[0].label

それはですはるかに高速ルビー1.8+ソリューションより:

caller[0][/`([^']*)'/, 1]

backports時間(またはプルリクエスト!)を取得したときに含まれます。


これはRubiniusでは利用できないことに注意してください。
最大

1
pryを使用している場合は、pryスタックトレースを無視する必要があるようです...そのためのデフォルトのソリューションではないようです。
dtc 2015

6
今それはcaller_locations[0].labelRuby 2.2.0上にあるようですそれ以外の場合は常にsend_action結果があります
brcebn

1
アプリメソッドの呼び出しのみを取得し、フレームワークの呼び出しを無視するにはどうすればよいですか?
マトリックス

31

使用する caller_locations(1,1)[0].label(ルビ> = 2.0の場合)

編集:私の答えは使用するように言っていました__method__が、私は間違っていました、それは現在のメソッド名を返します。


1
@OswaldoFerreiraおかげで、SOの別の回答のどこかで見つけました
Dorian

5
これは不正解です。現在のメソッドを呼び出したメソッドではなく、現在のメソッドを返します...
thrice801

1
魅力のように動作します。また、2.0以前の方法よりもはるかに高速であるように見えます。
Dr.Strangelove

21

私が使う

caller[0][/`([^']*)'/, 1]

4
DigitalRossのアプローチに対するこれの利点は何ですか?
Andrew Grimm

2
よりクリーンで正確。検索を行うのではなく、配列メソッドを使用して、位置に基づいて不要な文字を分割します(これは正しくない可能性があります)。
新しいアレクサンドリア

2
単にcaller [0] [/ `(。*) '/、1]を使用しないのはなぜですか?私は正規表現の第一人者ではありませんが、動作するようです。
collimarco

7
@collimarco文字列が'あなたが探しているものを超えていない限り(そして私はそれができないと思います)、結果は確かに同じになります。ただし、[^']*正規表現エンジンはaに達した瞬間にその部分と式を一致させようとするのをやめるので、パフォーマンスは向上し'ます(バージョンが最後に移動し、最後にaが見つからなかったためバックトラックします')。もちろん、この場合の違いはごくわずかですが.、可能な場合は正規表現で回避することをお勧めします。
Thor84no

4

いかがですか

caller[0].split("`").pop.gsub("'", "")

はるかにきれいなイモ。


3

代わりに、それをライブラリー関数として記述し、必要な場所に呼び出しを行うことができます。コードは次のようになります。

module CallChain
  def self.caller_method(depth=1)
    parse_caller(caller(depth+1).first).last
  end

  private

  # Copied from ActionMailer
  def self.parse_caller(at)
    if /^(.+?):(\d+)(?::in `(.*)')?/ =~ at
      file   = Regexp.last_match[1]
      line   = Regexp.last_match[2].to_i
      method = Regexp.last_match[3]
      [file, line, method]
    end
  end
end

上記のモジュールメソッドをトリガーするには、次のように呼び出す必要があります。 caller = CallChain.caller_method

からのコード参照


1
可能性のあるソリューションへのリンクはいつでも歓迎しますが、リンクの前後にコンテキスト追加して、他のユーザーがそれが何であるか、なぜそこにあるのかを理解できるようにしてください。ターゲットサイトに到達できない、または永久にオフラインになる場合に備えて、常に重要なリンクの最も関連性の高い部分を引用してください。外部サイトへのリンク以上のものであることが、なぜ、どのようにしていくつかの回答が削除されるのかについて考えられる理由であることを考慮に入れてください
XaviLópez14年

@XaviLópezが回答を更新しました。間違っているか何か間違っているかを修正します...種類の提案のためのthnx :)
amit karsale

1
回答を改善していただきありがとうございます。残念ながら、私はRubyについてこの投稿について適切にコメントできるほどの知識がありませんが、答えは今は大丈夫です。反対票を削除しました。幸運:-)
XaviLópez

2

ruby、java、pythonのいずれの言語でも、呼び出し元と呼び出し先の情報を任意の言語で表示するには、常にスタックトレースを確認する必要があります。RustやC ++などの一部の言語では、実行時に表示できるある種のプロファイリングメカニズムを有効にするオプションがコンパイラに組み込まれています。Rubyにはruby-profと呼ばれるものがあると思います。

上記のように、ルビの実行スタックを調べることができます。この実行スタックは、バックトレースロケーションオブジェクトを含む配列です。

基本的に、このコマンドについて知っておく必要があるのは次のとおりです。

caller(start = 1、length = nil)→配列またはnil

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.