我正在ruby中的对象中重新定义一个方法,我需要将新方法作为闭包.例如:
def mess_it_up(o)
x = "blah blah"
def o.to_s
puts x # Wrong! x doesn't exists here, a method is not a closure
end
end
Run Code Online (Sandbox Code Playgroud)
现在,如果我定义一个Proc,它就是一个闭包:
def mess_it_up(o)
x = "blah blah"
xp = Proc.new {||
puts x # This works
end
# but how do I set it to o.to_s.
def o.to_s
xp.call # same problem as before
end
end
Run Code Online (Sandbox Code Playgroud)
有什么想法怎么做?
谢谢.
Cha*_*les 23
这工作(在irb中测试):
注意:这仅更改str- 不是所有String实例.请阅读下面的详细信息,了解其工作原理
another_str = "please don't change me!"
str = "ha, try to change my to_s! hahaha!"
proc = Proc.new { "take that, Mr. str!" }
singleton_class = class << str; self; end
singleton_class.send(:define_method, :to_s) do
proc.call
end
puts str.to_s #=> "take that, Mr. str!"
puts another_str.to_s #=> "please don't change me!"
# What! We called String#define_method, right?
puts String #=> String
puts singleton_class #=> #<Class:#<String:0x3c788a0>>
# ... nope! singleton_class is *not* String
# Keep reading if you're curious :)
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为你正在打开str的单例类并在那里定义一个方法.因为这个,以及对Module#define_method的调用,有些人称之为"平坦范围",所以如果你使用的话,你可以访问超出范围的变量def to_s; 'whatever'; end.
你可能想在这里看看其他一些"元编程法术":
media.pragprog.com/titles/ppmetr/spells.pdf
为什么它只会改变str?
因为Ruby有几个有趣的技巧.在Ruby对象模型中,方法调用导致接收者不仅搜索它的类(和它的祖先),而且还搜索它的单例类(或者像Matz所称的那样,它是本征类).这个单例类允许您[重新]定义单个对象的方法.这些方法称为"单例方法".在上面的例子中,我们正在这样做 - 定义一个单例方法名称to_s.它的功能与此相同:
def str.to_s
...
end
Run Code Online (Sandbox Code Playgroud)
唯一的区别是我们在调用时使用闭包Module#define_method,而是def一个关键字,这会导致范围的变化.
为什么它不能更简单?
好吧,好消息是你用Ruby编程,所以随意发疯:
class Object
def define_method(name, &block)
singleton = class << self; self; end
singleton.send(:define_method, name) { |*args| block.call(*args) }
end
end
str = 'test'
str.define_method(:to_s) { "hello" }
str.define_method(:bark) { "woof!" }
str.define_method(:yell) { "AAAH!" }
puts str.to_s #=> hello
puts str.bark #=> woof!
puts str.yell #=> AAAH!
Run Code Online (Sandbox Code Playgroud)
而且,如果你很好奇......
你知道班级方法吗?或者,在某些语言中,我们称之为静态方法?那么,那些不真正存在的红宝石.在Ruby中,类方法实际上只是在Class对象的singleton类中定义的方法.
如果这听起来很疯狂,请看看我上面提供的链接.如果你知道如何进行元编程,那么很多Ruby的功能都只能被挖掘 - 在这种情况下你真的想知道单例类/方法,更一般地说,知道Ruby对象模型.
HTH
- 查尔斯
在Ruby 1.9.2中实现的功能#1082使用Object#define_singleton_method使这变得简单:
def mess_it_up(o)
x = "blah blah"
# Use Object#define_singleton_method to redefine `to_s'
o.define_singleton_method(:to_s) { x }
end
Run Code Online (Sandbox Code Playgroud)
所涉及的概念仍然与我之前的答案相同,后者提供了对Ruby如何在Ruby的对象模型中工作的更深入的描述,以及Object#define_method概念上与Ruby 1.9.2相同的定义Object#define_singleton_method.
您可能会发现对类似任务有用的其他方法:
| 归档时间: |
|
| 查看次数: |
2845 次 |
| 最近记录: |