DSL
INTERNAL
● just embedded in GPL
(General Purpose Language)
EXTERNAL
● own parser/lexer/syntactic
tree
● examples: SQL
Slide 5
Slide 5 text
Examples from Ruby world
● rspec
● factory-girl
● chef
● sinatra
● AR migrations
Slide 6
Slide 6 text
Why?
● easy to read
● easy to use by non-programmers
● in Ruby… easy to implement!
Slide 7
Slide 7 text
Potential project
● DSL for defining online surveys
● All questions specified just using a DSL instead of
complicated forms
Slide 8
Slide 8 text
Survey DSL
01: survey :trug_questions do
02: title 'A few questions about TRUG'
03: question :city, kind: :single_choice do
04: text 'Where do you live?'
05: answer_option :gdansk
06: answer_option :gdynia
07: answer_option :sopot
08: end
09: end
Slide 9
Slide 9 text
Result
Slide 10
Slide 10 text
How?
Slide 11
Slide 11 text
Question + QuestionBuilder
Question = Struct.new(:text, :answer_options)
class QuestionBuilder
def initialize
@text = 'Unset Text'
@answer_options = []
end
def build
Question.new(@text, @answer_options)
end
end
Slide 12
Slide 12 text
QuestionBuilder
class QuestionBuilder
def text(content)
@text = content
end
def answer_option(label)
@answer_options << label
end
end
Slide 13
Slide 13 text
instance_eval
def build_question(&block)
builder = QuestionBuilder.new
builder.instance_eval(&block)
builder.build
end
build_question do
text 'Where do you live?'
answer_option :gdansk
answer_option :gdynia
answer_option :sopot
end
Slide 14
Slide 14 text
It may be a string
def build_question(dsl_string)
builder = QuestionBuilder.new
builder.instance_eval(dsl_string)
builder.build
end
build_question "
text 'Where do you live?'
answer_option :gdansk
answer_option :gdynia
answer_option :sopot
"
Slide 15
Slide 15 text
Result
--- !ruby/struct:Question
text: Where do you live?
answer_options:
- :gdansk
- :gdynia
- :sopot
Slide 16
Slide 16 text
docile gem
Docile turns any Ruby object into a DSL.
Especially useful with the Builder pattern.
Slide 17
Slide 17 text
docile gem
01: with_array([]) do
02: push 1
03: push 2
04: pop
05: push 3
06: end
#=> [1, 3]
def with_array(arr=[], &block)
Docile.dsl_eval(arr, &block)
end