本文介绍了Ruby中的装饰器(从Python迁移)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我今天要从Python的角度学习Ruby。我完全无法解决的一件事是等效的装饰器。为了简化工作,我尝试复制一个普通的Python装饰器:

I'm spending today learning Ruby from a Python perspective. One thing I have completely failed to grapple with is an equivalent of decorators. To pare things down I'm trying to replicate a trivial Python decorator:


#! /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),但对其进行装饰,这样它在执行操作之前会提醒我要进行平方的操作。让我们摆脱糖的困扰,使其更加基础:

So, I want to create a function square(x), but decorate it so it alerts me as to what it's going to square before it does it. Let's get rid of the sugar to make it more basic:


...
def square(x):
    print math.pow(x, 2)
square = document(square)
...

所以,如何在Ruby中复制此代码?这是我的第一次尝试:

So, how do I replicate this in Ruby? Here's my first attempt:


#! /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 `'

我想这是因为括号不是强制性的,它把我的换行符尝试返回wrap()。我不知道没有调用它就无法引用该函数。

Which I guess it because parentheses aren't mandatory and it's taking my "return wrap" as an attempt to "return wrap()". I know of no way to refer to a function without calling it.

我尝试了其他各种方法,但没有任何帮助。

I've tried various other things, but nothing gets me far.

推荐答案

这是消除别名方法名称之间冲突的另一种方法(注意,其他使用模块进行装饰的解决方案也是很好的选择,因为它也避免了冲突):

Here's another approach that eliminates the problem with conflicts between names of aliased methods (NOTE my other solution using modules for decoration is a good alternative too as it also avoids conflicts):

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 局部变量在 define_method 块是闭包的事实中保持有效。

The above code works because the old_method local variable is kept alive in the new 'hello' method by fact of define_method block being a closure.

这篇关于Ruby中的装饰器(从Python迁移)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-13 13:17