Iterator Fu Failing Me

yes. just symetry/clarity. is use this pattern alot. even if someone
doesn't understand the mechanism i generally assume the 'ClassMethods' and
'InstanceMethods' names will give it away.

cheers.

-a

···

On Sun, 8 Jan 2006, Pierre Barbier de Reuille wrote:

Could you explain this module ?

I think I can understand why you defined a module ClassMethods : to include
class methods and not only instace methods.

However, I don't understant why the InstanceMethods module ? What do you
expect with this module ? Is it just for symetry ?

--

ara [dot] t [dot] howard [at] noaa [dot] gov
strong and healthy,
who thinks of sickness until it strikes like lightning?
preoccupied with the world,
who thinks of death, until it arrives like thunder?
-- milarepa

===============================================================================

That works. Now can anyone give me a version of the middle section
that doesn't require I call parse?() 50 times? I want something
close to:

  elements = tokens.map do |token|
    [ClassA, ClassB, ClassC].find { |kind| kind.parse?(token) }
  end

Except that I want the return result of parse?(), instead of the
class that took it.

Why not:

elements = tokens.map do |token|
  result = nil
  [ClassA, ClassB, ClassC].find { |kind| result = kind.parse?(token) }
end

Because this won't return the proper value from the block. You need at least to add a line with "result" after the #find. :slight_smile:

cut'n'past-o... oops

  And then it's much more inelegant than using #detect. :slight_smile:

You mean #detect or #select?

elements = tokens.select do |token|
   result = nil
   [ClassA, ClassB, ClassC].find { |kind| results << kind.parse?(token) }
   result
end

And this is kind of handy too...

elements = tokens.map do |token|
   result = nil
   [ClassA, ClassB, ClassC].find { |kind| result = [token, kind.parse?(token)] }
   result
end

···

On Jan 7, 2006, at 11:13 AM, Robert Klemme wrote:

Bob Hutchison <hutch@recursive.ca> wrote:

On Jan 6, 2006, at 11:36 PM, James Edward Gray II wrote:

Kind regards

   robert

----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/&gt;
Recursive Design Inc. -- <http://www.recursive.ca/&gt;
Raconteur -- <http://www.raconteur.info/&gt;
xampl for Ruby -- <http://rubyforge.org/projects/xampl/&gt;

Actually,

enum.c:
    rb_define_method(rb_mEnumerable,"find", enum_find, -1);
    rb_define_method(rb_mEnumerable,"detect", enum_find, -1);

...

(1..10).detect{|x| 10*x > 50} # => 6

...

···

On Sun, Jan 08, 2006 at 01:13:00AM +0900, Robert Klemme wrote:

Bob Hutchison <hutch@recursive.ca> wrote:
>On Jan 6, 2006, at 11:36 PM, James Edward Gray II wrote:
>
>>That works. Now can anyone give me a version of the middle section
>>that doesn't require I call parse?() 50 times? I want something
>>close to:
>>
>> elements = tokens.map do |token|
>> [ClassA, ClassB, ClassC].find { |kind| kind.parse?(token) }
>> end
>>
>>Except that I want the return result of parse?(), instead of the
>>class that took it.
>
>Why not:
>
>elements = tokens.map do |token|
> result = nil
> [ClassA, ClassB, ClassC].find { |kind| result = kind.parse?(token) }
>end

Because this won't return the proper value from the block. You need at
least to add a line with "result" after the #find. :slight_smile: And then it's much
more inelegant than using #detect. :slight_smile:

--
Mauricio Fernandez

>>I have a group of classes, all implementing a parse?() class method.
>>Calling parse?(token) will return the constructed object, if it can
>>be parsed by this class, or false otherwise.
>>
>>I want to run a bunch of tokens through these classes, grabbing the
>>first fit. For example:
>>
>> elements = tokens.map do |token|
>> ClassA.parse?(token) or
>> ClassB.parse?(token) or
>> ClassC.parse?(token)
>> end
>>
>>That works. Now can anyone give me a version of the middle section
>>that doesn't require I call parse?() 50 times? I want something
>>close to:
>>
>> elements = tokens.map do |token|
>> [ClassA, ClassB, ClassC].find { |kind| kind.parse?(token) }
>> end
>
> # Not tested
> elements = tokens.map {|token|
> [A, B, C].each {|kind|
> result = kind.parse?(token) and break result
> }
> }

