dsl snippets

How to use dual-purpose accessors in Ruby to create a DSL

Tagged ruby, dsl  Languages ruby

Instead of this:

Sitemap('public/sitemap.xml') do
  self.stylesheet = 'public/sitemap.xls'  
  self.ping = ['http://www.google.com', 'http://www.google.com']  
end

You could write this:

Sitemap('public/sitemap.xml') do
  stylesheet 'public/sitemap.xls'  
  ping ['http://www.google.com', 'http://www.google.com']  
end

Using dual-purpose accessors:

class Sitemap
  def stylesheet(path = nil) 
    return @path unless path
   @path = path
  end
  alias_method :stylesheet=, :stylesheet 
  ...
end

Writing a DSL in Ruby

Tagged ruby, dsl, instance_eval, instance_exec  Languages ruby

When defining a simple DSL instance_eval and instance_exec is your friend:

class Worker
  attr_reader :where
  def call(where, &block)
    @where = where
    instance_eval &block
  end

  def cut_trees
    puts "Cutting trees"
  end

  def make_planks
    puts "Making planks"
  end

  def i(what, &block)
    instance_eval &block
  end
end

def work where, &block
  puts "Working #{where}"
  Worker.new.(where, &block)
  puts "Going home"
end

Use the DSL like this:

work "in the woods" do
  cut_trees
  make_planks
  i "take a coffee break" do
    puts "Cooking coffee #{where}"
  end
end

Output is:

Working in the woods
Cutting trees
Making planks
Cooking coffee in the woods
Going home

instance_exec method allows you to pass arguments to your blocks, which instance_eval doesn't allow.