动态替换Ruby中对象的方法实现

前端之家收集整理的这篇文章主要介绍了动态替换Ruby中对象的方法实现前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我想用一个用户指定的块替换对象的方法的实现.在 JavaScript中,这很容易实现:
  1. function Foo() {
  2. this.bar = function(x) { console.log(x) }
  3. }
  4. foo = new Foo()
  5. foo.bar("baz")
  6. foo.bar = function(x) { console.error(x) }
  7. foo.bar("baz")

在C#中它也很容易

  1. class Foo
  2. {
  3. public Action<string> Bar { get; set; }
  4. public Foo()
  5. {
  6. Bar = x => Console.WriteLine(x);
  7. }
  8. }
  9.  
  10. var foo = Foo.new();
  11. foo.Bar("baz");
  12. foo.Bar = x => Console.Error.WriteLine(x);
  13. foo.Bar("baz");

但是我怎么能在Ruby中做同样的事情呢?我有一个解决方案,将lambda存储在一个实例变量中,该方法调用lambda,但我真的不喜欢开销和语法

  1. class Foo
  2. def initialize
  3. @bar = lambda {|x| puts x}
  4. end
  5.  
  6. def bar x
  7. @bar.call x
  8. end
  9.  
  10. def bar= blk
  11. @bar = blk
  12. end
  13. end
  14.  
  15. foo = Foo.new
  16. foo.bar "baz"
  17. foo.bar= lambda {|x| puts "*" + x.to_s}
  18. foo.bar "baz"

我想要这样的语法:

  1. foo.bar do |x|
  2. puts "*" + x.to_s
  3. end
  4. foo.bar "baz"

我想出了以下代码

  1. class Foo
  2. def bar x = nil,&blk
  3. if (block_given?)
  4. @bar = blk
  5. elsif (@bar.nil?)
  6. puts x
  7. else
  8. @bar.call x
  9. end
  10. end
  11. end

但是这对于多个参数来说有点难看,但仍然感觉不对.我也可以定义一个set_bar方法,但我不喜欢这样:).

  1. class Foo
  2. def bar x
  3. if (@bar.nil?)
  4. puts x
  5. else
  6. @bar.call x
  7. end
  8. end
  9.  
  10. def set_bar &blk
  11. @bar = blk
  12. end
  13. end

所以问题是:有没有更好的方法来做到这一点,如果没有,你更喜欢什么方式

编辑:
@ welldan97的方法有效,但我松散了局部变量范围,即

  1. prefix = "*"
  2. def foo.bar x
  3. puts prefix + x.to_s
  4. end

不起作用.我想我必须坚持使用lambda才能工作?

解决方法

使用def:
  1. foo = Foo.new
  2. foo.bar "baz"
  3.  
  4. def foo.bar x
  5. puts "*" + x.to_s
  6. end
  7.  
  8. foo.bar "baz"

是的,那么简单

编辑:为了不松开范围,您可以使用define_singleton_method(如@freemanoid答案):

  1. prefix = "*"
  2.  
  3. foo.define_singleton_method(:bar) do |x|
  4. puts prefix + x.to_s
  5. end
  6.  
  7. foo.bar 'baz'

猜你在找的Ruby相关文章