views:

57

answers:

2

Hello,

I have some difficulties for using Ruby block, passing in a method. As in the following case, I would like to display each element of @array, from Box instance (using .each method):

class Box
  def initialize
    @array = [:foo, :bar]
  end

  def each(&block)
    # well, hm..
  end
end

a = Box.new
a.each { |element| puts element }

Thanks for any help.

A: 

For this simple example, you actually aren't required to pass the block explicitly:

def each                  
  @array.each{|e| yield e}
end

Passing the block (which is a Proc object) explicitly allows you to test it for things, like the number of arguments that it expects:

class Box
  ...    
  def each(&block)
    @array.each do |e|
      case block.arity
      when 0
        yield
      when 1
        yield e
      when 2
        yield e, :baz
      else
        yield
      end
    end
  end
end

a = Box.new
a.each { puts "nothing" }              # displays "nothing, nothing"
a.each { |e| puts e }                  # displays "foo, bar"
a.each { |e1, e2| puts "#{e1} #{e2}" } # displays "foo baz, bar baz" 
Nate Kohl
Many thanks, Nate. I will studying your answer ^^
Puru puru rin..
+4  A: 

You really just need to delegate to the each method on @array and pass it the block. Additionally, you can include the Enumerable mix-in to gain access to the methods it provides (e.g. map, inject, etc...):

class Box
  include Enumerable

  def initialize
    @array = [:foo, :bar]
  end

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

More information on the Enumerable module is available in the documentation.

Patrick Reagan
Thanks, Patrick!
Puru puru rin..
+1 - This is pretty decent solution.
Webbisshh
The Forwardable library is another way to handle simple delegation: `require 'forwardable'`, and then inside Box: `extend Forwardable` and `def_delegator(:@array, :each)`
Wayne Conrad