Ruby 中的装饰器(从 Python 迁移)

2024-01-04

我今天从 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块是一个闭包。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Ruby 中的装饰器(从 Python 迁移) 的相关文章

随机推荐