Parsing a DSL in Ruby in less than 30 LoC

Mehdi Farsi
Apr 15, 2019 · 3 min read

In this article we’re going to see how to parse and serialize a DSL in less than 30 lines of codes.

To do so, we are going to parse the Retaurant Order DSL through the Orders file.

Before to start

I’m thrilled to share with you our latest project: Fun Facts about Ruby — Volume 1

Please feel free to spread the word and share this post! 🙏

Thank you for your time!

Orders dispatcher

The goal here is to be able to parse and serialize the content of the Orders file.

Then this serialization can be passed to our engine that is in charge of controlling the execution flow and processing the commands.

So let’s see how our Orders file looks like:

Here we can see that our DSL is composed of 2 commands: order_now and schedule.

The first one indicates that the order must be prepared immediately.

The second one indicates that the order preparation is scheduled at a given time.

The OrdersDsl class

All the parsing and serialization logic is defined in the OrdersDsl class.

So, let’s detail step-by-step the content of this class.

First, let’s have a look at the OrdersDsl#initialize method

Here, we define a @commands instance variable.

Then we assign a frozen hash to this instance variable.

In this hash we declare 2 entries

  • to_perform: an array that contains all the serializations of the order_now command
  • to_schedule: an array that contains all the serializations of the schedule command

This hash is frozen because we wont add any other entries at this point.

Now, let’s see how to run our DSL parser.

The OrdersDsl.run method

Let’s implement an OrdersDsl.run class method

Here, the OrdersDsl.run class method instantiates the OrdersDsl class and calls the OrdersDsl#parse method on the freshly created instance.

The #parse method is in charge of parsing and serializing the orders.

The OrdersDsl#parse method

This method reads the content of the Orders file and evaluate it in the context of our instance.

This mean that the commands in the Orders file will be evaluated as messages received by the evaluating scope – in our case, an instance of the OrdersDsl class.

Feel free to have a look to the Private & Protected in Ruby article if you are not familiar with the notion of message in Ruby.

⚠️⚠️

The file that you “evaluate” must be trusted.

Indeed, using eval or instance_eval in an unsafe context can lead to some serious vulnerabilities.

⚠️⚠️

Our instance must respond to these messages.

So we implement the OrdersDsl#order_now and the OrdersDsl#schedule instance methods — with a signature that matches against the commands in the Orders file

These methods will simply serialize an order and push it into the right @orders hash entry.

At this moment, our Orders file has been parsed and the orders have been serialized.

From now, we just have to implement the logic that consume and process these serialized informations.

Note that we could have used a method_missing hook method, to orchestrate the serialization and storage of each order without having to define a method per command of our DSL.

Conclusion

Parsing and serializing the commands of a given DSL is helpful when you want to control the execution flow of the commands — running a specific command before the others whatever their order of appearance in the DSL file.

These 2 operations can be easily and elegantly accomplished in Ruby thanks to the builtins provided by the language.

Voilà!

ONE MORE THING ⬇

Feel free to subscribe here: www.rubycademy.com

Thank you for taking the time to read this post :-)

Feel free to 👏 and share this article if it has been useful for you. 🚀

Also, as I post fews articles per month, feel free to follow me to be notified of my new article releases.

Here is a link to my last article:

Ruby is a multi-paradigm programming language

RubyCademy

E-Learning platform for Ruby and Ruby on Rails

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store