【问题标题】:Any way to determine which object called a method?有什么方法可以确定哪个对象称为方法?
【发布时间】:2010-04-24 03:43:24
【问题描述】:

我希望 Ruby 的消息传递基础架构意味着可能有一些巧妙的技巧。

如何确定调用对象——哪个对象调用了我当前所在的方法?

【问题讨论】:

    标签: ruby messaging introspection dynamic-languages


    【解决方案1】:

    通过

    你可以轻松查看调用感兴趣函数的代码行
    caller.first
    

    它会告诉你调用相关函数的文件名和行号。然后你可以反算它是哪个对象。

    但是,听起来您更喜欢调用某个函数的对象,可能是在实例方法中。我不知道有什么方法可以解决这个问题 - 但无论如何我都不会使用它,因为它似乎严重违反了封装。

    【讨论】:

    • 这是一个非常好的观点,我将只传递调用对象。这个想法是通过自动反映有关调用对象的一些信息来简化方法的一些参数。
    • 嗯,理想情况下,如果不止一次,应该是超类中的方法,可以使用self
    【解决方案2】:

    作为一个选项,有一个binding_of_caller gem 允许您在调用堆栈上的任何调用者(调用者、调用者的调用者等)的上下文中执行代码。它对于在开发中检查(读取在调用堆栈上的任何位置执行任何操作)调用堆栈很有用,如better_errors 中所使用的那样。

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

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

    我应该提一下,这种技术只能用于调试、娱乐或教育目的,因为它严重违反了 OOP 原则。
    主要是因为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 以外的数字来获取调用者的绑定。

    太老套了。但如果你真的需要这个 - 那就去吧。

    【讨论】:

      【解决方案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方法的鲁莽司机!

      【讨论】:

        【解决方案4】:

        你的意思是self

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

        【讨论】:

        • ++ 伙计,这简直太棒了,它看起来像一个程式化的 Z
        • 我读到你的test() OP 想要获取你得到的对象,如果你在irb 中输入self
        【解决方案5】:

        Peter 的answer 用于生产代码示例

        在我的公司中,我们在 Paranoia gem deleted_at 列的风格中弃用了 deleted 标志。下面的代码是我们在删除列之前如何确保一切顺利(部署此代码,然后在上线 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
        

        【讨论】:

          猜你喜欢
          • 2018-11-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-26
          • 1970-01-01
          • 2020-11-27
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多