If you’re using the prototype javascript library, its fun to add methods directly to the $() object.
So instead of typing:
new Effect.Move($('target-obj-name'), {x: 40, y: 50, mode: 'absolute'});
new Effect.Pulsate($('target-obj-name'));
You could type:
$('target-obj-name').moveTo(40,50).pulsate();
Much sexier. You could add any methods you want to $() to do anything you need to do in your application. Just reproduce the example below in a Javascript file (say prototype-extensions.js and include it in your web pages, using <script src="prototype-extensions.js"></script>):
Element.Methods.moveTo = function(element,x,y) {
new Effect.Move(element, {x: x, y: y, mode: 'absolute'});
return element;
}
Element.Methods.pulsate = function(element) {
new Effect.Pulsate(element);
return element;
}
Element.addMethods();
The methods you want to add to $() need to be added to the Element.Methods hash (so in the example above, Element.Methods.moveTo and Element.Methods['moveTo'] are equivalent in Javascript), with the first argument of the function being the target element.
Finally, you need to formally tell Prototype that these methods must be added into future $() objects, using the command Element.addMethods().
Now you can add any method to your $() objects that you want. Just like magic.
Late in the night, whilst the baby feeds, I continue to develop Dr Nic’s Civilizations game. This led me to develop a DSL for the specification of game rules. You need to see this.
Here’s an example definition of some terrain:
class Desert < Terrain
title "Desert"
letter "d"
graphic "desert"
movement_cost 1
defense_bonus 10
food 0
shield 1
trade 0
end
class Oasis < Desert
title "Oasis"
special_code 1
food 3
shield 1
trade 0
graphic "oasis"
end
An Oasis is a special version of the Desert terrain, so Ruby subclasses offer a compatible relationship.
This is seriously cool. All in Ruby.
Why write a DSL for something trite like game rules?
The descriptions of terrain (plains, hills, ocean), the improvements (roads, irrigation, mines), etc. all need defining somewhere. Here are the standard options:
- Rows in a database, imported into ActiveRecords at startup
- Files that are loaded at startup, parsed and converted into an internal data model
- Ruby DSL
The sort of configuration we're dealing with is static: its a part of the game design to a certain extent. Yes, I could put the configuration in a database and access/modify it via an admin console, though version control becomes an additional administrative hassle.
Storing game rule configuration in external files makes version control trivial, though there is a one-time cost of implementing special purpose syntax, parsers, internal game data models and testing.
A Ruby DSL is exactly the same as implementing option 2 - the configuration is stored in files, though as the syntax is pure Ruby, there is no need to implement a parser and internal data model.
There was a one time cost for supporting the syntax. But why the lucky stiff paid this cost for me with his traits definition for slaying dragons [1]. So I was free and clear of any actual effort.
"Yes, smart arse, but you still had to write up all those Ruby classes"
An irrelevant argument, you'd have to enter the configuration for any of the 3 options, but...
I wrote a generator to build the Ruby class definitions for me from the Freeciv's GPL rule sets. Sweet.
[1] The definition of the Terrain class, using the traits mechanism, is simple:
class Terrain
traits :title,
:letter,
:graphic,
:movement_cost,
:defense_bonus,
:food,
:shield,
:trade,
:special_code
end
Ever tried to explain DSLs (domain specific languages) to someone, so that they know how wonderful Ruby is, and just run out of useful examples? Try this piece of Street Magic on them…
The effect
See if your unsuspecting friend can figure out what this code will do. If they can, then say, “That’s because you are a domain expert in English. Good for you. Now use Ruby you Java boy.”
>> I.say "I love the Ruby language"
You said, 'I love the Ruby language'
Cool, yes? Yes.
How this trick works
To set this up for your unsuspecting Ruby noob, type the following into your console/irb:
>> class I; def self.say(text); puts "You said, '#{text}'"; end; end
=> nil
Now you have a constant I upon which you can call class methods.
In long hand, this is:
class I
def self.say(text)
puts "You said, '#{text}'"
end
end
Create other pronoun classes, such as You, Everyone, etc and give them methods representing verbs, such as say, said, want_to.
For example,
class You
def self.cannot(action, target)
puts "Didn't your mother tell you never say never? Of course you can #{action} #{target}"
end
end
Which delights us with:
>> You.cannot :learn, "Ruby"
Didn't your mother tell you never say never? Of course you can learn Ruby
“I still don’t know what a DSL is”
That’s unfortunate for you.
Australia and New Zealand celebrate Father’s Day on the first Sunday in September. Although we’re in Netherlands, my new son didn’t care and he went out and bought me some great gifts – all of which I’m wearing here – a dressing gown for late night nappy changes, a pair of boxer shorts (unseen) with “My hero” on them, and a nifty straw hat!

Steve Irwin died today after 44 years of passion, thrills, and excitement. Most software programmers are too scared to learn a new programming language.
I’ll miss you Steve.