有没有办法“打开”使用Proc.new或Kernel.proc实例化的Proc的严格执行,这样它的行为就像用lambda实例化的Proc?
我的初始化方法采用块和操作并将其分配给实例变量.我希望动作严格执行arity,所以当我稍后向它应用参数时,它会引发一个ArgumentError,我可以挽救并引发一个更有意义的异常.基本上:
class Command attr_reader :name,:action def initialize(name,&action) @name = name @action = action end def perform(*args) begin action.call(*args) rescue ArgumentError raise(WrongArity.new(args.size)) end end end class WrongArity < StandardError; end
不幸的是,默认情况下,操作不会强制执行arity:
c = Command.new('second_argument') { |_,y| y } c.perform(1) # => nil
action.to_proc不起作用,也不起作用(& action).
还有其他想法吗?或者更好地解决问题?
谢谢!
解决方法
你的@action将是一个Proc实例,Procs有一个
arity
方法,所以你可以检查该块应该有多少个参数:
def perform(*args) if args.size != @action.arity raise WrongArity.new(args.size) end @action.call(*args) end
那应该照顾像{| a |这样的无拼接块……}和{| a,b | ……}但是随着splats事情有点复杂.如果您有像{| * a |这样的块…}然后@ action.arity将为-1和{| a,* b | ……}会给你一个-2的智商.具有arity -1的块可以使用任意数量的参数(包括无参数),具有arity -2的块至少需要一个参数但可以使用更多参数,依此类推. splatless测试的简单修改应该照顾splatful块:
def perform(*args) if @action.arity >= 0 && args.size != @action.arity raise WrongArity.new(args.size) elsif @action.arity < 0 && args.size < -(@action.arity + 1) raise WrongArity.new(args.size) end @action.call(*args) end