Как вы можете себе представить, Athena использует немало концепций метапрограммирования для реализации своих функций. В следующей главе мы собираемся изучить основную функцию метапрограммирования — макросы.
Дальнейшее чтение
• https://athenaframework.org/EventDispatcher/
• https://athenaframework.org/Console/
• https://athenaframework.org/Routing/
Часть 4: Метапрограммирование
В этой части мы рассмотрим более продвинутые функции и методы метапрограммирования, уделяя особое внимание аннотациям. Эта информация, как правило, недостаточно хорошо документирована. Без дальнейших церемоний давайте рассмотрим, как использовать эти более продвинутые функции.
Эта часть содержит следующие главы:
• Глава 10, Работа с макросами
• Глава 11, Введение в аннотации
• Глава 12, Использование анализа типов во время компиляции
• Глава 13, Расширенное использование макросов
10. Работа с макросами
В этой главе мы собираемся исследовать мир метапрограммирования. Метапрограммирование может быть отличным способом «СУШИТЬ» (DRY) ваш код путем объединения шаблонного кода в фрагменты многократного использования или путем обработки данных во время компиляции для создания дополнительного кода. Сначала мы рассмотрим основную часть этой функции: макросы.
В этой главе мы рассмотрим следующие темы:
• Определение макросов
• Понимание API макросов.
• Изучение макросов.
К концу этой главы вы сможете понять, когда и как можно применять макросы, чтобы уменьшить количество шаблонного кода в приложении.
Технические требования
Для этой главы вам понадобится работающая установка Crystal.
Инструкции по настройке Crystal можно найти в Главе 1 «Введение в Crystal».
Все примеры кода в этой главе можно найти в папке Chapter 10 репозитория GitHub этой книги: https://github.com/PacktPublishing/Crystal-Programming/tree/main/Chapter10.
Определение макросов
В Crystal макрос имеет два значения. Как правило, это относится к любому коду, который запускается или расширяется во время компиляции. Однако, более конкретно, это может относиться к типу метода, который принимает узлы AST во время компиляции, тело которых вставляется в программу в момент использования макроса. Примером последнего является макрос property, который вы видели в предыдущих главах, который представляет собой простой способ определения как метода получения, так и метода установки для данной переменной экземпляра:
class Example
property age : Int32
def initialize(@age : Int32); end
end
Предыдущий код эквивалентен следующему:
class Example
@age : Int32
def initialize(@age : Int32); end
def age : Int32
@age
end
def age=(@age : Int32)
end
end
Как мы упоминали ранее, макросы принимают узлы AST во время компиляции и выводят код Crystal, который добавляется в программу, как если бы он был введен вручную. По этой причине property age: Int32 не является частью конечной программы, а только тем, во что оно расширяется — объявлением переменной экземпляра, методом получения и методом установки. Аналогичным образом, поскольку макросы работают на узлах AST во время компиляции, аргументы/значения, используемые внутри макроса, также должны быть доступны во время компиляции. Сюда входит следующее:
• Переменные среды.
• Константы
• Жестко запрограммированные значения.
• Жестко закодированные значения, созданные с помощью другого макроса.
Поскольку аргументы должны быть известны во время компиляции, макросы не заменяют обычные методы, даже если результат в обоих случаях кажется одинаковым. Возьмем, к примеру, эту небольшую программу:
macro print_value(value)
{{pp value}}
pp {{value}}
end
name = "George"
print_value name
Запуск этой программы приведет к следующему выводу:
name
"George"
Главное, на что следует обратить внимание, — это вывод значения, когда оно находится в контексте макроса. Поскольку макросы принимают узлы AST, макрос не имеет доступа к текущему значению переменной времени выполнения, такой как имя. Вместо этого типом значения в контексте макроса является Var, который представляет локальную переменную или аргумент блока. Это можно подтвердить, добавив в макрос строку, состоящую из {{pp value.class_name}}, которая в конечном итоге напечатает "Var”. Мы узнаем больше об узлах AST позже в этой главе.