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. Некоторые из них, на которые стоит обратить внимание, включают следующее:
•
•
•
Полный список см. в документации API: https://crystal-lang.org/api/IO.html.
Теперь, когда мы познакомились с IO, давайте вернемся к обновлению нашего CLI, чтобы лучше использовать ввод-вывод на основе терминала. Планируется обновить STDIN
и вывода непосредственно в STDOUT
. Это также позволит нам устранить необходимость в константе INPUT_DATA
. Теперь файл выглядит так:
require "./transform"
STDOUT.puts Transform::Processor.new.process STDIN.gets_to_end
Главное, что изменилось, это то, что мы заменили константу INPUT_DATA
на STDIN
. get_to_end
. При этом все данные из STDIN
будут прочитаны в виде строки, передав их в качестве аргумента методу #process
. Мы также заменили puts
на STDOUT.puts
, которые семантически эквивалентны, но это просто проясняет, куда направляются выходные данные.
Остальная логика внутри нашего типа процессора остается прежней, включая String.build
, чтобы вернуть вывод jq в виде строки, чтобы мы могли преобразовать его обратно в YAML перед выводом на терминал. Однако в следующем разделе будут представлены некоторые рефакторинги, которые сделают это ненужным.
Мы можем убедиться, что наше изменение работает, запустив echo $'---\n- id: 1\n author:\n name: Jim\n- id: 2\n author:\n name: Bob\n' | crystal src/transform_cli.cr '[.[] | {"id": (.id + 1), "name": .author.name}]',
который должен выводиться так же, как и раньше:
---
- id: 2
name: Jim
- id: 3
name: Bob