Posted over 3 years ago. Visible to the public.

Advanced Ruby: Metaprogramming and DSLs

Rubymonk training

Read the following Rubymonk articles:

For each chapter in each article:

  • Play with the introduced Ruby feature using a simple Ruby script or IRB console
  • Talk with your mentor what you learned.

Exercise: Roll your own DSL

This entire exercise should be implemented using pure Ruby, without any gems.

Write an Addressbook class that can be used like this:

Copy
book = Addressbook.new book.add_contact 'Henning Koch' book.add_contact 'Tobias Kraze' book.contacts # => ['Henning Koch', 'Tobias Kraze']

Now change Addressbook so contacts can be defined with a custom DSL:

Copy
book = Addressbook.parse do contact 'Henning Koch' contact 'Tobias Kraze' end book.contacts # => ['Henning Koch', 'Tobias Kraze']

Now allow each contact to have a phone and email attribute:

Copy
book = Addressbook.parse do contact 'Henning Koch' do phone '12345' email 'foo@bar.de' end contact 'Tobias Kraze' do phone '67890' email 'bam@baz.de' end end book.find('Henning Koch') # => { :phone => '12345', :email => 'foo@bar.de' } book.find('Tobias Kraze') # => { :phone => '67890', :email => 'bam@baz.de' }

Now change Addressbook so contacts can be accessed by their underscored names:

Copy
book.henning_koch # => { :phone => '12345', :email => 'foo@bar.de' } book.tobias_kraze # => { :phone => '67890', :email => 'bam@baz.de' }

Now change Addressbook so each contact becomes their own Contact instance which responds to #phone and #email:

Copy
book.henning_koch # => Contact<#....> book.henning_koch.phone # => '12345' book.henning_koch.email # => 'foo@bar.de'

Now allow arbitrary fields, not just phone and email:

Copy
book = Addressbook.parse do contact 'Henning Koch' do phone '12345' glasses true shirt 'red' end end book.henning_koch.shirt # => 'red'

Exercise: DSL styles

The DSL above could also be implemented using this syntax:

Copy
book = Addressbook.parse do |ab| ab.contact 'Henning Koch' do |c| c.phone '12345' c.glasses true c.shirt 'red' end end book.henning_koch.shirt # => 'red'

Change your implementation to work like this.

What are the advantages of this style of DSL? What are the drawbacks? Which do you prefer?

You have probably encountered examples of both styles before. Name a few.

Owner of this card:

Avatar
Henning Koch
Last edit:
9 months ago
by Henning Koch
Posted by Henning Koch to makandra Curriculum
This website uses cookies to improve usability and analyze traffic.
Accept or learn more