1
0
Fork 0
mirror of https://github.com/ms-ati/docile synced 2023-03-27 23:21:52 -04:00

added Pizza/PizzaBuilder to docs and to specs

This commit is contained in:
Marc Siegel 2011-12-06 18:41:43 -05:00
parent 1f62e56f54
commit bce3530787
2 changed files with 42 additions and 14 deletions

View file

@ -3,7 +3,8 @@
Definition: *Ready to accept control or instruction; submissive* [[1]]
Tired of overly complex DSL libraries and hairy meta-programming?
Let's make our Ruby DSLs more *docile*...
Let's make our Ruby DSLs more docile...
[1]: http://www.google.com/search?q=docile+definition "Google"
@ -15,31 +16,36 @@ Let's treat an Array's methods as its own DSL:
Docile.dsl_eval [] do
push 1
push 2
pop
push 3
end
#=> [1, 3]
```
Mutating (changing) the array is fine, but what you probably really want as your DSL is actually a [Builder Pattern][2].
For example, if you have a PizzaBuilder class that can build a pizza:
For example, if you have a PizzaBuilder class that can already build a Pizza:
``` ruby
@sauce_level = :extra
pizza = PizzaBuilder.new.cheese.pepperoni.bacon.sauce(@sauce_level).build
pizza = PizzaBuilder.new.cheese.pepperoni.sauce(@sauce_level).build
#=> #<Pizza:0x00001009dc398 @cheese=true, @pepperoni=true, @bacon=false, @sauce=:extra>
```
Then you can use this PizzaBuilder class as a DSL:
Then you can use this same PizzaBuilder class as a DSL:
``` ruby
@sauce_level = :extra
pizza = Docile.dsl_eval PizzaBuilder.new do
cheese
pepperoni
bacon
sauce @sauce_level
end.build
#=> #<Pizza:0x00001009dc398 @cheese=true, @pepperoni=true, @bacon=false, @sauce=:extra>
```
It's just that easy!
[2]: http://stackoverflow.com/questions/328496/when-would-you-use-the-builder-pattern "Builder Pattern"
## Features
@ -47,6 +53,7 @@ end.build
1. method lookup falls back from the DSL object to the block's context
2. local variable lookup falls back from the DSL object to the block's context
3. instance variables are from the block's context only
4. nested dsl evaluation
## Installation

View file

@ -4,6 +4,36 @@ describe Docile do
context :dsl_eval do
it "should return the DSL object" do
Docile.dsl_eval([]) do
push 1
push 2
pop
push 3
end.should == [1, 3]
end
Pizza = Struct.new(:cheese, :pepperoni, :bacon, :sauce)
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
it "should handle a Builder pattern" do
@sauce = :extra
Docile.dsl_eval(PizzaBuilder.new) do
bacon
cheese
sauce @sauce
end.build.should == Pizza.new(true, false, true, :extra)
end
class InnerDSL
def initialize; @b = 'b'; end
attr_accessor :b
@ -21,15 +51,6 @@ describe Docile do
Docile.dsl_eval(OuterDSL.new, &block)
end
it "should return the DSL object" do
Docile.dsl_eval([]) do
push 1
push 2
pop
push 3
end.should == [1, 3]
end
context "methods" do
it "should find method of outer dsl in outer dsl scope" do
outer { a.should == 'a' }