fails when no kind parses. in this case the result will be

  [[A,B,C]] (the return of each...)

You are (of course) absolutely right, it should be 'return result'
coupled with a default nil/false at the end.

One of these days I will learn not to write mail at four in the
morning :slight_smile:

regards.
-a

E

···

On 2006.01.07 23:49, ara.t.howard@noaa.gov wrote:

On Sat, 7 Jan 2006, Eero Saynatkari wrote:
>On 2006.01.07 13:36, James Edward Gray II wrote:

Not sure this is more Rubyish (seems a bit line-noisy) but:

  class Parser
    class << self
      def parse?(tok)
        tok.downcase if tok == self.name
      end
    end
  end

  class One < Parser; end
  class Two < Parser; end
  class Three < Parser; end

  parsers = [One, Two, Three]
  tokens = ['One','Two','One','siz','Four','Two']

  r = tokens.inject do |r,token|
    r << (parsers.zip([token] * parsers.length).detect { |p,tok| p.parse? tok } || )[0]
  end

  p r

Seems to work. It's *terribly* inefficient though I guess.

···

On Mon, 09 Jan 2006 01:09:23 -0000, James Edward Gray II <james@grayproductions.net> wrote:

On Jan 8, 2006, at 6:58 PM, jwesley wrote:

Perhaps I'm missing the point, but wouldn't the following work: (?)

   elements = tokens.map do |token|
     val = nil
     [ClassA, ClassB, ClassC].find { |kind| val = kind.parse?(token) }
     val
   end

It works just fine, yes. Just doesn't feel very Rubyish to me. <shrugs>

--
Ross Bamford - rosco@roscopeco.remove.co.uk

That works. Now can anyone give me a version of the middle section
that doesn't require I call parse?() 50 times? I want something
close to:

  elements = tokens.map do |token|
    [ClassA, ClassB, ClassC].find { |kind| kind.parse?(token) }
  end

Except that I want the return result of parse?(), instead of the
class that took it.

Why not:

elements = tokens.map do |token|
  result = nil
  [ClassA, ClassB, ClassC].find { |kind| result = kind.parse?
(token) }
end

Because this won't return the proper value from the block. You
need at least to add a line with "result" after the #find. :slight_smile:

cut'n'past-o... oops

  And then it's much more inelegant than using #detect. :slight_smile:

You mean #detect or #select?

#detect - because it stops as soon as it has a hit while #select will return an array. We need just the first hit.

[nil,nil,nil,"w",2,3].find {|x|puts x;x}

nil
w
=> "w"

[nil,nil,nil,"w",2,3].select {|x|puts x;x}

nil
w
2
3
=> ["w", 2, 3]

elements = tokens.select do |token|
  result = nil
  [ClassA, ClassB, ClassC].find { |kind| results << kind.parse?
(token) }
  result
end

You don't define results and you never assign result another value than nil...

And this is kind of handy too...

elements = tokens.map do |token|
  result = nil
  [ClassA, ClassB, ClassC].find { |kind| result = [token, kind.parse?
(token)] }
  result
end

There's no point in storing token in result because it's unchanged and available as block parameter.

Say what you want, find/detect is the most elegant solution.

    robert

···

Bob Hutchison <hutch@recursive.ca> wrote:

On Jan 7, 2006, at 11:13 AM, Robert Klemme wrote:

Bob Hutchison <hutch@recursive.ca> wrote:

On Jan 6, 2006, at 11:36 PM, James Edward Gray II wrote:

That works. Now can anyone give me a version of the middle section
that doesn't require I call parse?() 50 times? I want something
close to:

  elements = tokens.map do |token|
    [ClassA, ClassB, ClassC].find { |kind| kind.parse?(token) }
  end

Except that I want the return result of parse?(), instead of the
class that took it.

Why not:

elements = tokens.map do |token|
  result = nil
  [ClassA, ClassB, ClassC].find { |kind| result = kind.parse?(token) }
