Ruby 写了个新玩具 Ruby method decorators (类似 Python)

fredwu · 2012年09月12日 · 最后由 fredwu 回复于 2012年09月12日 · 3400 次阅读

欢迎来把玩: :D https://github.com/fredwu/ruby_decorators

凌晨 3 点了,累死了,睡觉了睡觉了……

感觉跟 python 的 decorator 差异很大。python 里面用 class 来实现 decorator 的话,__call__方法的参数是 funtion 类型,返回另一个 function。这里的 call 方法的 this 参数,是所 decorate 的方法的返回值吧?对返回值进行修改,倒跟 golang 里用 defer 修改返回值类似。python 的 decorator 可以对方法/函数进行重新定义,而且可以引用到原方法/函数,不是修改返回值

比如这样一个 python 的 decorator

def double_arguments(func):                                      
  def f(*args):                                                  
    return func(*[x * 2 for x in args])                          
  return f                                                       

@double_arguments                                                
def add(a, b, c):                                                
  return a + b + c                                               

@double_arguments                                                
def mul(a, b, c):                                                
  return a * b * c                                               

print add(1, 2, 3) # => 12                                       
print mul(1, 2, 3) # => 48                                       

double_arguments 会修改 add 和 mul 的定义,使传递给他们的参数都先乘以 2,再传递给原函数 如果 decorator 只能改变返回值,那是实现不了这个效果的 decorator 的实现里面,不仅可以引用到原先定义的函数/方法,也可以引用到实际调用时的参数 所以 ruby 可能可以写成这样?

class Batman < RubyDecorator
  def call(func)
    lambda {|*args|
      func(*args).sub('world', 'batman')
    }
  end
end

#3 楼 @reus 啊,非常感谢!

我更新了一下,现在 decorator 的第一个参数是原函数,而非返回值了。:)

class Batman < RubyDecorator
  def call(this, *args, &blk)
    this.call(*args, &blk).sub('world', 'batman')
  end
end

如果 decorator 返回的是 callable object,还可以实现多重 decorate,比如 python 的

@double_arguments
@double_arguments
@double_arguments
def foo(a, b):
  return a + b

print foo(1, 2) # => 24 八倍参数             

相当于

def foo(a, b):
  return a + b

foo = double_arguments(double_arguments(double_arguments(foo)))

#5 楼 @reus 嗯,接下来我要测试/实现的就是多重 decorator。:)

需要 登录 后方可回复, 如果你还没有账号请 注册新账号