This document discusses how to write your own domain-specific language (DSL). It begins by defining what a DSL is - a language designed for a particular domain that allows for more expressive communication within that domain.
It then covers the key aspects of writing a DSL, including parsing the DSL into an abstract syntax tree using a parser generator like DSL::Maker, validating the parsed structure follows the rules of the language, and producing output from the validated structure.
An example DSL for defining vehicle data is used to demonstrate these concepts. The document concludes by noting that production from a parsed DSL structure is left to the developer and encourages an outside-in, multi-pass approach to transformation.
5. What is a DSL?
● Domain-Specific Language
● Language - A vehicle for communication
6. What is a DSL?
● Domain-Specific Language
● Language - A vehicle for communication
● Domain - A restrained set of concepts
7. What is a DSL?
● Domain-Specific Language
● Language - A vehicle for communication
● Domain - A restrained set of concepts
● Specific - Limited to.
8. What is a DSL?
● Domain-Specific Language
● Language - A vehicle for communication
● Domain - A restrained set of concepts
● Specific - Limited to.
○ No, really. :)
11. Language and Communication
● Communicate in three directions
○ Author -> Executor
○ Author -> Maintainer
○ Specifier -> Author
12. Language and Communication
● Communicate in four directions
○ Author -> Executor
○ Author -> Maintainer
○ Specifier -> Author
○ Author -> Verifier
13. Language and Communication
● Communicate in MANY directions
○ Author -> Executor
○ Author -> Maintainer
○ Specifier -> Author
○ Author -> Verifier
○ Author -> Teammate(s)
○ Developer -> Sysadmin/Devops
○ … -> …
14. Language and Communication
● Communicate in MANY directions
○ Author -> Executor
○ Author -> Maintainer
○ Specifier -> Author
○ Author -> Verifier
○ Author -> Teammate(s)
○ Developer -> Sysadmin/Devops
○ … -> …
The ONLY
computer
15. Language and Communication
● Communicate in MANY directions
○ Author -> Executor
○ Author -> Maintainer
○ Specifier -> Author
○ Author -> Verifier
○ Author -> Teammate(s)
○ Developer -> Sysadmin/Devops
○ … -> …
All humans
16. Language and Communication
● Communicate in MANY directions
○ Author -> Executor
○ Author <-> Maintainer
○ Specifier <-> Author
○ Author <-> Verifier
○ Author <-> Teammate(s)
○ Developer <-> Sysadmin/Devops
○ … <-> …
All human
communication
is two-way
17. Domain-Specific
● Eskimos supposedly have 50+ words for
“snow”
○ Depends on how you count it
● Saami has 1000+ words dealing with
reindeer
○ snarri - a reindeer with short, branched horns
○ busat - a bull with a single, large testicle
19. DSLs you already use
● SQL
○ set manipulation DSL
● CSS
○ tree-visitor-defining DSL for setting metadata
● HAML
○ HTML-definition DSL
● Bash
○ A crappy way of issue shell commands with logic
20. Places for a DSL
● Packaging and orchestration
○ most devops/operations activities
● Configuration file generation
○ web servers
○ monitoring
○ datastores
● Configuration value management across environments
● Anything extremely complicated (such as SQL)
● Anything repetitive (such as CSS)
21. Reasons for a DSL
● Let the important things shine
● General-purpose is overly-verbose
● Bugs hide in boilerplate
● Non-developers can read and comprehend
○ And maybe even propose changes through PRs?
34. Writing a DSL - Validation
● DSL::Maker for parsing
● DSL::Maker for validation
35. . . .
class VehicleDSL < DSL::Maker
. . .
add_validation(:car) do |car|
unless car.engine
return “Cars must have an engine”
end
end
end
car {
make ‘Accord’
year 1990
engine {
hemi Yes
}
}
car ‘Civic’ {
year 2014
}
36. . . .
class VehicleDSL < DSL::Maker
. . .
add_validation(:car) do |car|
unless car.engine
return “Cars must have an engine”
end
end
end
car {
make ‘Accord’
year 1990
engine {
hemi Yes
}
}
car ‘Civic’ {
year 2014
}
37. #!/usr/bin/env ruby
require ‘vehicle/dsl’
filename = ARGV.shift ||
raise “No filename provided.”
# This raises the error
vehicles = Vehicle::DSL.parse_dsl(
IO.read(filename),
)
# Do something here with vehicles
Error: Cars must have an engine
38. Writing a DSL - Production
● DSL::Maker for parsing
● DSL::Maker for validation
● You’re on your own for production
39. Writing a DSL - Production
● Work from outside in.
○ Parsing is done inside-out.
● Transform in a series of passes.
○ Expand everything (it’s just data)
● Don’t do anything irrevocable until the end
○ Work in temp directories, stage everything
40. Conclusion
● DSL::Maker 0.1.0 is available right now
● Patches welcome
○ 100% test coverage
● I’m blogging about this at http:
//streamlined-book.blogspot.com
○ First post on the topic