end

Because this won't return the proper value from the block. You need at least to add a line with "result" after the #find. :slight_smile:

cut'n'past-o... oops

  And then it's much more inelegant than using #detect. :slight_smile:

You mean #detect or #select?

elements = tokens.select do |token|
  result = nil
  [ClassA, ClassB, ClassC].find { |kind| results << kind.parse?(token) }
  result
end

And this is kind of handy too...

elements = tokens.map do |token|
  result = nil
  [ClassA, ClassB, ClassC].find { |kind| result = [token, kind.parse?(token)] }
  result
end

That's wrong! That's twice I've done that. I'm going to go have a nap now.

elements = tokens.map do |token|
   result = nil
   [ClassA, ClassB, ClassC].find { |kind| result = [token, r = kind.parse?(token)]; r }
   result
end

Anyway, I like this version better...

elements = tokens.map do |token|
   result = nil
   [ClassA, ClassB, ClassC].find { |kind| (result = [token, kind.parse?(token)]).last }
   result
end

or this...

elements = tokens.map do |token|
   result = nil
   [ClassA, ClassB, ClassC].find do |kind|
     if r = kind.parse?(token) then result = [r, kind, token] end
   end
   result || [nil, nil, token]
end

and you can use "result = (r = kind.parse?(token)) && [r, kind, token]" if you choose

Cheers,
Bob

···

On Jan 7, 2006, at 12:19 PM, Bob Hutchison wrote:

On Jan 7, 2006, at 11:13 AM, Robert Klemme wrote:

Bob Hutchison <hutch@recursive.ca> wrote:

On Jan 6, 2006, at 11:36 PM, James Edward Gray II wrote:

Kind regards

   robert

----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/&gt;
Recursive Design Inc. -- <http://www.recursive.ca/&gt;
Raconteur -- <http://www.raconteur.info/&gt;
xampl for Ruby -- <http://rubyforge.org/projects/xampl/&gt;

----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/&gt;
Recursive Design Inc. -- <http://www.recursive.ca/&gt;
Raconteur -- <http://www.raconteur.info/&gt;
xampl for Ruby -- <http://rubyforge.org/projects/xampl/&gt;

This is wrong too! It should be:

elements = tokens.select do |token|
   result = nil
   [ClassA, ClassB, ClassC].find { |kind| result = kind.parse?(token) }
   result
end

Now, before I dig anymore holes, I'll stop now.

···

On Jan 7, 2006, at 12:19 PM, Bob Hutchison wrote:

You mean #detect or #select?

elements = tokens.select do |token|
  result = nil
  [ClassA, ClassB, ClassC].find { |kind| results << kind.parse?(token) }
  result
end

----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/&gt;
Recursive Design Inc. -- <http://www.recursive.ca/&gt;
Raconteur -- <http://www.raconteur.info/&gt;
xampl for Ruby -- <http://rubyforge.org/projects/xampl/&gt;

Hi --

···

On Sun, 8 Jan 2006, ara.t.howard@noaa.gov wrote:

On Sun, 8 Jan 2006, Pierre Barbier de Reuille wrote:

Could you explain this module ?

I think I can understand why you defined a module ClassMethods : to include
class methods and not only instace methods.

However, I don't understant why the InstanceMethods module ? What do you
expect with this module ? Is it just for symetry ?

yes. just symetry/clarity. is use this pattern alot. even if someone
doesn't understand the mechanism i generally assume the 'ClassMethods' and
'InstanceMethods' names will give it away.

Wouldn't it be clearer just to write instance methods for a module?
It feels a bit like you're creating a kind of second skin for a system
that already does this.

David

--
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!

For crying out loud I've done it again }:-{. Please ignore me.

···

On Mon, 09 Jan 2006 01:45:11 -0000, Ross Bamford <rosco@roscopeco.remove.co.uk> wrote:

Not sure this is more Rubyish (seems a bit line-noisy) but:

--
Ross Bamford - rosco@roscopeco.remove.co.uk

This one looks worse, but at least really does seem to work this time:

  r = tokens.inject() do |arr,token|
    arr << parsers.zip([token]*parsers.length).inject(nil) do |out,pt|
      out or pt[0].parse?(pt[1])
    end
  end

