ruby – 我可以对传递给方法的块强制执行arity吗?

有没有办法“打开”使用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

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...