How to write a clean Ruby DSL - Part I: Why?

Send to friend

DSLs (domain specific languages) are a great way to make your app obvious – both obvious to understand, and obvious to maintain.

This series of posts will look at the power of DSLs, look at a plugin called Machinist, and then implement a simple example in Ruby.

The ever-wordy Wikipedia defines a DSL as:

A programming language or specification language dedicated to a particular problem domain, a particular problem representation technique, and/or a particular solution technique.

Here’s an example of how much nicer a good dsl can make your code can look:

A lame dsl:

1
2
3
4
5
6
7

c = ChessGame.new
p = Piece.new("white_pawn_1")
c.positions["white_pawn_1"] = "a3"
c.update_positions!
# etc

Versus a nicer dsl:

1
2
3
4
5
6
7
8

ChessGame.new do |move|
  move.black_pawn(forward)
  move.white_pawn(forward)
  #…
  move.white_queen(pwn_king)
end

My chess_fu is weak, but you get the idea?

Machinist is an even better example. Machinist lets you stop using YAML fixtures, trading this (called with people(:caligula)):

1
2
3
4
5
6
7

Caligula:
   Id: 8
   Name: caligula
   Birthday: 3-16-0037
   Likes: fire

to:

1
2
3
4
5
6
7

Person.blueprint do 
  name {Sham.name}
  birthday {Sham.date}
  likes {Sham.likes}
End

And then calling it with Person.make(:name => ‘caligula, :likes => ‘fire’).

So, as we see above, two keys to a nice Ruby dsl are blocks and syntactic sugar. In the next part, we’ll quickly look at how Machinist does this.

  • Technology: