$30 off During Our Annual Pro Sale. View Details »

Defining DSL in Ruby

Defining DSL in Ruby

Michał Poczwardowski

June 17, 2015
Tweet

More Decks by Michał Poczwardowski

Other Decks in Programming

Transcript

  1. Defining DSL in Ruby
    TRUG 17/06/15

    View Slide

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

    View Slide

  3. DSL
    Domain Specific Language

    View Slide

  4. DSL
    INTERNAL
    ● just embedded in GPL
    (General Purpose Language)
    EXTERNAL
    ● own parser/lexer/syntactic
    tree
    ● examples: SQL

    View Slide

  5. Examples from Ruby world
    ● rspec
    ● factory-girl
    ● chef
    ● sinatra
    ● AR migrations

    View Slide

  6. Why?
    ● easy to read
    ● easy to use by non-programmers
    ● in Ruby… easy to implement!

    View Slide

  7. Potential project
    ● DSL for defining online surveys
    ● All questions specified just using a DSL instead of
    complicated forms

    View Slide

  8. 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

    View Slide

  9. Result

    View Slide

  10. How?

    View Slide

  11. 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

    View Slide

  12. QuestionBuilder
    class QuestionBuilder
    def text(content)
    @text = content
    end
    def answer_option(label)
    @answer_options << label
    end
    end

    View Slide

  13. 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

    View Slide

  14. 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
    "

    View Slide

  15. Result
    --- !ruby/struct:Question
    text: Where do you live?
    answer_options:
    - :gdansk
    - :gdynia
    - :sopot

    View Slide

  16. docile gem
    Docile turns any Ruby object into a DSL.
    Especially useful with the Builder pattern.

    View Slide

  17. 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

    View Slide

  18. 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

    View Slide

  19. Thanks!

    View Slide