This post is the first of two focusing on the implementation of a binary search tree in Ruby. This first part will deal with adding elements to a binary search tree. The second part will cover binary tree traversals.
Let’s jump straight in! After writing the unit tests, I have a first go at the code (I chose to go for a linked implementation rather than an array based one). I end up with this:
class BinaryTree
def add(value)
if @root.nil?
@root = BinaryTreeNode.new(value)
else
@root.add(value)
end
end
end
class BinaryTreeNode
def initialize(value)
@value = value
end
def add(value)
if value < @value
if @left.nil?
@left = BinaryTreeNode.new(value)
else
@left.add(value)
end
else
if @right.nil?
@right = BinaryTreeNode.new(value)
else
@right.add(value)
end
end
end
end
Green light, the unit tests pass. One thing is annoying me though: code duplication! In three places, once in BinaryTree and twice in BinaryTreeNode, I have:
if field.nil? field = BinaryTreeNode.new(value) else field.add(value) end
Wouldn’t it be great to have a method that writes this piece of code for a particular field? Metaprogramming, here we come! I will put this method in a module so that it can be included in both classes.
module BinaryTreeHelper
private
def add_or_create_node(field, value)
if instance_variable_get(field).nil?
instance_variable_set(field,
BinaryTreeNode.new(value))
else
instance_variable_get(field).add(value)
end
end
end
Now I can refactor my classes:
class BinaryTree
include BinaryTreeHelper
def add(value)
add_or_create_node(:@root, value)
end
end
class BinaryTreeNode
include BinaryTreeHelper
def initialize(value)
@value = value
end
def add(value)
add_or_create_node(value < @value ? :@left : :@right,
value)
end
end
Pretty nice, no?

Thursday, March 9th, 2006 at 6:16
Thanks for this really nice article. There are not many resources online that explain Ruby metaprogramming. Nice to see you are doing your bit to change that. Keep up the good work!
Thursday, March 9th, 2006 at 6:20
good one!
Thursday, March 9th, 2006 at 9:56
Thanks guys, now I guess I really have to work on part 2!
Monday, January 1st, 2007 at 5:56
real cool way
Tuesday, March 13th, 2007 at 22:36
Iin my opinion, this is not meta-programming. In this example, the code is merely refactored with a sub-routine replacing calls on objects with a common interface; however, ozone does have a great article on meta-programming: http://ozone.wordpress.com/2006/02/22/rubybeans-a-short-example-of-ruby-metaprogramming/ .
Tuesday, June 5th, 2007 at 23:22
now what about traversing this thing? how would you write an in order traversal?
Saturday, August 21st, 2010 at 4:12
Just curious, why didn’t you just write:
module BinaryTreeHelper
private
def add_or_create node, value
node ? node.add(value) : node = BinaryTreeNode.new(value)
end
end