0
0
Rubyprogramming~7 mins

DSL building patterns in Ruby

Choose your learning style9 modes available
Introduction

A DSL (Domain Specific Language) helps you write code that reads like plain English for a specific task. Building DSLs makes your code easier to understand and use for that task.

You want to create a simple way for users to configure settings without complex code.
You need a readable way to describe workflows or rules in your program.
You want to hide complicated logic behind easy-to-use commands.
You are building a testing framework that reads like natural language.
You want to make your code more expressive and self-explanatory.
Syntax
Ruby
class MyDSL
  def initialize(&block)
    instance_eval(&block) if block_given?
  end

  def command(arg)
    # do something with arg
  end
end

MyDSL.new do
  command 'example'
end

Use instance_eval to run the block in the context of the DSL object.

Define methods that represent commands or keywords in your DSL.

Examples
This DSL lets you say hello in a simple way.
Ruby
class GreetingDSL
  def initialize(&block)
    instance_eval(&block) if block_given?
  end

  def say(text)
    puts "Hello, #{text}!"
  end
end

GreetingDSL.new do
  say 'world'
end
This DSL collects settings in a hash for easy access.
Ruby
class ConfigDSL
  attr_reader :settings

  def initialize(&block)
    @settings = {}
    instance_eval(&block) if block_given?
  end

  def set(key, value)
    @settings[key] = value
  end
end

config = ConfigDSL.new do
  set :color, 'blue'
  set :size, 10
end

puts config.settings
This DSL defines tasks and runs them in order.
Ruby
class TaskDSL
  def initialize(&block)
    @tasks = []
    instance_eval(&block) if block_given?
  end

  def task(name, &block)
    @tasks << {name: name, action: block}
  end

  def run_all
    @tasks.each { |t| t[:action].call }
  end
end

workflow = TaskDSL.new do
  task 'clean' do
    puts 'Cleaning...'
  end
  task 'build' do
    puts 'Building...'
  end
end

workflow.run_all
Sample Program

This program builds a simple DSL to collect messages and then print them.

Ruby
class SimpleDSL
  def initialize(&block)
    @messages = []
    instance_eval(&block) if block_given?
  end

  def add_message(text)
    @messages << text
  end

  def show_messages
    @messages.each { |msg| puts "Message: #{msg}" }
  end
end

my_dsl = SimpleDSL.new do
  add_message 'Hello'
  add_message 'DSL'
  add_message 'World'
end

my_dsl.show_messages
OutputSuccess
Important Notes

Use instance_eval carefully because it changes the context to the DSL object.

Keep DSL commands simple and focused on the domain task.

Test your DSL with real examples to make sure it reads naturally.

Summary

DSLs make code easier to read and write for specific tasks.

Use instance_eval to run blocks inside your DSL object.

Define clear methods that represent your DSL commands.