Hello
I was trying to make an iterator that goes through a simple tree
structure something like that:
class Node
...
def each_child(&block)
@children.each { |child| yield(child) { child.each_child(&block) } }
end
...
end
so i could generate a simple html menu:
puts "<ul>"
root_node.each_child { |node|
puts "<li><a href=\"#{child.link}\">#{child.title}</a></li>"
unless node.children.empty?
puts "<ul>"
yield
puts "</ul>"
end
}
puts "</ul>"
But it turns out that Ruby syntax prohibits passing blocks to yield. A
simple workaround is to use block.call instead of yield everywhere.
Is there any good reason for that limitation?
···
--
Posted via http://www.ruby-forum.com/.
There is no point in passing a block to yield because yield implicitly calls the block passed to the current method.
I think what you really want is this:
def each_child(&b)
b[self] # or b.call(self) or simply yield self
@children.each {|ch| ch.each_child(&b)}
self
end
Kind regards
robert
···
On 28.06.2010 14:52, Andy Bogdanov wrote:
I was trying to make an iterator that goes through a simple tree
structure something like that:
class Node
..
def each_child(&block)
@children.each { |child| yield(child) { child.each_child(&block) } }
end
..
end
so i could generate a simple html menu:
puts "<ul>"
root_node.each_child { |node|
puts "<li><a href=\"#{child.link}\">#{child.title}</a></li>"
unless node.children.empty?
puts "<ul>"
yield
puts "</ul>"
end
}
puts "</ul>"
But it turns out that Ruby syntax prohibits passing blocks to yield. A
simple workaround is to use block.call instead of yield everywhere.
Is there any good reason for that limitation?
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
Looks like you can get it to work by explicitly taking the block, rather
than trying to yield.
def foo(&block)
block.call 1 do
2
end
end
foo do |param,&block|
puts "The param is #{param}"
puts "The block is #{block.call}"
end
I checked it on 1.8.7 - 1.9.2, it does not work on 1.8.6, though.
···
On Mon, Jun 28, 2010 at 7:52 AM, Andy Bogdanov <andy.bogdanov@gmail.com>wrote:
Hello
I was trying to make an iterator that goes through a simple tree
structure something like that:
class Node
...
def each_child(&block)
@children.each { |child| yield(child) { child.each_child(&block) } }
end
...
end
so i could generate a simple html menu:
puts "<ul>"
root_node.each_child { |node|
puts "<li><a href=\"#{child.link}\">#{child.title}</a></li>"
unless node.children.empty?
puts "<ul>"
yield
puts "</ul>"
end
}
puts "</ul>"
But it turns out that Ruby syntax prohibits passing blocks to yield. A
simple workaround is to use block.call instead of yield everywhere.
Is there any good reason for that limitation?
--
Posted via http://www.ruby-forum.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)
b[self] # or b.call(self) or simply yield self
@children.each {|ch| ch.each_child(&b)}
self
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.
···
--
Posted via http://www.ruby-forum.com/\.
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 = Struct.new :parent, :info do
def visit(visitor)
visitor.child(self)
end
end
class Parent < Child
def initialize
@children =
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 -= 1
end
def child(n)
puts "#{indent * ' '} <li>#{n.info}</li>"
end
end
I hope you get the idea.
Kind regards
robert
[1] Visitor pattern - Wikipedia
[2] Double dispatch - Wikipedia
···
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)
b[self] # or b.call(self) or simply yield self
@children.each {|ch| ch.each_child(&b)}
self
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.
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/