我今天从 Python 的角度学习 Ruby。我完全没能解决的一件事是装饰器的等价物。为了精简内容,我尝试复制一个简单的 Python 装饰器:
#! /usr/bin/env python
import math
def document(f):
def wrap(x):
print "I am going to square", x
f(x)
return wrap
@document
def square(x):
print math.pow(x, 2)
square(5)
运行这个给我:
I am going to square 5
25.0
因此,我想创建一个函数 square(x)
,但要对其进行装饰,以便它在执行之前提醒我它要对什么进行平方。让我们去掉糖以使其更基本:
...
def square(x):
print math.pow(x, 2)
square = document(square)
...
那么,我该如何在 Ruby 中复制它呢?这是我的第一次尝试:
#! /usr/bin/env ruby
def document(f)
def wrap(x)
puts "I am going to square", x
f(x)
end
return wrap
end
def square(x)
puts x**2
end
square = document(square)
square(5)
运行此生成:
./ruby_decorate.rb:8:in `document': wrong number of arguments (0 for 1) (ArgumentError)
from ./ruby_decorate.rb:15:in `<main>'
我猜这是因为圆括号不是强制性的,它把我的 return wrap
当作 return wrap()
的尝试。我知道没有办法在不调用函数的情况下引用它。
我已经尝试了其他各种方法,但没有什么能让我走得更远。
最佳答案
这是消除别名方法名称之间冲突问题的另一种方法(请注意,我使用模块进行装饰的其他解决方案也是一个不错的选择,因为它也避免了冲突):
module Documenter
def document(func_name)
old_method = instance_method(func_name)
define_method(func_name) do |*args|
puts "about to call #{func_name}(#{args.join(', ')})"
old_method.bind(self).call(*args)
end
end
end
上面的代码之所以有效,是因为 old_method
局部变量在新的“hello”方法中保持有效,因为 define_method
block 是一个闭包。
关于python - Ruby 中的装饰器(从 Python 迁移),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1891429/