2013-11-01 51 views
2

有一个,通常列调用命名参数方法,它看起来像这样干燥参数检查

def foo(x = nil, y = nil) 
    fail ArgumentError, "x must be present" unless x 
    fail ArgumentError, "y must be present" unless y 
    # do stuff with x and y 
end 

我想重写,就像这样

def foo(x = nil, y = nil) 
    required_arguments :x, :y 
    # do stuff with x and y 
end 

class Foo 
    required_arguments :bar, :x, :y 

    def bar(x = nil, y = nil) 
    end 
end 

我已经试图用alias_method_chain实施第二种方法,但问题是__method__在我的公用程序模块的上下文中进行评估,因此无法访问我需要检查的方法的参数。有任何想法吗?

+1

如果'x'和'y' **必须**,则不要为它们提供默认值。易如反掌。 –

+0

不幸的是,使用当前Ruby版本 – synapse

+0

命名参数需要缺省值啊,忘记了。 –

回答

0

value of such run-time assertions is limited,但他们确实有用。我已将它们并入YSupport。在命令行中键入gem install y_support,并按如下

require 'y_support/typing' 

def foo x=nil, y=nil 
    x.aT; y.aT 
    # do stuff with x and y 
end 

助记符使用它:在0​​,a的意思是“断言”和TTypeError - 提高TypeError如果断言失败。如果#aT方法在没有参数的情况下被调用,它只是强制接收方必须是truey。如果提供了一个块,则可以写入任何断言。例如,下面的呼叫强制接收器由3整除:

6.aT { |n| n % 3 == 0 } #=> 6 
7.aT { |n| n % 3 == 0 } #=> TypeError: 7:fixnum fails its check! 

在检查所述方法参数的情况下,ArgumentError是适当时,有的参数和类似的问题错误号码。当参数类型错误时,我更愿意提出TypeError。可以使用两个字符串参数自定义#aT方法的错误消息。第一个描述接收器,第二个描述块断言。例如:

7.aT "number of apples", "be divisible by three" do |n| n % 3 == 0 end 
#=> TypeError: Number of apples fails to be divisible by three! 

#aT方法,如果通过,返回其接收器,因此断言可以被链接:

81.aT("no. of apples", "divisible by 3) { |n| 
    n % 3 == 0 
}.aT("no. of apples", "be a square") { |n| 
    root = n ** 0.5; root == root.floor 
} ** 0.5 #=> 9.0 

其它更专门的运行时断言是可用在YSupport,如:

[ 1, 2, 3 ].aT_kind_of Enumerable #=> [ 1, 2, 3 ] 
:foobar.aT_respond_to :each 
#=> TypeError: Foobar:symbol does not respond to method 'each'! 
:foobar.aT_respond_to :each, "object returned from the black box" 
#=> TypeError: Object returned from the black box does not respond to method 'each'! 
7.aT_equal 8 
#=> TypeError: 7:fixnum must be equal to the prescribed value (8:fixnum)! 

可以在YSupport查找更多的这些方法自己,如果你错过了什么,欢迎您来贡献它。

作为邮政Scriptum这个职位,如果你习惯于ActiveSupport#present?方法,YSupport运行时断言它是:

[].aT_present "supplied array" 
#=> TypeError: Supplied array not present! 
+0

看起来非常酷,但我宁可不猴子补丁'对象'。不管怎么说,还是要谢谢你。 – synapse

+0

我在改进之前写了它。但是,无论如何,以'aE'开头的方法名在正则编码中非常罕见,因此它不会混淆名称。我确实考虑过这些问题,我认为这是一个可以接受的折衷方案。 –

+0

@synapse:另外,猴子补丁类不限于'Object'。 '数组'具有例如。 '强制对象存在的数组#aT_includes',强制数组对象唯一性的'Array#aT_uniq' ...'Hash'具有'Hash#aE_has',它通过'ArgumentError'强制所讨论的哈希具有给定的密钥。 .. –

3

如果您使用Ruby 2.0,你可以使用关键字参数:

def foo(x: (fail ArgumentError), y: (fail ArgumentError)) 
    # do stuff with x and y 
end 

而在红宝石2。1你有适当的必需的参数:

def foo(x:, y:) 
    # do stuff with x and y 
end 

这样,你做实际上有一个名为参数(你叫他们在你的问题的命名参数,但是这是一个有点混乱,恕我直言),所以你必须这样调用的方法:

foo(x: 1, y: 2) 
+0

从我+1,我也使用这种技术。然而,有时候,你想做的不仅仅是'失败ArgumentError' ... –