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/>
Recursive Design Inc. -- <http://www.recursive.ca/>
Raconteur -- <http://www.raconteur.info/>
xampl for Ruby -- <http://rubyforge.org/projects/xampl/>