【发布时间】:2010-04-24 03:43:24
【问题描述】:
我希望 Ruby 的消息传递基础架构意味着可能有一些巧妙的技巧。
如何确定调用对象——哪个对象调用了我当前所在的方法?
【问题讨论】:
标签: ruby messaging introspection dynamic-languages
我希望 Ruby 的消息传递基础架构意味着可能有一些巧妙的技巧。
如何确定调用对象——哪个对象调用了我当前所在的方法?
【问题讨论】:
标签: ruby messaging introspection dynamic-languages
通过
你可以轻松查看调用感兴趣函数的代码行caller.first
它会告诉你调用相关函数的文件名和行号。然后你可以反算它是哪个对象。
但是,听起来您更喜欢调用某个函数的对象,可能是在实例方法中。我不知道有什么方法可以解决这个问题 - 但无论如何我都不会使用它,因为它似乎严重违反了封装。
【讨论】:
self。
作为一个选项,有一个binding_of_caller gem 允许您在调用堆栈上的任何调用者(调用者、调用者的调用者等)的上下文中执行代码。它对于在开发中检查(读取在调用堆栈上的任何位置执行任何操作)调用堆栈很有用,如better_errors 中所使用的那样。
Binding类的对象将执行上下文封装在代码中的某个特定位置,并保留此上下文以供将来使用。
我应该提一下,这种技术只能用于调试、娱乐或教育目的,因为它严重违反了 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 以外的数字来获取调用者的绑定。
太老套了。但如果你真的需要这个 - 那就去吧。
【讨论】:
最好的技术:
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方法的鲁莽司机!
【讨论】:
你的意思是self?
irb> class Object
.. def test
.. self
.. end
.. end
=> nil
irb> o = Object.new
=> #<Object:0xb76c5b6c>
irb> o.test
=> #<Object:0xb76c5b6c>
【讨论】:
test() OP 想要获取你得到的对象,如果你在irb 中输入self。
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
【讨论】: