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?

···

--
-yossef

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

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, 2007 11:12 PM, Yossef Mendelssohn <ymendel@pobox.com> wrote:

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?

--
-yossef

--
what do I think about Ruby?
http://ruby-smalltalk.blogspot.com/

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, 4:12 pm, Yossef Mendelssohn <ymen...@pobox.com> wrote:

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

A little better.

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

T.

···

On Nov 24, 5:12 pm, Yossef Mendelssohn <ymen...@pobox.com> wrote:

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

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

···

On Nov 25, 12:00 am, Trans <transf...@gmail.com> wrote:

On Nov 24, 5:12 pm, Yossef Mendelssohn <ymen...@pobox.com> wrote:

> 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

A little better.

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

T.

--
-yossef

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

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, 3:00 am, MonkeeSage <MonkeeS...@gmail.com> wrote:

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

--
-yossef

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, 8:52 am, Yossef Mendelssohn <ymen...@pobox.com> 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.