R
Ruby Quiz
Brian Schroder said:
I always wanted to learn more about the reflection capabilites of ruby,
and indeed there is quite a lot to learn. This quiz was not too
complicated, but the design of a good gui takes a lot of time.
(Especially if you're not accustomed to the toolkit).
I agree and I think that about summarizes this quiz.
The main point of the quiz is using "reflection". What is reflection? To quote
the Pragmatic Programmers:
...to examine aspects of the program from within the program itself.
Obviously, to write an Object Browser, we would need to be able to learn things
about objects we didn't design and create. This technique has a lot of
practical applications though and odds are even a new Ruby programmer has seen
it in action.
Used tab completion in irb? Built test cases with Test::Unit? Both are great
examples of tools that figure out your intentions by looking at Ruby code.
That's reflection.
So, how do we do all that? I don't want to recreate a bunch of documentation
here, but here are some methods to look up if you're new to Ruby's reflection
capabilities:
ObjectSpace.each_object
Object.class
Object.methods
Object.instance_variables
# and many more in Object
Module.ancestors
Module.constants
Module.class_variables
# and many more in Module
Putting such methods to use is pretty trivial. Here's Brian's (original) code
for building an object tree:
# Class Tree
class ClassTreeNode
attr_accessor :klass, :subclasses, bjects
def initialize(klass)
@klass = klass
@subclasses = {}
@objects = []
end
def add_class(klass)
@subclasses[klass] ||= ClassTreeNode.new(klass)
end
def add_object(object)
@objects << object
self
end
end
# Creates or updates a klass_tree.
# When updating no classes or objects are removed
def object_browser(classtree = ClassTreeNode.new(Kernel))
ObjectSpace.each_object do | x |
classnode = classtree
x.class.ancestors.reverse[1..-1] \
.inject(classtree){ | classnode, klass |
classnode.add_class(klass)
}.add_object(x)
end
classtree
end
object_browser() just assembles a "Class Tree" by walking
ObjectSpace.each_object() and using ancestors() to find parent Classes/Modules.
(Note the clever use of inject(). Isn't that iterator cool?!)
The rest of Brian's solution (not shown) hands that Class Tree off to GUI
routines, to build suitable displays. These routines use more reflection
methods to fetch method and variable lists.
Both solutions use gtk2 to manage their GUIs. That involves no small amount of
code and is a little beyond the scope of this summary, so I'll simply refer you
to the solutions if you want to dig deeper.
I owe a big thanks to Jamis and Brian for pushing the quiz along this weekend
while I was horribly busy.
All teasers for the next quiz have been censored out of this summary.
I always wanted to learn more about the reflection capabilites of ruby,
and indeed there is quite a lot to learn. This quiz was not too
complicated, but the design of a good gui takes a lot of time.
(Especially if you're not accustomed to the toolkit).
I agree and I think that about summarizes this quiz.
The main point of the quiz is using "reflection". What is reflection? To quote
the Pragmatic Programmers:
...to examine aspects of the program from within the program itself.
Obviously, to write an Object Browser, we would need to be able to learn things
about objects we didn't design and create. This technique has a lot of
practical applications though and odds are even a new Ruby programmer has seen
it in action.
Used tab completion in irb? Built test cases with Test::Unit? Both are great
examples of tools that figure out your intentions by looking at Ruby code.
That's reflection.
So, how do we do all that? I don't want to recreate a bunch of documentation
here, but here are some methods to look up if you're new to Ruby's reflection
capabilities:
ObjectSpace.each_object
Object.class
Object.methods
Object.instance_variables
# and many more in Object
Module.ancestors
Module.constants
Module.class_variables
# and many more in Module
Putting such methods to use is pretty trivial. Here's Brian's (original) code
for building an object tree:
# Class Tree
class ClassTreeNode
attr_accessor :klass, :subclasses, bjects
def initialize(klass)
@klass = klass
@subclasses = {}
@objects = []
end
def add_class(klass)
@subclasses[klass] ||= ClassTreeNode.new(klass)
end
def add_object(object)
@objects << object
self
end
end
# Creates or updates a klass_tree.
# When updating no classes or objects are removed
def object_browser(classtree = ClassTreeNode.new(Kernel))
ObjectSpace.each_object do | x |
classnode = classtree
x.class.ancestors.reverse[1..-1] \
.inject(classtree){ | classnode, klass |
classnode.add_class(klass)
}.add_object(x)
end
classtree
end
object_browser() just assembles a "Class Tree" by walking
ObjectSpace.each_object() and using ancestors() to find parent Classes/Modules.
(Note the clever use of inject(). Isn't that iterator cool?!)
The rest of Brian's solution (not shown) hands that Class Tree off to GUI
routines, to build suitable displays. These routines use more reflection
methods to fetch method and variable lists.
Both solutions use gtk2 to manage their GUIs. That involves no small amount of
code and is a little beyond the scope of this summary, so I'll simply refer you
to the solutions if you want to dig deeper.
I owe a big thanks to Jamis and Brian for pushing the quiz along this weekend
while I was horribly busy.
All teasers for the next quiz have been censored out of this summary.