I have a bit of an odd use-case for a Ruby Enumerable, it seems. I am attempting to do something like the following:
result = my_strategies.some_method do |strategy|
strategy.get_result
end
The method some_method is just a placeholder, but is the basis behind the rest of this question.
The enumerable my_strategies contains an ordered list of strategies for retrieving a value from a remote service; a more preferable strategy is run before a less preferable strategy,
Sometimes the more preferable strategy will fail, in a way that retries alone won’t correct. In that case, the strategy will return nil.
I can see a way of doing this by relying on an each block, thusly:
result = nil
my_strategies.each do |strategy|
result = strategy.get_result
if not r.nil?
break
end
end
This seems unnecessarily noisy. I’m wondering if there is a method I can substitute some_method for in my first example; something similar to .any?, but returning the value that caused the block to be true, instead of just returning true.
Alternate approaches to what I am trying to do are also welcome.
EDIT: I originally asked this question because I had tried this block of code:
result = my_strategies.find do |strategy|
strategy.get_result
end
Except that this returned me the strategy that succeeded, instead of the value it returned when it did. I don’t care about which strategy got me the value, I just want to know what the value is.
Your need is very common but unfortunately there is no such abstraction in the core. However, Facets guys identified this gap a long time ago and implemented Enumerable#find_yield (a.k.a Enumerable#map_detect):
Or simply:
result = my_strategies.map_detect(&:get_result). Ruby 2.0 implements lazy enumerables (for early versions use enumerable-lazy) so now we can write: