有什么方法可以确定哪个对象调用了方法?

发布于 2024-08-30 02:23:16 字数 74 浏览 6 评论 0原文

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

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

笙痞 2024-09-06 02:23:16

您可以轻松查看调用感兴趣函数的代码行,通过

caller.first

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

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

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.

孤云独去闲 2024-09-06 02:23:16

作为一个选项,有一个 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 以外的数字来获取调用者的绑定。

非常哈克。但如果你真的需要这个——就可以了。

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.

年华零落成诗 2024-09-06 02:23:16

最佳技术:

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

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!

终止放荡 2024-09-06 02:23:16

你的意思是像self

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

You mean like self?

irb> class Object
  ..   def test
  ..     self
  ..   end
  .. end
  => nil
irb> o = Object.new
  => #<Object:0xb76c5b6c>
irb> o.test
  => #<Object:0xb76c5b6c>
雪落纷纷 2024-09-06 02:23:16

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

在我的公司中,我们不推荐使用 deleted 标志,其风格为 < href="https://github.com/rubysherpas/paranoia" rel="nofollow noreferrer">Paranoia gem deleted_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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文