I read a few posts about how good fit Ruby is for building DSLs, Domain Specific Languages. Ever the curious I have been waiting for the opportunity to build a very simple one for a particular problem.
Well, I did not have to wait very long (when you have a hammer everything looks like a nail). I needed a quick method which generates nice html graphs for my post about browser javascript engine benchmarking. After spending a few minutes searching for a free tool (I did not want anything fluffy, just something very basic) I hit the nail in the head with my hammer. Only the nail was the generated HTML charts for my post and the hammer, (my desire to build) a DSL in Ruby.
I would like to say it was difficult but in fact it was a piece of cake with Ruby (and armed with the knowledge of previous DSL builders). The solution is composed of the following three parts:
- The DSL file which defines the charts
- The interpreter which understands the definitions in the DSL file
- The “controller” which just passes the data contained in the DSL file to the interpreter
So let’s see each part separately:
browser_js_benchmarks.dsl (the DSL)
chart "Score" do |c|
c.add "Safari 3.1.2" => 164
c.add "Firefox 3.0.1" => 156
c.add "Shiretoko" => 145
c.add "Google Chrome" => 1589
end
chart.rb (the interpreter)
require "math_aux"
class ChartDSL
Template = %(
chart_loader.rb (the controller)
require "chart"
class ChartLoader
def self.load_chart(dsl_filename)
c = ChartDSL.new
c.load(dsl_filename)
end
end
if __FILE__ == $0
ChartLoader.load_chart(ARGV[0])
end
For the sake of completeness here is math_aux.rb:
module MathAux
def self.normalize(numbers, to=1.0)
norm_rat = to / numbers.max
numbers.map { |n| n * norm_rat }
end
end
To generate the charts, one only has to run “the interpreter” with a dsl file as the first parameter:
ruby chart_loader.rb browser_js_benchmarks.dsl
The output is called generated_charts.html and contains the following:
Google Chrome | 1589 | |
Safari 3.1.2 | 164 | |
Firefox 3.0.1 | 156 | |
Shiretoko | 145 |
Note that in ~30-40 code lines we have a “language interpreter”, one that understands the chart DSL and spits out some HTML code that represents the charts. Of course there is plenty of room for improvement, like having the same color denote the same actor between charts (Firefox 3.0.1 should always be the blue bar, for example, unlike in my post), using a better solution for the template strings, adding the possibility of pie charts (although “standard” HTML is not very flexible on different chart forms, one would probably have to use a <canvas> ), and so on.
The essential thing is that it works and it does what the particular situation demanded. It took me a couple of interrupted hours plus the time to read through two related posts which is not that much given that I now have a “tool” (once again, I feel a bit conceited to call it that) which I can use for my future posts whenever the need arises. A custom hammer for my custom nail.
(If you care, feel free to download, use and modify the source code located here)