Forum: Ruby Iterator Fu Failing Me

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
James G. (Guest)
on 2006-01-07 06:38
(Received via mailing list)
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

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

Thanks for any tips you can offer.

James Edward G. II
Marcel Molina Jr. (Guest)
on 2006-01-07 06:41
(Received via mailing list)
On Sat, Jan 07, 2006 at 01:36:30PM +0900, James Edward G. II wrote:
>     ClassC.parse?(token)
> Except that I want the return result of parse?(), instead of the
> class that took it.

do/end doesn't bind tightly enough for the assignment to 'elements'.
Using {}
should work.

marcel
James G. (Guest)
on 2006-01-07 06:50
(Received via mailing list)
On Jan 6, 2006, at 10:39 PM, Marcel Molina Jr. wrote:

> should work.
Sure it does:

 >> numbers = (1..3).map do |n|
?>   n * 2
 >> end
=> [2, 4, 6]

My problem is not syntax.  It's that I can't find a way to iterate to
the result of parse?().

James Edward G. II
unknown (Guest)
on 2006-01-07 07:41
(Received via mailing list)
Are "Write a new Enumerable method that mimics find but returns the
block result instead" or "do a less elegant solution involving
assignment" not acceptable solutions?
unknown (Guest)
on 2006-01-07 08:02
(Received via mailing list)
On Sat, 7 Jan 2006, James Edward G. II wrote:

>    ClassC.parse?(token)
> took it.
harp:~ > cat a.rb

   module Parser
     module ClassMethods
       def parse tokens, klasses
         tokens.map{|token| catch('parse!'){ klasses.each{|klass|
klass.parse! token}; nil}}
       end
       def parse! token
         ret = parse?(token) and throw 'parse!', ret
       end
       def parse? token
         return "<#{ token }> parsed by <#{ self }>" if token =~
self::RE
       end
     end
     module InstanceMethods
     end
     def self::included other
       other.module_eval{ extend ClassMethods and include
InstanceMethods }
     end
     extend ClassMethods and include InstanceMethods
   end

   class ClassA
     include Parser
     RE = /a/
   end

   class ClassB
     include Parser
     RE = /b/
   end

   class ClassC
     include Parser
     RE = /c/
   end

   elements = Parser::parse %w( a b c d ), [ClassA, ClassB, ClassC]

   p elements


   harp:~ > ruby a.rb
   ["<a> parsed by <ClassA>", "<b> parsed by <ClassB>", "<c> parsed by
<ClassC>", nil]


you can probably come up with something shorter - but using catch/throw
with
parsers is very useful to break of conditions like these.

cheers.

-a
Eero S. (Guest)
on 2006-01-07 08:17
(Received via mailing list)
On 2006.01.07 13:36, James Edward G. II wrote:
>     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
                }
              }

> Except that I want the return result of parse?(), instead of the
> class that took it.
>
> Thanks for any tips you can offer.
>
> James Edward G. II


E
Michael Q. Harris (Guest)
on 2006-01-07 10:14
(Received via mailing list)
Are "Write a new Enumerable method that mimics find but returns the
block result instead" or "do a less elegant solution involving
assignment" not acceptable solutions?
Henrik M. (Guest)
on 2006-01-07 12:35
(Received via mailing list)
On Sat, 2006-01-07 at 05:36, James Edward G. II wrote:
>      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

I am not certain if this solution fits, but...

There is a refactoring named Replace Conditional with Polymorphism that
might solve your problem. The idea is that when you have a conditional,
you can create a class hierarchy with one subclass for each leg in the
conditional. (See
http://www.refactoring.com/catalog/replaceConditio...
for a slightly better explanation.)

You already have several different parser classes, and of course you
don't need to bother with a class hierarchy, so you could do something
like:

parser = ParserFactory.create(parser_type)
...
elements = tokens.map do |token|
  parser.parse?(token)
end

Note that 'parser_type' may well be the class of a token in tokens.

This works assuming that all tokens in 'tokens' are of the same type.
For example, you have one parser for handling CSV data, another for XML,
a third for SGML, a fourth for non-compliant HTML, etc.

On the other hand, if each parser class handles a subset of the tokens
you get from one type of input, for example you have tokenized an XML
file, and have one parser for elements, another for processing
instructions, a third for text nodes, etc., you will need something
different. A case statement would do the trick:

elements = tokens.map do |token|
  case token
    when Element
      ElementParser.parse?(token)
    when Text
      TextParser.parse?(token)
      ...
    else
      raise "Unknown token type"
  end
end

You can then factor out the case statement into a method named parse?,
move the parse? method to a class of it's own, and be back to:

elements = tokens.map do |token|
  ParseEverything.parse?(token)
end

A while ago I wrote a CSV parser in Java for a talk on Test Driven
Design. The Java code got horribly complex, but it struck me that in
Ruby I could do this:

class Parser
  def parse(reader, writer)
    tokenize(reader) { |type| |value|
      write(type, value, writer)
    }
  end
end

By mixing in tokenize and write methods, it would be possible to build
parsers that handle most formats.

I hope this helps.

/Henrik

--

