找到第一个不会引发错误的proc,并获取其返回值

时间:2012-01-08 03:35:43

标签: ruby

场景是这样的:根据输入本身的某些质量,您需要使用几种可能的过程中的一种来处理某些输入。在您尝试将输入发送给每个人之前,您不会提前知道哪些是可行的。

让我们说你有一系列可能的尝试尝试。你想要的是找到第一个没有引发错误的proc,并获得它的返回值,最好是一次通过。如果没有找到proc,则引发错误。

你最好如何在红宝石中做到这一点?

到目前为止,我的回答看起来像下面两个中的一个,但我正在寻找一种更惯用的方式。还有一种将返回值nil视为有效的方法 - 现在这两种方法都将nil视为错误状态。

(1)

ret = nil
array_of_procs.find do |p|
   begin
     ret = p[input]
   rescue
     next
   end
end
raise ArgumentError unless ret

(2)

ret = array_of_procs.inject(nil) do |memo, p|
  memo = p[input] rescue next
  break memo
end
raise ArgumentError unless ret

3 个答案:

答案 0 :(得分:4)

这是我的解决方案,请注意救援修改器拯救了StandardError,我认为没有办法在不进行多行阻止的情况下改变它。

def first_valid_result(procs, input)
  procs.each { |p| return p[input] rescue nil }
  raise ArgumentError
end

这是规范

describe '#first_valid_result' do
  let(:error_proc)  { lambda { |input| raise } }
  let(:procs)       { [error_proc] * 2 }
  let(:input)       { :some_input }

  it "returns the input from the first proc that doesnt raise an error" do
    procs.insert 1, lambda { |input| input }
    first_valid_result(procs, input).should == input
  end

  it "treats nil as a valid return value" do
    procs.insert 1, lambda { |input| nil }
    first_valid_result(procs, input).should be_nil
  end

  it "raises an ArgumentError when no valid proc exists" do
    expect { first_valid_result procs, input }.to raise_error ArgumentError
  end
end

答案 1 :(得分:0)

您可以将代码缩短为:

array_of_procs.find {|p| ret=p[input] rescue StandardError next}; raise ArgumentError("...") unless ret

我想......

答案 2 :(得分:0)

稍微调整Joshua的答案,以便可以在数组本身上调用它,并允许注入“fail”行为:

module ArrayofProcsMethods
  def find_call(*args)
    self.each { |p| return p[*args] rescue nil }
    block_given? ? yield : raise(ArgumentError, "No valid proc found")
  end
end

array_of_procs.extend(ArrayofProcsMethods)
array_of_procs.find_call(input) 
array_of_procs.find_call(input) { default_value }
array_of_procs.find_call(input) { raise ProcNotFoundCustomError }