Any way to determine which object called a method?

故事扮演 提交于 2020-01-29 02:42:11

问题


I'm hoping that Ruby's message-passing infrastructure means there might be some clever trick for this.

How do I determine the calling object -- which object called the method I'm currently in?


回答1:


As an option, there is a binding_of_caller gem that allows you to execute code in context of any caller on the call stack (caller, caller's caller and so on). It's useful for inspecting (read do anything at any position on the call stack) call stack in development, as used in better_errors.

Objects of class Binding encapsulate the execution context at some particular place in the code and retain this context for future use.

– http://www.ruby-doc.org/core-2.1.4/Binding.html

Should I mention, this technique should only be used for debugging, fun or educational purposes, because it violates principles of OOP really badly.
Mostly because of eval.

Let's prepare stuff:

require 'binding_of_caller' # I assume, you installed this gem already?

Get the immediate (closest on stack, hence 0) caller instance:

binding.of_caller(0).eval('self')

...or even an immediate calling method:

binding.of_caller(0).eval('__method__')

If you need to get higher up the call stack, use numbers other than 0 for getting a caller's binding.

Awfully hacky. But if you really need this — there you go.




回答2:


You can easily look at the line of code that called the function of interest through

caller.first

which will tell you the filename and line number which called the relevant function. You could then back-calculate which object it was.

However, it sounds like you're more after some object that called a certain function, perhaps within an instance method. I'm not aware of a method for figuring this out - but I wouldn't use it anyway, since it seems to violate encapsulation badly.




回答3:


Technology at its finest:

 1  # phone.rb
 2  class Phone
 3    def caller_id
 4      caller
 5    end
 6  end
 7  
 8  class RecklessDriver
 9    def initialize
10      @phone = Phone.new
11    end
12    def dial
13      @phone.caller_id
14    end
15  end
16  
17  p = Phone.new
18  p.caller_id.inspect   # => ["phone.rb:18:in `<main>'"]
19  
20  macek = RecklessDriver.new
22  macek.dial.inspect    # => ["phone.rb:13:in `dial'", "phone.rb:22:in `<main>'"]

Note: Line number for demonstrative purposes. phone.rb:X refers to Line X of the script.

Look at phone.rb:13! This dial method is what sent the call! And phone.rb:22 refers to the reckless driver that used the dial method!




回答4:


You mean like self?

irb> class Object
  ..   def test
  ..     self
  ..   end
  .. end
  => nil
irb> o = Object.new
  => #<Object:0xb76c5b6c>
irb> o.test
  => #<Object:0xb76c5b6c>



回答5:


Peter's answer used in production code example

In my company we were deprecating deleted flag in flavor of Paranoia gem deleted_at column. The code bellow is how we were ensuring all will go well before we remove column (deploying this code and then after 2 or 3 days of being live we deploy migration remoove_column :lessons, :deleted

class Lesson < ActiveRecord::Base

  def deleted
    if caller.select { |c| c.match /serialization\.rb/ }.any?
      # this is Rails object mapping
      !!deleted_at
    else
      raise 'deplicated - deleted was replaced by  deleted_at'
    end
  end
end


来源:https://stackoverflow.com/questions/2703136/any-way-to-determine-which-object-called-a-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!