http://www.henrikmartensson.org/  - Reflections on software development
Brian M. (Guest)
on 2006-01-07 13:05
(Received via mailing list)
On 1/6/06, James Edward G. II <removed_email_address@domain.invalid> wrote:
>      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
>

How about:

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

It isn't perfectly efficient but it is short.

Brian.
Robert K. (Guest)
on 2006-01-07 15:35
(Received via mailing list)
James Edward G. II <removed_email_address@domain.invalid> wrote:
>     ClassC.parse?(token)
> Except that I want the return result of parse?(), instead of the
> class that took it.
>
> Thanks for any tips you can offer.
>
> James Edward G. II

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

alternative using a method definition

def parse(token)
  parsers.each {|par| a=par.parse(token) and return a}
  false
end

But the best solution is

elements = tokens.map do |tok|
  parsers.detect {|par| par.parse(tok)}
end

:-)

Kind regards

    robert
unknown (Guest)
on 2006-01-07 16:50
(Received via mailing list)
On Sat, 7 Jan 2006, Eero S. wrote:

>>     ClassB.parse?(token) or
>
>  # 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...)

regards.

-a
--
===============================================================================
| 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
===============================================================================
unknown (Guest)
on 2006-01-07 17:29
(Received via mailing list)
On Sat, 7 Jan 2006, Robert K. wrote:

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

nice.

-a
--
===============================================================================
| 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
===============================================================================
Robert K. (Guest)
on 2006-01-07 17:45
(Received via mailing list)
removed_email_address@domain.invalid wrote:
> On Sat, 7 Jan 2006, Robert K. wrote:
>
>> elements = tokens.map do |tok|
>> parsers.inject(false) {|a,par| a=par.parse(tok) and break a}
>> end
>
> nice.

Yeah, but #detect is better here.  And if *I* say that another solution
is
bettern than an inject solution... :-)

    robert
Bob H. (Guest)
on 2006-01-07 18:06
(Received via mailing list)
On Jan 6, 2006, at 11:36 PM, James Edward G. 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


----
Bob H.                  -- blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc.          -- <http://www.recursive.ca/>
Raconteur                      -- <http://www.raconteur.info/>
xampl for Ruby                 -- <http://rubyforge.org/projects/xampl/>
Robert K. (Guest)
on 2006-01-07 18:15
(Received via mailing list)
Bob H. <removed_email_address@domain.invalid> wrote:
>> 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. :-)  And then it's
much
more inelegant than using #detect. :-)

Kind regards

    robert
Pierre Barbier de Reuille (Guest)
on 2006-01-07 18:24
(Received via mailing list)
removed_email_address@domain.invalid a écrit :
>>    ClassA.parse?(token) or
>>  end
>       def parse tokens, klasses
>     module InstanceMethods
>     end
>     def self::included other
>       other.module_eval{ extend ClassMethods and include InstanceMethods }
>     end
>     extend ClassMethods and include InstanceMethods
>   end

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 ?

Thanks !
Pierre Barbier de Reuille (Guest)
on 2006-01-07 18:30
(Received via mailing list)
Robert K. a écrit :
>>>   end
>> 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. :-)  And then it's
> much more inelegant than using #detect. :-)
>
> Kind regards
>
>    robert
>

Well, looking at the documentation of ruby1.8, detect and find are
aliases ... is it specific to ruby1.8 or some newer/older version ?

Pierre
unknown (Guest)
on 2006-01-07 18:30
(Received via mailing list)
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.

cheers.

-a
--
===============================================================================
| 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
===============================================================================
Bob H. (Guest)
on 2006-01-07 19:21
(Received via mailing list)
On Jan 7, 2006, at 11:13 AM, Robert K. wrote:

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

cut'n'past-o... oops

>   And then it's much more inelegant than using #detect. :-)

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


>
> Kind regards
>
>    robert
>
>

----
Bob H.                  -- blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc.          -- <http://www.recursive.ca/>
Raconteur                      -- <http://www.raconteur.info/>
xampl for Ruby                 -- <http://rubyforge.org/projects/xampl/>
Robert K. (Guest)
on 2006-01-07 20:09
(Received via mailing list)
Bob H. <removed_email_address@domain.invalid> wrote:
>>>>     [ClassA, ClassB, ClassC].find { |kind| kind.parse?(token) }
>>> (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. :-)
>
> cut'n'past-o... oops
>
>>   And then it's much more inelegant than using #detect. :-)
>
> 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
nil
nil
w
=> "w"
>> [nil,nil,nil,"w",2,3].select {|x|puts x;x}
nil
nil
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 H. (Guest)
on 2006-01-07 20:21
(Received via mailing list)
On Jan 7, 2006, at 12:19 PM, Bob H. wrote:

