Tim Wilde asked how I would build a DSL, given the example that I gave:

task "warn if website is not alive":
every 3.Minutes()
starting now
when WebSite("http://example.org").IsAlive ==false
then:
notify "admin@example.org", "server down!"

Now, I have a small confession to make, I didn't build the DSL for the post, I just thought it up and posted it. Tim has spiked a somewhat nicer implementation of the C# fluent interface, and it was about 250 lines of code, in 8 classes, 6 interfaces.

Face with that, I felt that I had no other choice than to go on and build a DSL implementation. If fact, I think that this is a good exercise of DSL building. We have started from the required syntax, and then we see how we can implement it.

I had to make two modifications to the DSL in order to make it really work, I marked them in red. One was that I wanted to implement the DSL in C#, and it has no way to write an indexed property, which I need in order to create extension properties in Boo, something that Boo completely supports. It was an interesting insight. The second was that the is operator is for reference types, not for values types, so I changed the IsAlive is false to IsAlive == false.

Most of my DSL use the Anonymous Base Class pattern. This means that you need to imagine a base class that wraps the code in this class. This is a really simple DSL, and I wanted to introduce as little complexity as possible, so we just use the basic capabilities of the language.

There are several interesting things that are going on in the DSL. For a start, we are using Boo's ability to drop parenthesizes if needed, which gives us a more "keyword" feeling. Another interesting approach is that when the last parameter of a method is a delegate, we can use just create a block and use that as a way to create the delegate.

The "when" keyword is a lot more interesting. We want to do late evaluation of the expression that we pass to the when keyword, but the language doesn't allow us to do so. This is where the real power of Boo comes into place, we simply change the language.

To my knowledge, this type of transformations is not available in other languages. In fact, while I am certainly not a Ruby expert, I do not believe that this is possible in Ruby. (Let us see if this brings the mob out of the woodworks, shall we?)