Adding *each*

I’m trying to wrap my head around how to do an “each” for objects of a
class that I have created.

Consider this contrived example
class X
def initialize
@x = [10, ‘a’, ‘c’, 9, 8]
end
end

In Ruby 1.8, what’s the magic incantation so that I can do

x = X.new
x.each {|y| puts y}

I have read and reread Dave T.'Programming Ruby 1.9 and … well
… I think I have to define each in class X and add some enumerable
stuff … but … I just don’t get it.

On Sun, Aug 22, 2010 at 2:45 AM, Ralph S. [email protected]
wrote:

 x = X.new
 x.each {|y| puts y}

I have read and reread Dave T.'Programming Ruby 1.9 and … well … Â I think I have to define each in class X and add some enumerable stuff … but … I just don’t get it.

class X
include Enumerable

def initialize
@x = [10, ‘a’, ‘c’, 9, 8]
end

def each(&block)
@x.each(&block)
end
end

On Saturday, August 21, 2010 12:45:49 pm Ralph S. wrote:

In Ruby 1.8, what’s the magic incantation so that I can do

x = X.new
x.each {|y| puts y}

You can do that anyway, it just doesn’t do anything. All methods can
accept a
block, whether you want them to or not. All you have to do is yield to
it.

I have read and reread Dave T.'Programming Ruby 1.9 and … well …
I think I have to define each in class X and add some enumerable stuff

First, why are you reading a 1.9 book and applying it to 1.8?
Not that it should matter…

You have to define ‘each’, yes, and you probably should include
enumerable.
I’ll give a contrived solution to your contrived example:

class X
def each
yield @x[0]
yield @x[1]

end
end

That ‘yield’ is a call to whatever block you passed. You could, of
course,
wrap it in a loop, or even an enumerator of its own:

class X
def each
@x.each {|x| yield x}
end
end

In this specific case, your contrived example is just contrived enough
that we
could take it a step further. You can grab that block as an actual
argument by
prefixing it with &, and apply it the same way. So, you can just pass it
straight through, as Michael F. suggested:

class X
def each(&block)
@x.each(&block)
end
end

It’s contrived, but we may as well finish it up:

class X

adds map, select, and so on

include Enumerable

def each(&block)
# enum_for makes a new enum which uses ‘each’ by default
return enum_for if block_given?
@x.each(&block)
end
end

I don’t always include Enumerable, but I do always do enum_for, because
not
everything I want to enumerate is already in a form I can call ‘each’
on. For
example:

class Foo
def all_bars
return enum_for :all_bars unless block_given?
yield :bar
yield :foobar
yield :baz
end
end

Now I can do crazy stuff like:

Foo.new.all_bars.map(&:to_s)
Foo.new.all_bars{|b| puts b}

That way, I can have multiple methods like that, each of which either
behaves
as the appropriate iterator, or gives me an appropriate enumerable (an
enumerator, specifically) to play with.

I just don’t get it.

I hope I’ve helped, but if not, I’m going to need more than that. If you
still
don’t get it, let me know what you don’t get, and we can go from there.