slotted into the code before and it gives:

  ["one", "two", "one", nil, nil, "three"]

Sorry about that.

···

On Mon, 09 Jan 2006 01:45:11 -0000, Ross Bamford <rosco@roscopeco.remove.co.uk> wrote:

On Mon, 09 Jan 2006 01:09:23 -0000, James Edward Gray II > <james@grayproductions.net> wrote:

On Jan 8, 2006, at 6:58 PM, jwesley wrote:

Perhaps I'm missing the point, but wouldn't the following work: (?)

   elements = tokens.map do |token|
     val = nil
     [ClassA, ClassB, ClassC].find { |kind| val = kind.parse?(token) }
     val
   end

It works just fine, yes. Just doesn't feel very Rubyish to me. <shrugs>

Not sure this is more Rubyish (seems a bit line-noisy) but:

--
Ross Bamford - rosco@roscopeco.remove.co.uk

You mean #detect or #select?

#detect - because it stops as soon as it has a hit while #select will return an array. We need just the first hit.

[nil,nil,nil,"w",2,3].find {|x|puts x;x}

nil
w
=> "w"

[nil,nil,nil,"w",2,3].select {|x|puts x;x}

nil
w
2
3
=> ["w", 2, 3]

The trouble is that detect returns the 'x' not the result of processing x successfully (or, in terms of the original post, the class that accepts the token not the result of the #parse? method). That's why you have to capture the result in the block. Map returns the result of processing.

elements = tokens.select do |token|
  result = nil
  [ClassA, ClassB, ClassC].find { |kind| results << kind.parse?
(token) }
  result
end

You don't define results and you never assign result another value than nil...

Sorry, I've 'corrected' myself in a mail I just sent out. (My email is suffering long delays today, and my mind isn't working all that quickly either I think)

This is what I had intended with the "<< results" is:

results =
tokens.each do |token|
   # use find over the collection of classes to find the one that successfully parses the
   # token. Find will return the class, not the result of #parse?, so capture that result
   # by using a closure on result (Note: result must appear outside of and before the block.
   # Collect each result in results.
   result = nil
   [ClassA, ClassB, ClassC].find { |kind| result = kind.parse?(token)}
   results << result if result
end

If you also want the nil results then you can use:

elements = tokens.map do |token|
   result = nil
   [ClassA, ClassB, ClassC].find { |kind| result = kind.parse?(token)}
   result
end

Say what you want, find/detect is the most elegant solution.

Only they return the wrong things.

···

On Jan 7, 2006, at 1:08 PM, Robert Klemme wrote:

   robert

----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/&gt;
Recursive Design Inc. -- <http://www.recursive.ca/&gt;
Raconteur -- <http://www.raconteur.info/&gt;
xampl for Ruby -- <http://rubyforge.org/projects/xampl/&gt;

Damn it...

···

On Mon, 09 Jan 2006 02:17:26 -0000, Ross Bamford <rosco@roscopeco.remove.co.uk> wrote:

  r = tokens.inject() do |arr,token|
    arr << parsers.zip([token]*parsers.length).inject(nil) do |out,pt|
      out or pt[0].parse?(pt[1])
    end
  end

  ==

  r = tokens.inject() do |arr,token|
    arr << parsers.inject(nil) { |out,p| out or p.parse?(token) }
  end

Now I'm really done. Promise.

--
Ross Bamford - rosco@roscopeco.remove.co.uk

generally i do just this. however, i've found it extremely useful to be able
to do

   include SomeModule::InstanceMethods # mixin only instance methods

   extend SomeModule::ClassMethods # mixin only class methods

   include SomeModule # mixin InstanceMethods and extend with ClassMethods via
                      # over-ridden self::included

when factoring out code in large systems.

regards.

-a

···

On Sun, 8 Jan 2006 dblack@wobblini.net wrote:

Wouldn't it be clearer just to write instance methods for a module? It
feels a bit like you're creating a kind of second skin for a system that
already does this.

--

