Support for arbitrary iterators in Enumerable?

Hello,

I really like the way Ruby handles iteration (each/yield), and
combined with all the standard methods in Enumerable, it makes it easy
powerful algorithms in a very concise way. However, and unless I’m
missing something, Enumerable is hard-coded to only use the standard
#each iterator.

Sometimes it’s convenient for a class to provide several iterators.
For example, String has #each_line and #each_byte, and we could
imagine #each_word, #each_paragraph, etc. With the current setup, only
one of these can be aliased to #each and conveniently use
Enumerable#collect and friends.

I would really like to be able to pass the name of an iterator method
to Enumerable methods. If the parameter value defaults to :each, it
would not break any existing code.

Here’s an example of what I’m thinking of, for Enumerable#collect:

module Enumerable
def collect(iterator = :each)
raise “Invalid iterator” if not self.respond_to?(iterator)
result = Array.new
self.send(iterator) do |val|
result << yield(val)
end
return result
end
end

Is this kind of thing already possible (maybe in 1.8.0) ? If not, do
you think it would be a valuable addition ?

···


Pierre-Charles David (pcdavid emn fr)
Computer Science PhD Student, École des Mines de Nantes, France
Homepage: http://pcdavid.net/

Hello,

it’s a bit of an old mail from somebody else i’m sending again (2 oct
2003)… i probably missed something, since nobody answered to it, but it
seems interesting to me. is speed the issue maybe?
why is it not the way he suggests?

emmanuel

Pierre-Charles David wrote:

···

Hello,

I really like the way Ruby handles iteration (each/yield), and
combined with all the standard methods in Enumerable, it makes it easy
powerful algorithms in a very concise way. However, and unless I’m
missing something, Enumerable is hard-coded to only use the standard
#each iterator.

Sometimes it’s convenient for a class to provide several iterators.
For example, String has #each_line and #each_byte, and we could
imagine #each_word, #each_paragraph, etc. With the current setup, only
one of these can be aliased to #each and conveniently use
Enumerable#collect and friends.

I would really like to be able to pass the name of an iterator method
to Enumerable methods. If the parameter value defaults to :each, it
would not break any existing code.

Here’s an example of what I’m thinking of, for Enumerable#collect:

module Enumerable
def collect(iterator = :each)
raise “Invalid iterator” if not self.respond_to?(iterator)
result = Array.new
self.send(iterator) do |val|
result << yield(val)
end
return result
end
end

Is this kind of thing already possible (maybe in 1.8.0) ? If not, do
you think it would be a valuable addition ?

Pierre-Charles David wrote:

I would really like to be able to pass the name of an iterator method

to Enumerable methods. If the parameter value defaults to :each, it
would not break any existing code.

enumerator in 1.8.1

            str = "xyz"

            enum = Enumerable::Enumerator.new(str, :each_byte)
            a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]

Guy Decoux