Enumerable#detect_result?

Actual code from a recent project:

# This is bunk, but I'm tired and can't think of the right way to

do this
# I was trying formats.detect, but that just returns the format,
not the result
result = nil
formats.each do |f|
result = f.process(mesg)
break if result
end

In this context, ‘formats’ is an array of format objects, each of
which represents a format a message can take. The process method takes
in a message, checks it against the format object’s configuration, and
returns either nil (if there was no match) or some useful value.

Thanks to testing, my original concept of

formats.detect { |f|  f.process(mesg) }

was rejected as being wrong. After all, I want the result of the
process call, not the format object. I could go with collect/detect,
but knowing I want the first makes that rather pointless, especially
if processing could be expensive and the array could be long.

Is there anything like Enumerable#detect_result? Is there any desire
for it? Is there any better name?

On Nov 24, 2007 11:12 PM, Yossef M. [email protected] wrote:

end

hmm yeah I also feel the need for something like map_first sometimes,
but there is no such beast.

you can simplify the code above a little bit

formats.each do | f |
result = …
break result if result
end

and if performance is not a problem the following is an alternative

formats.map{ |f| f.process( mesg )}.detect{|x| x}
if x can never be false that can be written as
formats.map{ … }.compact.first or use facets
formats.map_if{ … }.first if there are possible false values.

I do not know a standard or facets built in method that will stop
iterating and return the block’s value, hopefully I am wrong :wink:

HTH
Robert

On Nov 24, 4:12 pm, Yossef M. [email protected] wrote:

Is there anything like Enumerable#detect_result? Is there any desire
for it? Is there any better name?

Would this work?

module Enumerable
def detect_result(ifnone=nil, &block)
self.each { |x|
result = block.call(x)
return result if result
}
if ifnone
then ifnone.call
else nil
end
end
end

Regards,
Jordan

On Nov 24, 5:12 pm, Yossef M. [email protected] wrote:

end

A little better.

 result = nil
 formats.find do |f|
   result = f.process(mesg)
 end

T.

Yossef,

Just curious, but does the detect_results method for the Enumerable
module that I listed above, work for your example:

results = formats.detect_results { |f| f.process(mesg) }

?

Regards,
Jordan

On Nov 25, 3:00 am, MonkeeSage [email protected] wrote:

Jordan
I didn’t bother to try. It looks like it’ll work just fine. I like the
idea of specifying an alternate value if nothing matches, but it’s
always odd to pass two blocks to a method.

On Nov 25, 8:52 am, Yossef M. [email protected] wrote:

I didn’t bother to try. It looks like it’ll work just fine. I like the
idea of specifying an alternate value if nothing matches, but it’s
always odd to pass two blocks to a method.

It’s actually the same thing that detect() does, I just made it return
the value of the first True instance, rather than the object. If you
look at the docs for Enumerable#detect, it’s the same semantics for
ifnone.

Regards,
Jordan

On Nov 25, 12:00 am, Trans [email protected] wrote:

  result = f.process(mesg)

T.
Well, dang. I would say that’s obvious, but if that were actually the
case I would’ve thought of it. Nice one.