Find the first proc that does not cause an error and get its return value

The scenario looks something like this: you have an input that you want to process using one of several possible processes, depending on the quality of the input itself. You do not know in advance what will work until you try to send an input for everyone.

Let's say you have many possible attempts to try. You want to find the first proc that does not cause an error and get its return value, preferably in one pass. And if proc is not found, throw an error.

What is the best way to do this in ruby?

My answer so far looks like one of the two below, but I'm looking for a more idiomatic path. And also a way that treats the nil return value as real - right now both of them treat nil as an error state.

(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 
+4
source share
3 answers

Here is my solution, note that the rescue modifier saves StandardError, and I don't think there is a way to change this without going into a multi-line block.

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

And here is the specification

 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 
+4
source

You can shorten your code to:

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

I think...

0
source

The Joshua adaptation will answer a bit so that it can be called in the array itself, and also enable the "fail" behavior in:

 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 } 
0
source

Source: https://habr.com/ru/post/1389864/


All Articles