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
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.
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.
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
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.
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.
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
On Mon, 09 Jan 2006 01:09:23 -0000, James Edward G. II [email protected] wrote:
It works just fine, yes. Just doesn’t feel very Rubyish to me.
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.
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