DRYing参数检查

时间:2013-11-01 07:08:50

标签: ruby

有一种方法通常使用命名参数调用,它看起来像这样

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__,所以我无法访问我需要的方法的参数校验。有什么想法吗?

2 个答案:

答案 0 :(得分:3)

如果您使用ruby 2.0,则可以使用关键字参数:

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

在ruby 2.1中你有适当的必要参数:

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

这样你实际上有了命名参数(你在问题中称它们为命名参数,但这有点令人困惑),所以你必须调用这样的方法:

foo(x: 1, y: 2)

答案 1 :(得分: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

助记符:在aT中,a表示“断言”而T表示TypeError - 如果断言失败则抬起TypeError。如果在没有参数的情况下调用#aT方法,它只会强制接收器必须是真实的。如果提供了块,则可以写入任何断言。例如,以下调用强制接收器可被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中自行查找更多这些方法,如果您遗漏了某些内容,欢迎您提供。

作为本文的帖子脚本,如果您习惯于ActiveSupport的{​​{1}}方法,#present?中的运行时断言是:

YSupport