ara [dot] t [dot] howard [at] noaa [dot] gov
strong and healthy,
who thinks of sickness until it strikes like lightning?
preoccupied with the world,
who thinks of death, until it arrives like thunder?
-- milarepa

===============================================================================

Aargh! I shoul've tested more carefully. Yes you're completely right. But the inject version still works, I think that's then my favourite.

elements = tokens.map do |tok|
  parsers.inject(false) {|a,pars| a = pars.parse? tok and break a}
end

Thanks for correcting me!

    robert

···

Bob Hutchison <hutch@recursive.ca> wrote:

On Jan 7, 2006, at 1:08 PM, Robert Klemme wrote:

You mean #detect or #select?

#detect - because it stops as soon as it has a hit while #select
will return an array. We need just the first hit.

[nil,nil,nil,"w",2,3].find {|x|puts x;x}

nil
w
=> "w"

[nil,nil,nil,"w",2,3].select {|x|puts x;x}

nil
w
2
3
=> ["w", 2, 3]

The trouble is that detect returns the 'x' not the result of
processing x successfully (or, in terms of the original post, the
class that accepts the token not the result of the #parse? method).
That's why you have to capture the result in the block. Map returns
the result of processing.

  r = tokens.inject() do |arr,token|
    arr << parsers.zip([token]*parsers.length).inject(nil) do |out,pt|
      out or pt[0].parse?(pt[1])
    end
  end

Damn it...

==

  r = tokens.inject() do |arr,token|
    arr << parsers.inject(nil) { |out,p| out or p.parse?(token) }
  end

Now I'm really done. Promise.

This thread is jinxed. :slight_smile:

···

On Jan 8, 2006, at 9:38 PM, Ross Bamford wrote:

On Mon, 09 Jan 2006 02:17:26 -0000, Ross Bamford > <rosco@roscopeco.remove.co.uk> wrote:

--
Ross Bamford - rosco@roscopeco.remove.co.uk

----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/&gt;
Recursive Design Inc. -- <http://www.recursive.ca/&gt;
Raconteur -- <http://www.raconteur.info/&gt;
xampl for Ruby -- <http://rubyforge.org/projects/xampl/&gt;

You mean #detect or #select?

#detect - because it stops as soon as it has a hit while #select
will return an array. We need just the first hit.

[nil,nil,nil,"w",2,3].find {|x|puts x;x}

nil
w
=> "w"

[nil,nil,nil,"w",2,3].select {|x|puts x;x}

nil
w
2
3
=> ["w", 2, 3]

The trouble is that detect returns the 'x' not the result of
processing x successfully (or, in terms of the original post, the
class that accepts the token not the result of the #parse? method).
That's why you have to capture the result in the block. Map returns
the result of processing.

Aargh! I shoul've tested more carefully. Yes you're completely right. But the inject version still works, I think that's then my favourite.

elements = tokens.map do |tok|
parsers.inject(false) {|a,pars| a = pars.parse? tok and break a}
end

Personally, I don't like the break. It'd be very nice if there were equivalent operations returning the result of the calculation rather than the object.

Thanks for correcting me!

Sorry for the brutally finger-tied attempts at communication :slight_smile:

···

On Jan 7, 2006, at 5:43 PM, Robert Klemme wrote:

Bob Hutchison <hutch@recursive.ca> wrote:

On Jan 7, 2006, at 1:08 PM, Robert Klemme wrote:

   robert

----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/&gt;
Recursive Design Inc. -- <http://www.recursive.ca/&gt;
Raconteur -- <http://www.raconteur.info/&gt;
xampl for Ruby -- <http://rubyforge.org/projects/xampl/&gt;

why not write a new iterator: it will probably be useful again sometime:

module Enumerable
  def find_first_result
    each {|item| result = yield item; return result if result }
    nil
  end
end

irb(main):075:0> tokens = %w( adam codes in ruby )
=> ["adam", "codes", "in", "ruby"]
irb(main):076:0> classes = [/a/, /b/, /c/]
=> [/a/, /b/, /c/]
irb(main):077:0> elements = tokens.map do |token|
irb(main):078:1* classes.find_first_result {|kind| kind =~ token}
irb(main):079:1> end
=> [0, 0, nil, 2]

-Adam