A Domain Specific Language (DSL) is a computer language targeted to a particular kind of problem or application domain. There are various ways to implement a DSL in Ruby: classic blocks, instance_eval or mixins and extend. Most often instance_eval is used. How does it work? First one has to define the DSL itself, for example in a class like the this:

class MyDsl
  def initialize
    @local_var = 1
  end

  def method_1
    puts "#{@local_var}+1=#{@local_var += 1}"
  end

  def method_2
    puts "says your DSL method"
  end
end

then one can apply the dsl to an object:

MyClass.apply_dsl(MyDSL) do |obj|
  obj.method_1()
  obj.method_2()
end

We only need the define an “apply_dsl” method. The first option is to use simple Ruby blocks to apply the DSL:

class MyClass
  def self.apply_dsl(a_class, &block)
    yield a_class.new if block_given?
  end
end

The second option is to use instance_eval to apply the DSL:

class MyClass
  def self.apply_dsl(a_class, &block)
    dsl = a_class.new
    dsl.instance_eval &block if block_given?
  end
end

Or one can use mixins and extend..

class MyClass
  def self.apply_dsl(a_module)
    obj = MyClass.new
    obj.extend(a_module)
    obj.init
    yield obj if block_given?
  end
end

but then one would use modules instead of classes:

module MyDSL
  def init
    @i = 1
  end

  def method_1
    puts "#{@i}+1=#{@i += 1}"     
  end

  def method_2
    puts "says your DSL method"
  end
end
Advertisements