有没有办法确定是哪个对象调用了一个方法?

25
我希望Ruby的消息传递基础设施意味着可能会有一些聪明的技巧来解决这个问题。 我该如何确定调用对象——即调用当前方法的对象是什么?
5个回答

16

你可以通过以下方法轻松查看调用感兴趣函数的代码行:

caller.first

这将告诉您调用相关函数的文件名和行号。然后,您可以反向计算出是哪个对象。

然而,看起来你更想知道调用某个函数的对象,可能是在一个实例方法内部。我不知道有没有一种方法来解决这个问题 - 但我不会使用它,因为它似乎严重违反了封装性原则。


1
这是一个非常好的观点,我将只传递调用对象。这个想法是通过自动反映一些关于调用对象的信息来简化某些方法的参数。 - Joseph Weissman
1
最好的情况是,如果它不止一次使用,应该将其作为超类中的一个方法,并且可以使用 self - Peter

8
作为一种选择,有一个binding_of_caller gem可以让你在调用栈上的任何调用者的上下文中执行代码(调用者、调用者的调用者等)。它在开发中用于检查(读取在调用栈上的任何位置执行任何操作)调用栈,如在better_errors中使用。

Binding类的对象封装了代码中某个特定位置的执行上下文,并保留此上下文以供将来使用。

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

我应该提到,这种技术仅应用于调试、娱乐或教育目的,因为它严重违反了面向对象编程原则。
主要是因为eval
让我们准备好东西:
require 'binding_of_caller' # I assume, you installed this gem already?

获取立即(在堆栈上最接近的,因此是0)调用方实例:
binding.of_caller(0).eval('self')

...或者甚至是一个立即调用的方法:

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

如果您需要获取更高层次的调用堆栈,请使用除0以外的数字来获取调用者的绑定。

非常的hacky。但是如果您真的需要这个,那就用吧。


3

科技的最高水平:

 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>'"]

注意:示例行号。 phone.rb:X 指的是脚本的第X行。

看看 phone.rb:13!这个 dial 方法才是发起电话呼叫的方法!而 phone.rb:22 则指向使用了 dial 方法的鲁莽驾驶者!


1

Peter的答案在生产代码示例中使用

在我们公司中,我们正在废弃deleted标志,改用Paranoia gemdeleted_at列。下面的代码是我们如何确保在删除列之前一切都会顺利进行(部署此代码,然后在实时状态下经过2或3天后,我们部署迁移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

1
你的意思是像 self 这样吗?
irb> class Object
  ..   def test
  ..     self
  ..   end
  .. end
  => nil
irb> o = Object.new
  => #<Object:0xb76c5b6c>
irb> o.test
  => #<Object:0xb76c5b6c>

21
兄弟,那看起来就像一个风格化的Z,太棒了! - Pierreten
我看到你的 test() 函数中的问题,OP 想要获取在 irb 中输入 self 后得到的对象。 - lulalala

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接