You can make this very easy with the Docile gem, either by using the gem, or by reading the source code in order to understand how it works.
Say you want to make a Pizza via a DSL
Pizza = Struct.new(:cheese, :pepperoni, :bacon, :sauce)
And you use a builder pattern to make the Pizza
class PizzaBuilder
def cheese(v=true); @cheese = v; end
def pepperoni(v=true); @pepperoni = v; end
def bacon(v=true); @bacon = v; end
def sauce(v=nil); @sauce = v; end
def build
Pizza.new(!!@cheese, !!@pepperoni, !!@bacon, @sauce)
end
end
And you want a DSL, say something like
@sauce = :extra
pizza do
bacon
cheese
sauce @sauce
end
# => should return Pizza.new(true, false, true, :extra)
All you have to do is define the pizza method as
require 'docile'
def pizza(&block)
Docile.dsl_eval(PizzaBuilder.new, &block).build
end
And bang, you're done.