Выбрать главу

module MyModule

  module ClassMethods

    def foo

      "foo"

    end

  end

  macro included

    extend MyModule::ClassMethods

  end

  def bar

    "bar"

  end

end

class Foo

  include MyModule

end

pp Foo.foo

pp Foo.new.bar

Таким образом, пользователю нужно только включить модуль, чтобы получить оба типа методов, что в целом улучшит взаимодействие с пользователем.

macro finished в основном используется, когда вы хотите выполнить какой-либо макрокод только после того, как Crystal узнает обо всех типах. В некоторых случаях отсутствие вашего макрокода в обработчике finished может привести к неверным результатам. Следите за обновлениями! Мы рассмотрим это более подробно в Главе 15 "Документирование кода".

Резюме

Метапрограммирование — одна из областей, в которой Кристалл преуспевает. Он предоставляет нам довольно мощную систему, которую можно использовать для генерации кода и уменьшения количества шаблонов/повторений, при этом оставаясь при этом достаточно простой по сравнению с другими языками. Однако, когда это необходимо, эту силу следует использовать экономно.

В этой главе мы узнали, как и когда использовать макросы для сокращения шаблонного кода, как подключаться к различным событиям Crystal с помощью перехватчиков макросов, а также познакомились с API макросов для поддержки создания более сложных макросов.

В следующей главе мы рассмотрим аннотации и то, как их можно использовать в сочетании с макросами для хранения данных, которые можно прочитать во время компиляции.

11. Знакомство с аннотациями

Как упоминалось в предыдущей главе, макросы могут быть мощным инструментом для генерации кода, позволяющим уменьшить дублирование и сохранить ваше приложение DRY. Однако одно из ограничений макросов, особенно тех, которые находятся за пределами определения макроса, заключается в том, что сложно получить доступ к данным для использования внутри макроса, поскольку они должны быть доступны во время компиляции, как переменная среды или константа.

Ни один из этих вариантов в большинстве случаев не является отличным вариантом. Чтобы лучше решить эту проблему, нам нужно изучить следующую концепцию метапрограммирования Crystaclass="underline" аннотации.

В этой главе мы рассмотрим следующие темы:

• Что такое аннотации?

• Хранение данных в аннотациях.

• Чтение аннотаций

К концу этой главы вы должны иметь четкое представление о том, что такое аннотации и как их использовать.

Технические требования

Требования к этой главе следующие:

• Рабочая установка Crystal.

Инструкции по настройке Crystal можно найти в Главе 1 «Введение в Crystal».

Все примеры кода, использованные в этой главе, можно найти в папке Chapter 11 на GitHub: https://github.com/PacktPublishing/Crystal-Programming/tree/main/Chapter11.

Что такое аннотации?

Проще говоря, аннотация — это способ прикрепить метаданные к определенным функциям кода, к которым впоследствии можно получить доступ во время компиляции внутри макроса. Crystal поставляется в комплекте с некоторыми встроенными аннотациями, с которыми вы, возможно, уже работали, например @[JSON::Field] или аннотацией @[Link], которая была рассмотрена в Главе 7, «Взаимодействие C». Хотя обе эти аннотации включены по умолчанию, они различаются по своему поведению. Например, аннотация JSON::Field существует в стандартной библиотеке Crystal и реализована/используется таким образом, что вы можете воспроизвести ее в своем собственном коде с помощью собственной аннотации. С другой стороны, аннотация Link имеет особые отношения с компилятором Crystal, и часть ее поведения не может быть воспроизведена в пользовательском коде.

Пользовательские аннотации можно определить с помощью ключевого слова annotation:

annotation MyAnnotation; end

Вот и все. Затем аннотацию можно было применить к различным элементам, включая следующие:

• Методы экземпляра и класса.

• Переменные экземпляра

• Классы, структуры, перечисления и модули.

Аннотацию можно применять к различным объектам, помещая имя аннотации в квадратные скобки синтаксиса @[], как в следующем примере:

@[MyAnnotation]

def foo

  "foo"

end

@[MyAnnotation]

class Klass

end

@[MyAnnotation]