188

is there a way in Ruby to find the calling method name inside of a method?

For example:

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

8 Answers 8

240
puts caller[0] 

or perhaps...

puts caller[0][/`.*'/][1..-2] 
Sign up to request clarification or add additional context in comments.

5 Comments

That gives the name of the calling method, but it doesn't give any indication to which module or class the method belongs to. Is that possible?
@thomthom Yes that is possible you can call self.class.name to see the class name
Excellent use of regex as a string index! Can also use caller[0][/`(.*)'/,1]
This doesn't seem to work in Rails 5.2.1. In Rails controller this returns "block in make_lambda". I guess this is for Ruby only.
196

In Ruby 2.0.0, you can use:

caller_locations(1,1)[0].label 

It's much faster than the Ruby 1.8+ solution:

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

Will get included in backports when I get the time (or a pull request!).

5 Comments

It's worth noting that this is not available in Rubinius.
if ur using pry, you have to ignore the pry stacktrace it seems...there doesn't seem to be a default solution for that.
Now it seems to be caller_locations[0].label on Ruby 2.2.0 else you always have send_action result
how can we get only call app method and ignore frameworks call ?
Be aware: for Ruby >= 3.4 it's base_label now, because label has class name in it.
41

Use caller_locations(1,1)[0].label (for ruby >= 2.0)

Edit: My answer was saying to use __method__ but I was wrong, it returns the current method name.

4 Comments

@OswaldoFerreira Thanks, found it on SO in another answer somewhere
This is incorrect, it returns current method, not the method that called the current method...
works like a charm. Also seem to be much faster than pre 2.0 methods.
Be aware: for Ruby >= 3.4 it's base_label now, because label has class name in it.
21

I use

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

4 Comments

What's the advantage of this over DigitalRoss' approach?
Cleaner and more precise. Rather than doing the search, then using an array method to split of unwanted characters based on position (which could be incorrect).
Why not simply use caller[0][/`(.*)'/, 1] ? I'm not a guru about regular expressions, but it seems to work.
@collimarco As long as the String doesn't contain a ' beyond the one you're looking for (and I assume it can't), the result will be the same, sure. However, [^']* will perform better as the regex engine will stop trying to match that part the expression the moment it reaches a ' (your version will go to the end, then backtrack because it didn't find a ' at the end). The difference is pretty negligible in this case of course, but it's a good habit to avoid . in regexes where possible.
4

How about

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

Much cleaner imo.

Comments

4

Instead you can write it as library function and make a call wherever needed. The code goes as follows :

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 

To trigger the above module method you need to call like this: caller = CallChain.caller_method

code reference from

3 Comments

A link to a potential solution is always welcome, but please add context around the link so your fellow users will have some idea what it is and why it’s there. Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline. Take into account that being barely more than a link to an external site is a possible reason as to Why and how are some answers deleted?.
@XaviLópez have updated the answer, plz rectify if am doing wrong or somthing mistaken...thnx for the kind suggestion :)
Thanks for improving your answer. Unfortunately, I don't have enough knowledge about Ruby to be able to properly comment about this post, but the answer looks alright now. I've removed my downvote. Best luck :-)
1

The answer from @amitkarsale works, but private does not do anything in a module since modules are not instantiated. Here is call_chain.rb, rewritten according to Rubocop's suggestions:

module CallChain def self.caller_method(depth = 1) parse_caller(caller(depth + 1).first).last end def self.parse_caller(at) return unless /^(.+?):(\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 if __FILE__ == $PROGRAM_NAME caller = CallChain.caller_method puts caller end 

Comments

0

In order to see the caller and callee information in any language, whether it be ruby or java or python, you would always want to look at the stack trace. In some languages, such as Rust and C++, there are options built into the compiler to turn on some sort of profiling mechanism you can view during run time. I do belive one exists for Ruby called ruby-prof.

And as mentioned above, you could look into the execution stack for ruby. This execution stack is an array containing backtrace location objects.

Essentially all you need to know about this command is as follows:

caller(start=1, length=nil) → array or nil

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.