Играете на гитаре и вынуждены постоянно искать в интернете аккорды для исполнения песен с менее распространенными аккордами?
А как насчет инструмента командной строки (CLI), который принимает на вход название аккорда и выводит аппликатуру, отображающую способ его исполнения?
В статье мы реализуем эту идею и с нуля создадим такой CLI в Rust.
Конечная цель
Итоговый результат работы — создание CLI с именем chord
. Он принимает на вход одну строку, а именно название аккорда, и выводит его аппликатуру. Пример:
$ chord C
x ◯ ◯
┌─┬─┬─┬─┬─┐
│ │ │ │ ◯ │
├─┼─┼─┼─┼─┤
│ │ ◯ │ │ │
├─┼─┼─┼─┼─┤
│ ◯ │ │ │ │
└─┴─┴─┴─┴─┘
Почему Rust?
Rust выбран не случайно. По результатам опроса Stack Overflow, проведенного в 2021 году, он является самым излюбленным языком программирования:
Rust отлично подходит как для создания бэкенд-сервисов, так и CLI.
К делу!
Установка Rust
Устанавливаем Rust следующим образом:
$ curl --proto '=https' --tlsv1.2 -sSf <https://sh.rustup.rs> | sh
Более подробная информация по установке предоставлена по ссылке.
Создание нового проекта Rust
$ cargo new chord --bin Created binary (application) `chord` package
Компилируем и запускаем программу, проверяя корректность всех настроек:
$ cd chord $ cargo run Hello, world!
Полученный результат:
|-Cargo.toml
|-Cargo.lock
|-src
| |-main.rs
Вывод грифа
У гитары 6 струн. Как правило, для отображения постановки пальцев используется гриф.
На данный момент main.rs
выглядит так:
fn main() {
println!("Hello, world!");
}
Внесем в него изменения для вывода пустого грифа:
const FRETBOARD: &str = "◯ ◯ ◯ ◯ ◯ ◯
┌─┬─┬─┬─┬─┐
│ │ │ │ │ │
├─┼─┼─┼─┼─┤
│ │ │ │ │ │
├─┼─┼─┼─┼─┤
│ │ │ │ │ │
└─┴─┴─┴─┴─┘";
fn main() {
println!("{}", FRETBOARD);
}
Выполняем программу и получаем следующий результат:
$ cargo run
◯ ◯ ◯ ◯ ◯ ◯
┌─┬─┬─┬─┬─┐
│ │ │ │ │ │
├─┼─┼─┼─┼─┤
│ │ │ │ │ │
├─┼─┼─┼─┼─┤
│ │ │ │ │ │
└─┴─┴─┴─┴─┘
Clap
Для парсинга аргументов командной строки потребуется библиотека Clap.
Присоединяем к проекту Clap в качестве зависимости:
$ cargo add clap --features derive
Эта команда просто добавляет следующую строку в cargo.toml
, где описаны зависимости для Rust:
clap = { version = "3.2.21", features = ["derive"] }
Обновляем main.rs
таким образом:
const FRETBOARD: &str = "◯ ◯ ◯ ◯ ◯ ◯ ┌─┬─┬─┬─┬─┐ │ │ │ │ │ │ ├─┼─┼─┼─┼─┤ │ │ │ │ │ │ ├─┼─┼─┼─┼─┤ │ │ │ │ │ │ └─┴─┴─┴─┴─┘"; use clap::Parser; /// CLI, показывающий, как сыграть гитарный аккорд #[derive(Parser, Debug)] #[clap(version, about)] struct Args { /// Название аккорда #[clap()] name: String, } fn main() { let args = Args::parse(); println!("This is how you play '{}' chord: \n{}", args.name, FRETBOARD); }
Макросы Rust значительно упрощают для Clap процедуру аннотации Args
и обеспечивают бесплатный парсинг аргументов:
/// CLI, показывающий, как сыграть гитарный аккорд
#[derive(Parser, Debug)]
#[clap(version, about)]
struct Args {
/// Название аккорда
#[clap()]
name: String,
}
Проверяем:
$ cargo run -- --help chord 0.1.0 A CLI to show you how to play a guitar chord USAGE: chord <NAME> ARGS: <NAME> Name of the chord OPTIONS: -h, --help Print help information -V, --version Print version information $ cargo run -- C This is how you play 'C' chord: ◯ ◯ ◯ ◯ ◯ ◯ ┌─┬─┬─┬─┬─┐ │ │ │ │ │ │ ├─┼─┼─┼─┼─┤ │ │ │ │ │ │ ├─┼─┼─┼─┼─┤ │ │ │ │ │ │ └─┴─┴─┴─┴─┘
Двойное тире --
— это общепринятый способ указать на окончание параметров для cargo
, а остальное передается программе CLI. Такой принцип действия характерен не только для cargo
, но и многих других shell
-команд.
Есть еще одна скрытая особенность, на которую стоит обратить внимание. Заметили, что A CLI to show you how to play a guitar chord
(CLI, показывающий, как сыграть гитарный аккорд) и Name of the chord
(Название аккорда) являются комментариями в исходном коде? Они также включены в справочное сообщение.
Из исходного кода:
/// A CLI to show you how to play a guitar chord
#[derive(Parser, Debug)]
#[clap(version, about)]
struct Args {
/// Name of the chord
#[clap()]
name: String,
}
Из вывода:
chord 0.1.0 A CLI to show you how to play a guitar chord USAGE: chord <NAME> ARGS: <NAME> Name of the chord
Это вся необходимая информация, которую нужно знать о Clap. Переходим непосредственно к самому CLI.
CLI
Обновляем функцию main
следующим образом:
fn main() {
let args = Args::parse();
let chords: HashMap<&str, &str> =
HashMap::from([("C", "x32010"), ("G", "320003"), ("D", "xx0232")]);
match chords.get(&args.name[..]) {
None => println!("Unknown chord '{}'", args.name),
Some(pattern) => {
let mut board: Vec<char> = FRETBOARD.chars().collect();
for (i, ch) in pattern.chars().enumerate() {
let idx: usize = i * 2;
if ch == 'x' {
board[idx] = ch
} else {
let value: usize = ch.to_digit(10).unwrap() as usize;
board[idx] = ' ';
board[idx + 24 * value] = '◯'
}
}
println!(
"This is how you play '{}' chord: \n{}",
args.name,
board.iter().collect::<String>()
)
}
}
}
Если название входного аккорда неизвестно, то выводится сообщение об ошибке Unknown chord
. В противном случае мы накладываем постановку пальцев поверх пустого грифа, представленного ранее.
Тестируем код:
$ cargo run -- C This is how you play 'C' chord: x ◯ ◯ ┌─┬─┬─┬─┬─┐ │ │ │ │ ◯ │ ├─┼─┼─┼─┼─┤ │ │ ◯ │ │ │ ├─┼─┼─┼─┼─┤ │ ◯ │ │ │ │ └─┴─┴─┴─┴─┘ $ cargo run -- Asus4 Unknown chord 'Asus4'
Отличный результат! Быстро и просто!
Установка
До сих пор мы компилировали и запускали CLI. cargo
занимается не только сборкой, выполнением, управлением зависимостями библиотек, но и установкой.
Устанавливаем CLI chord
:
cargo install --path .
И работаем с данным CLI напрямую:
$ chord G
This is how you play 'G' chord:
◯ ◯ ◯
┌─┬─┬─┬─┬─┐
│ │ │ │ │ │
├─┼─┼─┼─┼─┤
│ ◯ │ │ │ │
├─┼─┼─┼─┼─┤
◯ │ │ │ │ ◯
└─┴─┴─┴─┴─┘
Теперь вы знаете, как создать CLI в Rust.
Заключение
Забыли, как сыграть аккорд? Не беда — у вас под рукой отличный инструмент.
Переходите по ссылке в ветку blog-post-checkpoint
, где предоставлен код для данной статьи. С новейшей версией CLI можно ознакомиться по ссылке на ветке master
.
Читайте также:
- 5 функций CLI на Rust для оптимизации привычных инструментов
- Разработка макроса Rust для автоматического написания шаблонного кода SQL
- Тестирование клиент-серверов на Rust для IoT
Читайте нас в Telegram, VK и Дзен
Перевод статьи Yuchen Z.: Build a Command Line Tool With Rust to Play Guitar Chords