>>>>   elements = tokens.map do |token|
>>>   [ClassA, ClassB, ClassC].find { |kind| result = kind.parse?
> You mean #detect or #select?
> 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

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

----
Bob H.                  -- blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc.          -- <http://www.recursive.ca/>
Raconteur                      -- <http://www.raconteur.info/>
xampl for Ruby                 -- <http://rubyforge.org/projects/xampl/>
Bob H. (Guest)
on 2006-01-07 20:24
(Received via mailing list)
On Jan 7, 2006, at 12:19 PM, Bob H. wrote:

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

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.

----
Bob H.                  -- blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc.          -- <http://www.recursive.ca/>
Raconteur                      -- <http://www.raconteur.info/>
xampl for Ruby                 -- <http://rubyforge.org/projects/xampl/>
Mauricio F. (Guest)
on 2006-01-07 20:27
(Received via mailing list)
On Sun, Jan 08, 2006 at 01:13:00AM +0900, Robert K. wrote:
> >>
> Because this won't return the proper value from the block.  You need at
> least to add a line with "result" after the #find. :-)  And then it's much
> more inelegant than using #detect. :-)

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

...
James G. (Guest)
on 2006-01-07 20:54
(Received via mailing list)
On Jan 7, 2006, at 7:33 AM, Robert K. wrote:

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

That's what I was looking for.  Thank you.

> But the best solution is
>
> elements = tokens.map do |tok|
>  parsers.detect {|par| par.parse(tok)}
> end

That's not equivalent.  It's actually the same example I showed in my
original question message that didn't work.  See that post for
details, but the short story is that it finds the parsers that did
the conversion, not the parsed elements I was looking for.

James Edward G. II
Bob H. (Guest)
on 2006-01-07 21:15
(Received via mailing list)
On Jan 7, 2006, at 1:08 PM, Robert K. wrote:
> w
> => "w"
>>> [nil,nil,nil,"w",2,3].select {|x|puts x;x}
> nil
> nil
> 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.

>    robert
>
>

----
Bob H.                  -- blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc.          -- <http://www.recursive.ca/>
Raconteur                      -- <http://www.raconteur.info/>
xampl for Ruby                 -- <http://rubyforge.org/projects/xampl/>
Eero S. (Guest)
on 2006-01-07 21:43
(Received via mailing list)
On 2006.01.07 23:49, removed_email_address@domain.invalid wrote:
> >>  elements = tokens.map do |token|
> >>    [ClassA, ClassB, ClassC].find { |kind| kind.parse?(token) }
>
>   [[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 :)

> regards.
> -a


E
Robert K. (Guest)
on 2006-01-08 00:44
(Received via mailing list)
Bob H. <removed_email_address@domain.invalid> wrote:
>> nil
>>
>
> 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

Thanks for correcting me!

    robert
unknown (Guest)
on 2006-01-08 01:08
(Received via mailing list)
Hi --

On Sun, 8 Jan 2006, removed_email_address@domain.invalid wrote:

> 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
removed_email_address@domain.invalid

"Ruby for Rails", from Manning Publications, coming April 2006!
http://www.manning.com/books/black
Bob H. (Guest)
on 2006-01-08 16:08
(Received via mailing list)
On Jan 7, 2006, at 5:43 PM, Robert K. wrote:

>>> nil
>>> => ["w", 2, 3]
> 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 :-)

>
>    robert
>
>

----
Bob H.                  -- blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc.          -- <http://www.recursive.ca/>
Raconteur                      -- <http://www.raconteur.info/>
xampl for Ruby                 -- <http://rubyforge.org/projects/xampl/>
jwesley (Guest)
on 2006-01-09 02:58
(Received via mailing list)
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

Justin
James G. (Guest)
on 2006-01-09 03:10
(Received via mailing list)
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>

James Edward G. II
Ross B. (Guest)
on 2006-01-09 03:55
(Received via mailing list)
On Mon, 09 Jan 2006 01:09:23 -0000, James Edward G. II
<removed_email_address@domain.invalid> wrote:

> 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:

	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.
Ross B. (Guest)
on 2006-01-09 04:13
(Received via mailing list)
On Mon, 09 Jan 2006 01:45:11 -0000, Ross B.
<removed_email_address@domain.invalid> wrote:

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

For crying out loud I've done it again }:-{. Please ignore me.
Ross B. (Guest)
on 2006-01-09 04:25
(Received via mailing list)
On Mon, 09 Jan 2006 01:45:11 -0000, Ross B.
<removed_email_address@domain.invalid> wrote:

>>>      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:
>

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.
Ross B. (Guest)
on 2006-01-09 04:40
(Received via mailing list)
On Mon, 09 Jan 2006 02:17:26 -0000, Ross B.
<removed_email_address@domain.invalid> 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
>

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.
Bob H. (Guest)
on 2006-01-09 15:05
(Received via mailing list)
On Jan 8, 2006, at 9:38 PM, Ross B. wrote:

> 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. :-)

>
> --
> Ross B. - removed_email_address@domain.invalid
>

----
Bob H.                  -- blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc.          -- <http://www.recursive.ca/>
Raconteur                      -- <http://www.raconteur.info/>
xampl for Ruby                 -- <http://rubyforge.org/projects/xampl/>
Adam S. (Guest)
on 2006-01-09 20:47
(Received via mailing list)
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
unknown (Guest)
on 2006-01-10 02:29
(Received via mailing list)
On Sun, 8 Jan 2006 removed_email_address@domain.invalid 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.

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
--
===============================================================================
| 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
===============================================================================
This topic is locked and can not be replied to.