Slide 1

Slide 1 text

Defining DSL in Ruby TRUG 17/06/15

Slide 2

Slide 2 text

Michal Poczwardowski Ruby on Rails developer [email protected] [email protected]

Slide 3

Slide 3 text

DSL Domain Specific Language

Slide 4

Slide 4 text

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

Slide 18

Slide 18 text

Resources https://en.wikipedia.org/wiki/Domain-specific_language https://robots.thoughtbot.com/writing-a-domain-specific-language-in-ruby http://ms-ati.github.io/docile/ http://radar.oreilly.com/2014/04/make-magic-with-ruby-dsls.html

Slide 19

Slide 19 text

Thanks!