Предметно-орієнтована мова (DSL) - це невелика мова, оптимізована для конкретної предметної області. Оскільки DSL має конкретне призначення, вона може суттєво підвищити продуктивність і полегшити розуміння, дозволяючи авторові оголосити що він хоче, а не як.
Однією з проблемних областей, де їх застосовують, є складні налаштування та конфігурації.
Наприклад, мова DOT дозволяє записати текстовий опис графа, який потім перетворює на зображення один з інструментів Graphviz (наприклад, dot).
Простий граф має такий вигляд:
graph {
graph [bgcolor="yellow"]
a [color="red"]
b [color="blue"]
a -- b [color="green"]
}
Якщо помістити це у файл example.dot і виконати dot example.dot -T png -o example.png, отримаємо зображення example.png, де червоний і синій кружечки зʼєднані зеленою лінією на жовтому тлі.
Напишіть предметно-орієнтовану мову, подібну до мови dot від Graphviz.
Наша DSL подібна до мови dot від Graphviz тим, що нашу DSL будемо використовувати для створення структур даних графів. Однак, на відміну від мови DOT, наша DSL буде внутрішньою DSL, призначеною лише для використання в нашій мові.
Дізнаймося більше про різницю між внутрішніми та зовнішніми DSL.
У цій вправі ми цілком вільні спроєктувати графовий DSL своєї мрії.
Можливо, нам захочеться створити DSL на основі списків тегів і записів, ось так:
my_graph =
Graph.create([
Title("My Graph"),
Node("a", { color: Green }),
Node("b", { color: Blue }),
Edge("a", "b", { style: Dotted }),
])
Або, можливо, нам більше до вподоби DSL на основі ланцюжків викликів функцій, ось так:
my_graph =
Graph.create()
.with_title("My Graph")
.add_node("a", Attr.create().with_color(Green))
...
А може, у нас зовсім інший план? Тож берімося! Тести вимагають лише створити кілька конкретних графів, а як ми їх будуємо, цілком залежить від нас.
Утім, DSL зазвичай кращий, якщо він зрозумілий, лаконічний і не надто несподіваний (наприклад, функція minus призначена для віднімання, а не для побудови ребра між двома вузлами, як у node("a") - node("b")).
Щоб подвоїти задоволення, можемо за бажанням спробувати реалізувати функцію to_dot, яка перетворює наш граф на формат DOT!