Читать «Crystal Programming. Введение на основе проекта в создание эффективных, безопасных и читаемых веб-приложений и приложений CLI» онлайн
Джордж Дитрих
Страница 48 из 75
Далее мы обрабатываем некоторые контексты ошибок, например, если конечная точка не имеет аннотации шаблона или возвращаемое значение не может быть отображено через Crinja. Я намеренно создаю общие исключения, чтобы возвращался ответ об ошибке 500, поскольку мы не хотим утечки внутренней информации за пределы API.
Наконец, мы используем Crinja для получения шаблона на основе имени в аннотации и его визуализации, используя значение, возвращаемое из действия контроллера, в качестве значения объекта данных. Затем мы используем визуализированное содержимое в качестве тела ответа для ATH::Response, устанавливая тип содержимого ответа на text/html.
Чтобы включить такое поведение, нам просто нужно применить аннотацию @ [Blog::Annotations::Template("article.html.j2")] к нашему методу #article в ArticleController. Мы можем все проверить, сделав еще один запрос:
curl --request GET 'http://localhost:3000/article/1' --header
'accept: text/html'
Ответом в этом контексте должен быть наш HTML-шаблон. Если вы установите заголовок application/json или вообще удалите его, ответом должен быть JSON.
Резюме
И вот она, реализация блога, в которой используются некоторые интересные функции Athena, которые, в свою очередь, сделали реализацию простой и очень гибкой. Мы использовали преобразователи параметров для обработки как десериализации тела запроса, так и для поиска и предоставления значения из базы данных. Мы создали специальный обработчик аннотаций и форматов для поддержки ответов в нескольких форматах посредством согласования содержимого. И самое главное, мы прикоснулись к компоненту DI, показав, как он упрощает повторное использование объектов, а также как можно использовать концепцию контейнера на запрос для предотвращения утечки состояния между запросами.
Как вы можете себе представить, 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 позже в этой главе.
Макросами легко злоупотреблять из-за предоставляемых ими возможностей. Однако, как говорится: с большой силой приходит и большая ответственность. Эмпирическое правило заключается в том, что если вы можете добиться того, чего хотите, с помощью обычного метода, используйте обычный метод и используйте макросы как можно реже. Это не значит, что макросов следует избегать любой ценой, а скорее, что их следует использовать стратегически,