Crystal Programming. Введение на основе проекта в создание эффективных, безопасных и читаемых веб-приложений и приложений CLI - Джордж Дитрих
Ни один из этих вариантов в большинстве случаев не является отличным вариантом. Чтобы лучше решить эту проблему, нам нужно изучить следующую концепцию метапрограммирования Crystal: аннотации.
В этой главе мы рассмотрим следующие темы:
• Что такое аннотации?
• Хранение данных в аннотациях.
• Чтение аннотаций
К концу этой главы вы должны иметь четкое представление о том, что такое аннотации и как их использовать.
Технические требования
Требования к этой главе следующие:
• Рабочая установка 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]
module MyModule
end
К одному и тому же элементу также можно применить несколько аннотаций:
annotation Ann1; end
annotation Ann2; end
@[Ann1]
@[Ann2]
@[Ann2]
def foo
end
В этом конкретном контексте на самом деле нет смысла использовать более одной аннотации, поскольку нет способа отличить их друг от друга; однако это будет иметь больше смысла, если вы добавите данные в аннотацию, что является темой следующего раздела.
Итак, аннотации — это то, что можно применять к различным вещам в коде для хранения метаданных о них. Но чем они на самом деле хороши? Основное преимущество, которое они предоставляют, заключается в том, что они не зависят от реализации. Другими словами, это означает, что вы можете просто аннотировать что-то, и соответствующая библиотека сможет читать из него данные без необходимости специального определения макроса для создания переменной экземпляра, метода или типа.
Примером этого может быть, скажем, у вас есть модель ORM, которую вы хотите проверить. Например, если одна из установленных вами библиотек использует собственный макрос, такой как column id : Int64, это может сделать другие библиотеки нефункциональными, поскольку аннотация может быть неправильно применена к переменной экземпляра или методу. Однако если все библиотеки используют аннотации, то все они работают со стандартными переменными экземпляра Crystal, поэтому у библиотек нет возможности конфликтовать, и это делает все более естественным.
Кроме того, аннотации более ориентированы на будущее и более гибки по сравнению с определениями макросов для этого конкретного варианта использования. Далее давайте поговорим о том, как хранить данные в аннотации.
Хранение данных в аннотациях
Подобно методу, аннотация поддерживает как позиционные, так и именованные аргументы:
annotation MyAnnotation
end
@[MyAnnotation(name: "value", id: 123)]
def foo; end
@[MyAnnotation("foo", 123, false)]
def bar; end
В этом примере мы определили два пустых метода, к каждому из которых применена аннотация. Первый использует исключительно именованные аргументы, а второй использует исключительно позиционные аргументы. Лучший пример применения нескольких аннотаций одного и того же типа можно продемонстрировать, когда в каждую аннотацию включены данные. Вот пример:
annotation MyAnnotation; end
@[MyAnnotation(1, enabled: false)]
@[MyAnnotation(2)]
def foo
end
Поскольку значения в каждой аннотации могут быть разными, связанная библиотека может создать несколько методов или переменных, например, на основе каждой аннотации и данных в ней. Однако эти данные бесполезны, если вы не можете получить к ним доступ! Давайте посмотрим, как это сделать дальше.
Чтение аннотаций
В Crystal вы обычно вызываете метод объекта, чтобы получить доступ к некоторым данным, хранящимся внутри. Аннотации ничем не отличаются. Тип Annotation предоставляет три метода, которые можно использовать для доступа к данным, определенным в аннотации, различными способами. Однако прежде чем вы сможете получить доступ к данным в аннотации, вам необходимо получить ссылку на экземпляр Annotation. Это можно сделать, передав тип Annotation методу #annotation, определенному для типов, поддерживающих аннотации, включая TypeNode, Def и MetaVar. Например, мы можем использовать этот метод для печати аннотации, примененной к определенному классу или методу, если таковой имеется:
annotation MyAnnotation; end
@[MyAnnotation]
class MyClass
def foo
{{pp @type.annotation MyAnnotation}}
{{pp @def.annotation MyAnnotation}}
end
end
MyClass.new.foo
Метод #annotation вернет NilLiteral, если аннотация указанного типа не применена. Теперь, когда у нас есть доступ к примененной аннотации, мы готовы начать чтение из нее данных!
Первый, наиболее простой способ — использование метода #[], который может показаться знакомым, поскольку он также используется, среди прочего, как часть типов Array и Hash. Этот метод имеет две формы: первая принимает NumberLiteral и возвращает позиционное значение по предоставленному индексу. Другая форма принимает StringLiteral, SymbolLiteral или MacroId и возвращает значение с предоставленным ключом. Оба этих метода вернут NilLiteral, если по указанному индексу или указанному ключу не существует значения.
Два других метода, #args и #named_args, не возвращают конкретное значение, а вместо этого возвращают коллекцию всех позиционных или именованных аргументов в аннотации в виде TupleLiteral и NamedTupleLiteral соответственно.
Прежде всего, давайте посмотрим, как мы можем работать с
Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение Crystal Programming. Введение на основе проекта в создание эффективных, безопасных и читаемых веб-приложений и приложений CLI - Джордж Дитрих, относящееся к жанру Программирование. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.

