2010/6/28 Andy Bogdanov <andy.bogdanov / gmail.com>:
>> There is no point in passing a block to yield
>
> Maybe there always is a way to avoid using procs and lambdas, but i
> don't see other easy way in my case (see below).
> Proc#call accepts blocks, why does yield not? It's almost the same
> thing.
>
>> yield implicitly calls the block
>> passed to the current method.
>
> Thanks for the tip. Forgot that yield belongs to method context only.
>
>> def each_child(&b)
>> =A0 =A0b[self] # or b.call(self) or simply yield self
>> =A0 =A0 / children.each {|ch| ch.each_child(&b)}
>> =A0 =A0self
>> end
>
> This code will just pass all the elements to a block, there's no way to
> wrap lower levels into <ul> tag. I need to control what happens before
> and after each_child so i have use a number of procs as arguments or do
> this trick with a block.

This would not be solved by yield accepting a block however.  Your
problem is more complicated.  Basically you have a tree structure and
you want to traverse the tree while treating inner nodes and leafs
differently.  You would need at least two different blocks to do what
you want.  This kind of problem is typically solved with a visitor
pattern [1] or similar solution.  Basically you need double dispatch
[2] on the node type and on the algorithm type.

In your case you could do

# untested
Child =3D Struct.new :parent, :info do
  def visit(visitor)
    visitor.child(self)
  end
end

class Parent < Child
  def initialize
    @children =3D []
  end

  def visit(visitor)
    visitor.enter_node(self)
    @children.each {|ch| ch.visit(visitor)}
    visitor.leave_node(self)
  end
end

class HtmlPrinter
  def enter_node(n)
    @indent ? @indent + 1 : 1
    puts "#{indent * ' '}<ul>"
  end

  def leave_node(n)
    puts "#{indent * ' '}</ul>"
    @indent -=3D 1
  end

  def child(n)
    puts "#{indent * ' '} <li>#{n.info}</li>"
  end

end

I hope you get the idea.

Kind regards

robert


[1] http://en.wikipedia.org/wiki/Visitor_pattern
[2] http://en.wikipedia.org/wiki/Double_dispatch

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/