I love programming in Ruby. It’s amazing how powerful and expressive the
language can be. One of the best parts about Ruby is how easy it is to
whip up a DSL (Domain Specific Language) to help clean up you code and
hopefully make it more enjoyable (readable, understandable) to work
with. I recently had the chance to cleanup some messy, hard to
understand code with a really simple and easy to understand DSL and I
thought it might be useful to share the basics doing something like
this.
What We’re Working With
For this example lets say you’re writing some code that builds an html
page. Lets say you have a class for each html element and a page is made
up of a heiarchy of these html elements. The code to build a simple page
might look something like this:
Okay, so you might not actually do something like this in reality but if
you did and you were defining a bunch of pages and wanted to adjust each
of them it would probably get confusing really fast. Even this simple
example is a little hard to read as is…the Input is in the Form? Oh ya,
it’s in the wrapper Div which is inside the Form. Confusing!
What will the DSL Look Like?
When I’m looking at some ugly code that I want to clean up I like to
step back a little and write some code the way I want it to look and
then work on making my DSL or whatever work towards that goal.
I would much rather be writing the stuff about in a way that looks
something like this:
To me something like that is a lot easier to follow, especially with
something hierarchical like html or xml.
So that’s all well and good, but this looks pretty different than the
code we had earlier, it might be a lot of work to build something to do
this. Is it really work all that effort just so our code looks a little
better? In all honesty it depends on the situation. If you have code
like this on one little spot it might not be worth the effort. But
writting a lot of unclear code all over the place then replacing it with
a readable DSL will gain you many High Fives from future developers.
Besides, it really isn’t that much work and DSLs are too cool to pass
up, so lets get to it.
Building the DSL
Lets start out with something simple that will just define and return a
couple of our elements.
This little bit of code gives us the main structure of our DSL. It
doesn’t quit work yet since there’s no way to set the parent attribute
on each of the elements. Lets take care of that.
Okay, wo what I’m doing here is just keeping track of whatever the
current container element is and setting it to @current so that the
elements being defined within the block can set it’s parent attribute.
Lets take a look at what using our DSL might look like so far:
That looks pretty close now! I have to be honest though, I cheated and
made a little change so that this would be possible:
So I moved the page method outside of our DSL class and made it create
an instance of HTMLPageDSL. We then call instance_eval giving the
HTMLPageDSL object the block to evaluate.
The last thing I want to do is add a bit of syntax magic so we don’t
have to type quite as much. At the moment we’re passing all the
attributes as a hash, but in my initial example I could pass some
options directly, without a hash.
First we add the following methods to HTMLPageDSL
After that we can use it in our DSL methods to let us pass array
arguments or a hash to the method call.
And that’s it. Now we can pass the type as the first argument to the
call to input and any other options as a hash, or everything as a hash
if we want.
Conclusion
So there we have it, a nice simple example of creating a DSL. This
example isn’t perfect, that’s for sure, but it does show how to get
started and how simple it can be.
Comments
comments powered by Disqus