在Ruby中动态替换对象上的方法实现 [英] Dynamically replace method implementation on an object in Ruby
问题描述
我想用用户指定的块替换对象的方法实现.在JavaScript中,这很容易实现:
I'd like to replace the implementation of a method for an object with a block that the user specifies. In JavaScript, this is easily accomplished:
function Foo() {
this.bar = function(x) { console.log(x) }
}
foo = new Foo()
foo.bar("baz")
foo.bar = function(x) { console.error(x) }
foo.bar("baz")
在C#中也很容易
class Foo
{
public Action<string> Bar { get; set; }
public Foo()
{
Bar = x => Console.WriteLine(x);
}
}
var foo = Foo.new();
foo.Bar("baz");
foo.Bar = x => Console.Error.WriteLine(x);
foo.Bar("baz");
但是我该如何在Ruby中做同样的事情?我有一个解决方案,将lambda存储在实例变量中,该方法调用lambda,但我真的不喜欢开销和语法
But how can I do the same in Ruby? I have a solution that stores a lambda in an instance variable and the method calls the lambda, but I don't really like the overhead and syntax
class Foo
def initialize
@bar = lambda {|x| puts x}
end
def bar x
@bar.call x
end
def bar= blk
@bar = blk
end
end
foo = Foo.new
foo.bar "baz"
foo.bar= lambda {|x| puts "*" + x.to_s}
foo.bar "baz"
我想要这样的语法:
foo.bar do |x|
puts "*" + x.to_s
end
foo.bar "baz"
我想出了以下代码
class Foo
def bar x = nil, &blk
if (block_given?)
@bar = blk
elsif (@bar.nil?)
puts x
else
@bar.call x
end
end
end
但是,对于多个参数来说,这有点丑陋,但仍然感觉不到正确".我也可以定义set_bar方法,但我也不喜欢:).
But this is kinda ugly for more than one parameter and still doesn't feel 'right'. I could also define a set_bar method, but i don't like that either :).
class Foo
def bar x
if (@bar.nil?)
puts x
else
@bar.call x
end
end
def set_bar &blk
@bar = blk
end
end
问题是:有没有更好的方法可以做到这一点?如果没有,您会选择哪种方式
So question is: Is there a better way do to do this and if not, what way would you prefer
@ welldan97的方法有效,但是我松开了局部变量范围,即
@welldan97's approach works, but i loose the local variable scope, i.e.
prefix = "*"
def foo.bar x
puts prefix + x.to_s
end
不起作用.我想我必须坚持使用lambda才能起作用?
doesn't work. I suppose I have to stick with lambda for that to work?
推荐答案
使用def
:
foo = Foo.new
foo.bar "baz"
def foo.bar x
puts "*" + x.to_s
end
foo.bar "baz"
是的,很简单
要不松开范围,可以使用define_singleton_method
(如@freemanoid答案中所示):
To not loose the scope you can use define_singleton_method
(as in @freemanoid answer):
prefix = "*"
foo.define_singleton_method(:bar) do |x|
puts prefix + x.to_s
end
foo.bar 'baz'
这篇关于在Ruby中动态替换对象上的方法实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!