Since school has been back in, I've been much busier than (seemingly) ever. I haven't had the opportunity to do some of the things I've wanted (such as writing more in TDDing xorBlog), but I wanted to share my Wizard, which you can teach to learn spells. I should also note that this is the product of work with my partner, Clayton Smith.
We were given the assignment as a few unit tests:
require 'wizard'
require 'test/unit'
class WizardTest < Test::Unit::TestCase
def setup
@wiz = Wizard.new
end
def test_teach_one_spell
got_here = false
@wiz.learn('telepathy') { puts "I see what you're thinking"; got_here = true}
@wiz.telepathy
assert(got_here)
end
def test_teach_another_spell
got_here = false
spell_code = lambda { puts "no more clouds"; got_here = true}
@wiz.learn('stop_rain', &spell_code)
@wiz.stop_rain
assert(got_here)
end
def test_teach_a_couple_of_spells
got_here1 = false
got_here2 = false
@wiz.learn('get_what_you_want') { |want| puts want; got_here1 = true }
@wiz.learn('sleep') { puts 'zzzzzzzzzzzz'; got_here2 = true}
@wiz.get_what_you_want("I'll get an 'A'")
@wiz.sleep
assert(got_here1 && got_here2)
end
def test_unknown_spell
@wiz.learn('rain') { puts '...thundering...' }
assert_raise(RuntimeError, "Unknown Spell") {@wiz.raln }
end
end
We simply had to make the tests pass:
class Wizard
def initialize()
@spells=Hash.new
end
def learn(spell, &code)
@spells[spell]=code
end
def method_missing(method_id, *args)
begin
@spells["#{method_id}"].call(args)
rescue
raise("Unknown Spell")
end
end
end
Basically, all that happens is that when you create a
Wizard
, the
initialize()
method is called, and it creates a
Hash
to store spells in. Then you have a method,
learn()
, which takes as a parameter a block of code and stores that code in the
Hash
. Then when someone calls a method that doesn't exist for an object, Ruby automatically calls the
method_missing()
method. In this method, all I do is try to call the code stored in the hash under the name of the method they tried to call. If that doesn't work, I raise an exception with the message "Unknown Spell." Quite simple to do something so complex. I can't even imagine how I'd do something like that in a more "traditional" language (though, I can't say that I've tried either).
Can you imagine how cool it would be to say, have one programmer who wrote this Wizard into a game, and other programmers who just litter places in the game (in
SpellBooks
, consisting of
Spells
of course) with code that names the spell and specifies what it does? Without even needing to know anything about each other! Instantly extending what a
Wizard
can do, without even having to so much as
think about changing
Wizard
- it's a beautiful world, indeed.
Hey! Why don't you make your life easier and subscribe to the full post
or short blurb RSS feed? I'm so confident you'll love my smelly pasta plate
wisdom that I'm offering a no-strings-attached, lifetime money back guarantee!
Leave a comment
There are no comments for this entry yet.
Leave a comment