I've written my own Tree
class which includes Enumerable
. Tree
then provides an #each
function. As a consequence, it is able to automatically acquire all the Enumerable
functions like #map
, #select
, #find
, et cetera. This all works in my code so far.
Here's the problem. When I wrote #each
for my Tree
, I gave #each
an argument which is the name of the tree traversal algorithm to use, such as :pre_order
or :breadth_first
. But now when I call #map
or #inject
or #any?
et cetera, it can only use the default traversal algorithm. Is there any way I can pass this argument through the other Enumerable
functions? Here are my criteria;
Enumerable
function. This is very important because trees can have very different performance for different algorithms.Enumerable
function to pass this argument to #each
; that defeats the purpose of the module.Here's an abbreviated version of my code;
class Tree
include Enumerable
...
# Overwrite #each, and give it the algorithm argument.
def each(algorithm = :pre_order, &block)
if TRAVERSAL_ALGORITHMS.include? algorithm
self.send(algorithm, &block)
else
self.method_missing(algorithm)
end
end
def pre_order(&block)
yield self
self.branches.each do |branch|
branch.pre_order(&block)
end
end
def post_order(&block)
...
end
def breadth_first(&block)
...
end
end
I want to call things like this;
tree.find(13, :breadth_first)
tree.any?(:post_order) do |node|
node.root >= 10
end
I am so silly.
The method #enum_for
gives me all the power here. I can implement Charlie's syntax of
tree.breadth_first.find(13)
by adding the conventional line
return self.enum_for(__method__) unless block_given?
in each of my traversal methods. The tree.breadth_first
will return an Enumerator
which enumerates according to the breadth-first algorithm; any Enumerable
method called on that will use that enumeration internally.