litbaza книги онлайнРазная литератураCrystal Programming. Введение на основе проекта в создание эффективных, безопасных и читаемых веб-приложений и приложений CLI - Джордж Дитрих

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 22 23 24 25 26 27 28 29 30 ... 75
Перейти на страницу:
class="p1">На данный момент наш интерфейс командной строки отвечает всем нашим требованиям. Мы можем преобразовать несколько жестко запрограммированных входных данных YAML в JSON и обработать их с помощью фильтра jq, а выходные данные преобразовать обратно в YAML и вывести для нашего просмотра, все время принимая фильтр jq в качестве аргумента CLI. Однако нашей реализации по-прежнему не хватает гибкости и производительности. В следующей главе будет рассказано, как использовать типы ввода-вывода (IO) для улучшения приложения в соответствии с обоими этими критериями.

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

5. Операции ввода/вывода

В этой главе будет подробно рассмотрено CLI-приложение, о котором говорилось в предыдущей главе, с акцентом на операции ввода/вывода (IO). В ней будут рассмотрены следующие темы:

• Поддержка терминального ввода-вывода, такого как STDIN/STDOUT/STDERR

• Поддержка дополнительного ввода-вывода

• Тестирование производительности

• Объяснение поведения ввода-вывода

К концу этой главы у вас должно быть общее представление об операциях ввода-вывода, в том числе о том, как их использовать и как они себя ведут. С помощью этих концепций вы сможете создавать интерактивные, эффективные потоковые алгоритмы, которые могут быть использованы в различных приложениях. Знание того, как работает IO, также поможет вам понять более сложные концепции, которые будут рассмотрены в следующих главах, таких как Глава 6 "Параллелизм".

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

Для выполнения кода, описанного в этой главе, вам потребуется следующее программное обеспечение:

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

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

• Средство измерения использования памяти, например https://man7.org/linux/man-pages/man1/time.1.html с параметром -v

Инструкции по настройке Crystal приведены в Главе 1 "Введение в Crystal". Скорее всего, jq можно установить с помощью менеджера пакетов в вашей системе, но его также можно установить вручную, загрузив с сайта https://stedolan.github.io/jq/download.

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

Поддерживающий терминальный ввод/вывод

В предыдущей главе мы остановились на нашем типе процессора, имеющем метод def process(input : String) : String, который преобразует входную строку, обрабатывает ее с помощью jq, а затем преобразует и возвращает выходные данные. Затем мы вызываем этот метод со статическим вводом. Однако CLI-приложение не очень полезно, если его нужно перекомпилировать каждый раз, когда вы хотите изменить входные данные.

Более правильный способ справиться с этим - использовать терминальный ввод-вывод, а именно Standard In(STDIN), Standard Out (STDOUT) и Standard Error (STDERR). Это позволит нам использовать данные, выводить данные и выводить ошибки соответственно. Фактически, вы уже используете стандартный вывод, даже не подозревая об этом! Метод Crystal puts записывает переданное ему содержимое в стандартный вывод, за которым следует перевод строки. Тип STDOUT наследуется от абстрактного типа ввода-вывода, который также определяет метод puts для экземпляра ввода-вывода. В принципе, это позволяет вам делать то же самое, что и puts верхнего уровня, но для любого ввода-вывода. Например, обратите внимание, что эти два варианта puts дают один и тот же результат:

puts "Hello!"         # => Hello!

STDOUT.puts "Hello!"  # => Hello!

Но подождите, что такое IO? Технически в Crystal IO — это все, что наследуется от абстрактного типа IO.

Однако на практике ввод/вывод обычно представляет собой что-то, что может записывать и/или считывать данные, например файлы или тела HTTP-запроса/ответа. IO также обычно реализуется таким образом, что не все читаемые/записываемые данные должны находиться в памяти одновременно, чтобы поддерживать «потоковую передачу» данных. Пользовательский IO также может быть определен для более специализированных случаев использования.

В нашем контексте типы STDIN, STDOUT и STDERR фактически являются экземплярами IO::FileDescriptor.

Crystal предоставляет некоторые полезные типы IO, которые мы уже использовали. Помните, как мы также использовали IO::Memory как средство передачи преобразованных входных данных в jq? Или как мы использовали String.build для создания строки данных после того, как jq преобразовал ее? IO::Memory — это реализация IO, которая хранит записанные данные в памяти приложения, а не во внешнем хранилище, таком как файл. Метод String.build выдает IO, в который можно записать данные, а затем возвращает записанное содержимое в виде строки. Полученный IO можно рассматривать как оптимизированную версию IO::Memory. Пример этого в действии будет выглядеть так:

io = IO::Memory.new

io << "Hello"

io << " " << "World!"

puts io # => Hello World!

string = String.build do |io|

    io << "Goodbye"

    io << " " << "World"

end

puts string # => Goodbye World!

Стандартная библиотека Crystal также включает в себя несколько примесей, которые можно использовать для улучшения поведения IO. Например, модуль IO::Buffered можно включить в тип IO, чтобы повысить производительность за счет добавления буферизации ввода/вывода к типу IO Другими словами, вы можете сделать так, чтобы данные не записывались немедленно в базовый IO, если это тяжелый процесс. Файл является примером буферизованного IO.

Crystal также предоставляет некоторые дополнительные специализированные типы ввода-вывода, которые можно использовать в качестве строительных блоков для создания других типов IO. Некоторые из них, на которые стоит обратить внимание, включают следующее:

Delimited — IO, который оборачивает другой IO, считывая только до начала указанный разделитель. Может быть полезно для экспорта только части потока клиенту.

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

Sized — IO, который оборачивает другой ввод-вывод, устанавливая ограничение на количество байтов, которые можно прочитать.

Полный список см. в документации API: https://crystal-lang.org/api/IO.html.

Теперь, когда мы познакомились с IO, давайте вернемся к обновлению нашего CLI, чтобы лучше использовать ввод-вывод на основе терминала. Планируется обновить src/transform_cli.cr для чтения непосредственно из STDIN и вывода непосредственно в STDOUT. Это также позволит нам устранить необходимость в константе INPUT_DATA. Теперь файл выглядит так:

require "./transform"

STDOUT.puts Transform::Processor.new.process STDIN.gets_to_end

Главное, что изменилось, это то, что мы заменили константу INPUT_DATA на STDIN. get_to_end.

1 ... 22 23 24 25 26 27 28 29 30 ... 75
Перейти на страницу:

Комментарии
Минимальная длина комментария - 20 знаков. Уважайте себя и других!
Комментариев еще нет. Хотите быть первым?