clap
This commit is contained in:
956
priprava/rust_priprava10.md
Normal file
956
priprava/rust_priprava10.md
Normal file
@@ -0,0 +1,956 @@
|
|||||||
|
# clap — krok za krokom
|
||||||
|
|
||||||
|
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
|
||||||
|
|
||||||
|
`Cargo.toml`:
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
clap = { version = "4", features = ["derive"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::Parser;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 1: Čo je clap
|
||||||
|
|
||||||
|
clap je knižnica na spracovanie **argumentov príkazového riadku** (CLI argumentov).
|
||||||
|
|
||||||
|
Keď spustíš program z terminálu:
|
||||||
|
```bash
|
||||||
|
./moj_program --subor data.json --pocet 5 --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
clap ti tie argumenty automaticky sparsuje do Rust štruktúry.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Argumenty {
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: String,
|
||||||
|
|
||||||
|
#[arg(short, long)]
|
||||||
|
pocet: u32,
|
||||||
|
|
||||||
|
#[arg(short, long)]
|
||||||
|
verbose: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Argumenty::parse();
|
||||||
|
println!("Súbor: {}", args.subor);
|
||||||
|
println!("Počet: {}", args.pocet);
|
||||||
|
println!("Verbose: {}", args.verbose);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Spustenie:
|
||||||
|
```bash
|
||||||
|
./moj_program --subor data.json --pocet 5 --verbose
|
||||||
|
# Súbor: data.json
|
||||||
|
# Počet: 5
|
||||||
|
# Verbose: true
|
||||||
|
|
||||||
|
./moj_program -s data.json -p 5 -v
|
||||||
|
# To isté — short varianty
|
||||||
|
|
||||||
|
./moj_program --help
|
||||||
|
# Automaticky vygenerovaná nápoveda!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Čo clap robí za teba:**
|
||||||
|
- Parsuje argumenty z príkazového riadku
|
||||||
|
- Validuje typy (ak --pocet nie je číslo → chybová hláška)
|
||||||
|
- Generuje `--help` automaticky
|
||||||
|
- Generuje chybové hlášky ak niečo chýba
|
||||||
|
- Podporuje short (`-s`) aj long (`--subor`) verzie
|
||||||
|
|
||||||
|
### Úlohy 1
|
||||||
|
|
||||||
|
**1a.** Čo je CLI argument? Uveď 3 príklady programov, ktoré berú argumenty (napr. `ls -la`).
|
||||||
|
|
||||||
|
**1b.** Napíš štruktúru `Args` s jedným argumentom `meno: String` (long + short). Sparsuj a vypíš.
|
||||||
|
|
||||||
|
**1c.** Čo sa stane keď spustíš program bez argumentov? Čo keď s `--help`?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 2: Typy argumentov
|
||||||
|
|
||||||
|
### Povinný argument
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: String, // POVINNÝ — program spadne ak chýba
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --subor data.json # OK
|
||||||
|
./program # CHYBA: "required arguments were not provided"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Voliteľný argument (Option)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: Option<String>, // VOLITEĽNÝ — None ak neuvedený
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --subor data.json # args.subor = Some("data.json")
|
||||||
|
./program # args.subor = None
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bool flag
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
verbose: bool, // false ak neuvedený, true ak uvedený
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --verbose # args.verbose = true
|
||||||
|
./program -v # args.verbose = true
|
||||||
|
./program # args.verbose = false
|
||||||
|
```
|
||||||
|
|
||||||
|
Bool flag neberá hodnotu! Stačí ho uviesť a je true.
|
||||||
|
|
||||||
|
### Argument s default hodnotou
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long, default_value = "data.json")]
|
||||||
|
subor: String,
|
||||||
|
|
||||||
|
#[arg(short, long, default_value_t = 10)]
|
||||||
|
pocet: u32,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program # subor = "data.json", pocet = 10
|
||||||
|
./program --subor iny.json # subor = "iny.json", pocet = 10
|
||||||
|
./program -p 5 # subor = "data.json", pocet = 5
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pozor:** `default_value` je pre String (vždy v úvodzovkách). `default_value_t` je pre iné typy (čísla, bool).
|
||||||
|
|
||||||
|
### Úlohy 2
|
||||||
|
|
||||||
|
**2a.** Napíš Args s:
|
||||||
|
- `subor: String` — povinný
|
||||||
|
- `vystup: Option<String>` — voliteľný
|
||||||
|
- `pocet: u32` — default 5
|
||||||
|
- `verbose: bool` — flag
|
||||||
|
|
||||||
|
Vyskúšaj rôzne kombinácie spustenia.
|
||||||
|
|
||||||
|
**2b.** Čo sa stane ak zadáš `--pocet ahoj` (nie číslo)?
|
||||||
|
|
||||||
|
**2c.** Čo je rozdiel medzi `Option<String>` a `String` s `default_value`?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 3: short a long
|
||||||
|
|
||||||
|
### Automatické short a long
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: String,
|
||||||
|
// --subor hodnota (long = názov poľa)
|
||||||
|
// -s hodnota (short = prvé písmeno)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Len long (bez short)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(long)]
|
||||||
|
konfig: String,
|
||||||
|
// --konfig hodnota OK
|
||||||
|
// -k hodnota NEFUNGUJE
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Len short (bez long)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short)]
|
||||||
|
verbose: bool,
|
||||||
|
// -v OK
|
||||||
|
// --verbose NEFUNGUJE
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vlastné short/long
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short = 'f', long = "file")]
|
||||||
|
subor: String,
|
||||||
|
// -f hodnota OK
|
||||||
|
// --file hodnota OK
|
||||||
|
// --subor hodnota NEFUNGUJE (premenovali sme)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Kolízia short písmen
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// PROBLÉM: obe majú short 's'
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: String, // -s
|
||||||
|
|
||||||
|
#[arg(short, long)]
|
||||||
|
stav: String, // -s KOLÍZIA!
|
||||||
|
}
|
||||||
|
// Riešenie: jedného premenuj
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: String, // -s
|
||||||
|
|
||||||
|
#[arg(short = 't', long)]
|
||||||
|
stav: String, // -t
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 3
|
||||||
|
|
||||||
|
**3a.** Napíš Args kde:
|
||||||
|
- `input` má short `-i` a long `--input`
|
||||||
|
- `output` má short `-o` a long `--output`
|
||||||
|
- `debug` má len short `-d` (žiadny long)
|
||||||
|
- `format` má len long `--format` (žiadny short)
|
||||||
|
|
||||||
|
**3b.** Máš 3 polia: `subor`, `stav`, `slovo`. Všetky začínajú na 's'. Vyrieš kolíziu short písmen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 4: Pozičné argumenty
|
||||||
|
|
||||||
|
Doteraz sme používali pomenované argumenty (`--subor`, `-s`). Existujú aj pozičné — bez mena, len podľa poradia.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Vstupný súbor
|
||||||
|
vstup: String, // PRVÝ pozičný argument
|
||||||
|
|
||||||
|
/// Výstupný súbor
|
||||||
|
vystup: String, // DRUHÝ pozičný argument
|
||||||
|
|
||||||
|
#[arg(short, long)]
|
||||||
|
verbose: bool, // Pomenovaný (flag)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program input.json output.json --verbose
|
||||||
|
# ^^^^^^^^^^ ^^^^^^^^^^^
|
||||||
|
# prvý druhý pozičný
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pravidlo:** Ak pole nemá `#[arg(short, long)]`, je pozičné.
|
||||||
|
|
||||||
|
### Voliteľný pozičný
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
vstup: String, // povinný pozičný
|
||||||
|
vystup: Option<String>, // voliteľný pozičný
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program input.json # vystup = None
|
||||||
|
./program input.json output.json # vystup = Some("output.json")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pozičný s default
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(default_value = "data.json")]
|
||||||
|
subor: String,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program # subor = "data.json"
|
||||||
|
./program iny.json # subor = "iny.json"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 4
|
||||||
|
|
||||||
|
**4a.** Napíš Args pre program, ktorý kopíruje súbor:
|
||||||
|
```bash
|
||||||
|
./kopiruj zdrojovy.txt cielovy.txt
|
||||||
|
```
|
||||||
|
Dva pozičné argumenty.
|
||||||
|
|
||||||
|
**4b.** Napíš Args pre grep-like program:
|
||||||
|
```bash
|
||||||
|
./hladaj "hľadaný text" subor.txt --ignore-case
|
||||||
|
```
|
||||||
|
Pozičné: vzor a súbor. Pomenované: ignore_case (bool flag).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 5: Popis a help text
|
||||||
|
|
||||||
|
### Dokumentačné komentáre → help text
|
||||||
|
|
||||||
|
```rust
|
||||||
|
/// Správca knižnice — CLI nástroj na správu kníh
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Cesta k JSON súboru s dátami
|
||||||
|
#[arg(short, long)]
|
||||||
|
subor: String,
|
||||||
|
|
||||||
|
/// Počet výsledkov na stránku
|
||||||
|
#[arg(short, long, default_value_t = 10)]
|
||||||
|
pocet: u32,
|
||||||
|
|
||||||
|
/// Zapni podrobný výpis
|
||||||
|
#[arg(short, long)]
|
||||||
|
verbose: bool,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --help
|
||||||
|
# Správca knižnice — CLI nástroj na správu kníh
|
||||||
|
#
|
||||||
|
# Usage: program [OPTIONS] --subor <SUBOR>
|
||||||
|
#
|
||||||
|
# Options:
|
||||||
|
# -s, --subor <SUBOR> Cesta k JSON súboru s dátami
|
||||||
|
# -p, --pocet <POCET> Počet výsledkov na stránku [default: 10]
|
||||||
|
# -v, --verbose Zapni podrobný výpis
|
||||||
|
# -h, --help Print help
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pravidlo:** `///` komentár nad štruktúrou = popis programu. `///` nad poľom = popis argumentu. clap ich automaticky zobrazí v `--help`.
|
||||||
|
|
||||||
|
### about a help atribúty
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(about = "Správca knižnice", version = "1.0")]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long, help = "Cesta k súboru")]
|
||||||
|
subor: String,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --version
|
||||||
|
# program 1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 5
|
||||||
|
|
||||||
|
**5a.** Pridaj ku každému argumentu z úlohy 2a popis (`///` komentár). Spusti s `--help` a pozri výstup.
|
||||||
|
|
||||||
|
**5b.** Pridaj k štruktúre `#[command(about, version)]`. Vyskúšaj `--help` a `--version`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 6: Subcommands — podpríkazy
|
||||||
|
|
||||||
|
Väčšie programy majú podpríkazy:
|
||||||
|
```bash
|
||||||
|
git add file.txt
|
||||||
|
git commit -m "správa"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
V clap to riešiš cez enum:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[command(subcommand)]
|
||||||
|
prikaz: Prikaz,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
enum Prikaz {
|
||||||
|
/// Pridaj novú knihu
|
||||||
|
Pridaj {
|
||||||
|
/// Názov knihy
|
||||||
|
nazov: String,
|
||||||
|
/// Autor knihy
|
||||||
|
autor: String,
|
||||||
|
},
|
||||||
|
/// Odstráň knihu podľa názvu
|
||||||
|
Odstran {
|
||||||
|
/// Názov knihy na odstránenie
|
||||||
|
nazov: String,
|
||||||
|
},
|
||||||
|
/// Vypíš všetky knihy
|
||||||
|
Vypis,
|
||||||
|
/// Hľadaj knihy
|
||||||
|
Hladaj {
|
||||||
|
/// Hľadaný výraz
|
||||||
|
vyraz: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
|
||||||
|
match args.prikaz {
|
||||||
|
Prikaz::Pridaj { nazov, autor } => {
|
||||||
|
println!("Pridávam: {} od {}", nazov, autor);
|
||||||
|
}
|
||||||
|
Prikaz::Odstran { nazov } => {
|
||||||
|
println!("Odstraňujem: {}", nazov);
|
||||||
|
}
|
||||||
|
Prikaz::Vypis => {
|
||||||
|
println!("Výpis kníh...");
|
||||||
|
}
|
||||||
|
Prikaz::Hladaj { vyraz } => {
|
||||||
|
println!("Hľadám: {}", vyraz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program pridaj "Duna" "Frank Herbert"
|
||||||
|
./program odstran "Duna"
|
||||||
|
./program vypis
|
||||||
|
./program hladaj "Herbert"
|
||||||
|
./program --help
|
||||||
|
# Shows all subcommands
|
||||||
|
|
||||||
|
./program pridaj --help
|
||||||
|
# Shows help for "pridaj" subcommand
|
||||||
|
```
|
||||||
|
|
||||||
|
### Spoločné argumenty + subcommand
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Cesta k JSON súboru
|
||||||
|
#[arg(short, long, default_value = "data.json")]
|
||||||
|
subor: String,
|
||||||
|
|
||||||
|
#[command(subcommand)]
|
||||||
|
prikaz: Prikaz,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --subor moje.json pridaj "Duna" "Herbert"
|
||||||
|
# ^^^^^^^^^^^^^^^^^ ^^^^^^ spoločný arg pred subcommand
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 6
|
||||||
|
|
||||||
|
**6a.** Napíš CLI pre správcu kontaktov:
|
||||||
|
```bash
|
||||||
|
./kontakty pridaj "Anna" "+421900000000"
|
||||||
|
./kontakty odstran "Anna"
|
||||||
|
./kontakty vypis
|
||||||
|
./kontakty hladaj "Ann"
|
||||||
|
```
|
||||||
|
|
||||||
|
**6b.** Pridaj spoločný argument `--subor` (default "kontakty.json") pred subcommand.
|
||||||
|
|
||||||
|
**6c.** Pridaj do `pridaj` subcomandu voliteľný argument `--email`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 7: ValueEnum — enum ako argument
|
||||||
|
|
||||||
|
Ak chceš aby argument bol jedna z preddefinovaných hodnôt:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::{Parser, ValueEnum};
|
||||||
|
|
||||||
|
#[derive(Clone, ValueEnum)]
|
||||||
|
enum Format {
|
||||||
|
Json,
|
||||||
|
Csv,
|
||||||
|
Text,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long, default_value = "json")]
|
||||||
|
format: Format,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
match args.format {
|
||||||
|
Format::Json => println!("Výstup ako JSON"),
|
||||||
|
Format::Csv => println!("Výstup ako CSV"),
|
||||||
|
Format::Text => println!("Výstup ako text"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --format json
|
||||||
|
./program --format csv
|
||||||
|
./program --format text
|
||||||
|
./program --format xml # CHYBA: "invalid value 'xml'"
|
||||||
|
./program --help
|
||||||
|
# -f, --format <FORMAT> [default: json] [possible values: json, csv, text]
|
||||||
|
```
|
||||||
|
|
||||||
|
clap automaticky:
|
||||||
|
- Ukáže povolené hodnoty v `--help`
|
||||||
|
- Odmietne neplatnú hodnotu
|
||||||
|
- Case-insensitive porovnanie
|
||||||
|
|
||||||
|
### Na skúške — enum Stav ako argument
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Clone, ValueEnum, Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
enum Stav {
|
||||||
|
Nova,
|
||||||
|
Pouzivana,
|
||||||
|
Poskodena,
|
||||||
|
Vyradena,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
enum Prikaz {
|
||||||
|
ZmenStav {
|
||||||
|
nazov: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
stav: Stav,
|
||||||
|
},
|
||||||
|
PodlaStavu {
|
||||||
|
#[arg(short, long)]
|
||||||
|
stav: Stav,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program zmen-stav "Duna" --stav pouzivana
|
||||||
|
./program podla-stavu --stav nova
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 7
|
||||||
|
|
||||||
|
**7a.** Vytvor enum `Priorita { Nizka, Stredna, Vysoka }` s `ValueEnum`. Použi ho ako argument v CLI.
|
||||||
|
|
||||||
|
**7b.** Pridaj do subcommandu `pridaj` argument `--priorita` typu Priorita s defaultom `Stredna`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 8: Vec argumenty — viacero hodnôt
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Súbory na spracovanie
|
||||||
|
subory: Vec<String>, // 0 alebo viac pozičných
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program a.txt b.txt c.txt
|
||||||
|
# args.subory = ["a.txt", "b.txt", "c.txt"]
|
||||||
|
|
||||||
|
./program
|
||||||
|
# args.subory = []
|
||||||
|
```
|
||||||
|
|
||||||
|
### Minimálne 1
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Súbory na spracovanie (aspoň 1)
|
||||||
|
#[arg(required = true)]
|
||||||
|
subory: Vec<String>,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program a.txt b.txt # OK
|
||||||
|
./program # CHYBA: required
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pomenovaný s viacerými hodnotami
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
tagy: Vec<String>,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --tagy rust --tagy cli --tagy serde
|
||||||
|
# args.tagy = ["rust", "cli", "serde"]
|
||||||
|
|
||||||
|
./program -t rust -t cli -t serde
|
||||||
|
# to isté
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 8
|
||||||
|
|
||||||
|
**8a.** Napíš CLI, ktoré berie zoznam čísel a vypočíta ich súčet:
|
||||||
|
```bash
|
||||||
|
./sucet 1 2 3 4 5
|
||||||
|
# Súčet: 15
|
||||||
|
```
|
||||||
|
Hint: pozičný `Vec<i32>`.
|
||||||
|
|
||||||
|
**8b.** Napíš CLI s pomenovaným argumentom `--vyluc` ktorý berie viacero mien. Potom vypíš "Vylúčení: Anna, Boris".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 9: Validácia argumentov
|
||||||
|
|
||||||
|
### value_parser — kontrola rozsahu
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Port (1-65535)
|
||||||
|
#[arg(short, long, value_parser = clap::value_parser!(u16).range(1..=65535))]
|
||||||
|
port: u16,
|
||||||
|
|
||||||
|
/// Počet (1-100)
|
||||||
|
#[arg(short, long, value_parser = clap::value_parser!(u32).range(1..=100))]
|
||||||
|
pocet: u32,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --port 8080 --pocet 50 # OK
|
||||||
|
./program --port 0 # CHYBA: "0 is not in 1..=65535"
|
||||||
|
./program --pocet 200 # CHYBA
|
||||||
|
```
|
||||||
|
|
||||||
|
### PathBuf argument
|
||||||
|
|
||||||
|
Na skúške cesta k súboru je vždy `PathBuf`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Cesta k dátovému súboru
|
||||||
|
#[arg(short, long, default_value = "data.json")]
|
||||||
|
subor: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
// args.subor je PathBuf — môžeš ho priamo použiť
|
||||||
|
let kniznica = Kniznica::nacitaj_zo_suboru(&args.subor)
|
||||||
|
.unwrap_or_default();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./program --subor /cesta/k/suboru.json
|
||||||
|
./program -s data.json
|
||||||
|
./program # default: data.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 9
|
||||||
|
|
||||||
|
**9a.** Napíš Args s argumentom `--vek` typu u8, s rozsahom 0 až 150.
|
||||||
|
|
||||||
|
**9b.** Napíš Args s PathBuf argumentom `--vstup` (povinný) a `--vystup` (voliteľný, default "output.json").
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitola 10: Kompletný vzor zo skúšky
|
||||||
|
|
||||||
|
### Vzor: Knižnica CLI
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::{Parser, Subcommand, ValueEnum};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
// === Typy ===
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ValueEnum)]
|
||||||
|
pub enum Stav {
|
||||||
|
Nova,
|
||||||
|
Pouzivana,
|
||||||
|
Poskodena,
|
||||||
|
Vyradena,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Stav {
|
||||||
|
fn default() -> Self {
|
||||||
|
Stav::Nova
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Kniha {
|
||||||
|
pub nazov: String,
|
||||||
|
pub autor: String,
|
||||||
|
pub rok: u16,
|
||||||
|
pub stav: Stav,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||||
|
pub struct Kniznica {
|
||||||
|
pub knihy: Vec<Kniha>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// === serde I/O ===
|
||||||
|
|
||||||
|
impl Kniznica {
|
||||||
|
pub fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option<Kniznica> {
|
||||||
|
let raw = fs::read_to_string(cesta).ok()?;
|
||||||
|
serde_json::from_str(&raw).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uloz_do_suboru(&self, cesta: &PathBuf) -> bool {
|
||||||
|
let Ok(json) = serde_json::to_string_pretty(&self) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
fs::write(cesta, json).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pridaj(&mut self, kniha: Kniha) -> Result<(), String> {
|
||||||
|
if self.knihy.iter().any(|k| k.nazov == kniha.nazov) {
|
||||||
|
return Err(format!("Kniha '{}' už existuje", kniha.nazov));
|
||||||
|
}
|
||||||
|
self.knihy.push(kniha);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn odstran(&mut self, nazov: &str) -> Result<Kniha, String> {
|
||||||
|
let pos = self.knihy.iter()
|
||||||
|
.position(|k| k.nazov == nazov)
|
||||||
|
.ok_or(format!("Kniha '{}' nenájdená", nazov))?;
|
||||||
|
Ok(self.knihy.remove(pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === CLI ===
|
||||||
|
|
||||||
|
/// Správca knižnice
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(about, version)]
|
||||||
|
struct Args {
|
||||||
|
/// Cesta k JSON súboru
|
||||||
|
#[arg(short, long, default_value = "kniznica.json")]
|
||||||
|
subor: PathBuf,
|
||||||
|
|
||||||
|
#[command(subcommand)]
|
||||||
|
prikaz: Prikaz,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
enum Prikaz {
|
||||||
|
/// Pridaj novú knihu
|
||||||
|
Pridaj {
|
||||||
|
/// Názov knihy
|
||||||
|
nazov: String,
|
||||||
|
/// Autor knihy
|
||||||
|
autor: String,
|
||||||
|
/// Rok vydania
|
||||||
|
#[arg(short, long)]
|
||||||
|
rok: u16,
|
||||||
|
/// Stav knihy
|
||||||
|
#[arg(short, long, default_value = "nova")]
|
||||||
|
stav: Stav,
|
||||||
|
},
|
||||||
|
/// Odstráň knihu
|
||||||
|
Odstran {
|
||||||
|
/// Názov knihy
|
||||||
|
nazov: String,
|
||||||
|
},
|
||||||
|
/// Vypíš všetky knihy
|
||||||
|
Vypis {
|
||||||
|
/// Filtrovať podľa stavu
|
||||||
|
#[arg(short, long)]
|
||||||
|
stav: Option<Stav>,
|
||||||
|
},
|
||||||
|
/// Hľadaj knihy podľa autora
|
||||||
|
Hladaj {
|
||||||
|
/// Meno autora
|
||||||
|
autor: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
|
||||||
|
// Načítaj alebo vytvor prázdnu
|
||||||
|
let mut kniznica = Kniznica::nacitaj_zo_suboru(&args.subor)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
match args.prikaz {
|
||||||
|
Prikaz::Pridaj { nazov, autor, rok, stav } => {
|
||||||
|
let kniha = Kniha { nazov, autor, rok, stav };
|
||||||
|
match kniznica.pridaj(kniha) {
|
||||||
|
Ok(()) => println!("Kniha pridaná."),
|
||||||
|
Err(e) => println!("Chyba: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Prikaz::Odstran { nazov } => {
|
||||||
|
match kniznica.odstran(&nazov) {
|
||||||
|
Ok(kniha) => println!("Odstránená: {} ({})", kniha.nazov, kniha.autor),
|
||||||
|
Err(e) => println!("Chyba: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Prikaz::Vypis { stav } => {
|
||||||
|
let knihy: Vec<&Kniha> = match &stav {
|
||||||
|
Some(s) => kniznica.knihy.iter().filter(|k| &k.stav == s).collect(),
|
||||||
|
None => kniznica.knihy.iter().collect(),
|
||||||
|
};
|
||||||
|
if knihy.is_empty() {
|
||||||
|
println!("Žiadne knihy.");
|
||||||
|
} else {
|
||||||
|
for kniha in &knihy {
|
||||||
|
println!("{} — {} ({}) [{:?}]", kniha.nazov, kniha.autor, kniha.rok, kniha.stav);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Prikaz::Hladaj { autor } => {
|
||||||
|
let najdene: Vec<&Kniha> = kniznica.knihy.iter()
|
||||||
|
.filter(|k| k.autor.to_lowercase().contains(&autor.to_lowercase()))
|
||||||
|
.collect();
|
||||||
|
if najdene.is_empty() {
|
||||||
|
println!("Nič nenájdené.");
|
||||||
|
} else {
|
||||||
|
for kniha in &najdene {
|
||||||
|
println!("{} — {}", kniha.nazov, kniha.autor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ulož
|
||||||
|
kniznica.uloz_do_suboru(&args.subor);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Spustenie:
|
||||||
|
```bash
|
||||||
|
./kniznica pridaj "Duna" "Frank Herbert" --rok 1965
|
||||||
|
./kniznica pridaj "Hobbit" "J.R.R. Tolkien" --rok 1937 --stav pouzivana
|
||||||
|
./kniznica vypis
|
||||||
|
./kniznica vypis --stav nova
|
||||||
|
./kniznica hladaj "Tolkien"
|
||||||
|
./kniznica odstran "Duna"
|
||||||
|
./kniznica --subor backup.json vypis
|
||||||
|
```
|
||||||
|
|
||||||
|
### Úlohy 10
|
||||||
|
|
||||||
|
**10a.** Implementuj kompletný CLI pre **Správcu úloh** (Task Manager):
|
||||||
|
```
|
||||||
|
Štruktúra: Uloha { nazov: String, priorita: Priorita, hotova: bool }
|
||||||
|
Enum: Priorita { Nizka, Stredna, Vysoka }
|
||||||
|
|
||||||
|
Subcommands:
|
||||||
|
- pridaj <nazov> --priorita <priorita>
|
||||||
|
- hotovo <nazov>
|
||||||
|
- odstran <nazov>
|
||||||
|
- vypis [--priorita <priorita>]
|
||||||
|
- statistiky (počet celkom, hotových, nehotových)
|
||||||
|
|
||||||
|
Spoločný: --subor (PathBuf, default "ulohy.json")
|
||||||
|
```
|
||||||
|
|
||||||
|
**10b.** Implementuj kompletný CLI pre **Milionár** kvíz:
|
||||||
|
```
|
||||||
|
Subcommands:
|
||||||
|
- pridaj-otazku <text> --odpovede <4 odpovede> --spravna <index>
|
||||||
|
- hraj
|
||||||
|
- vypis-otazky
|
||||||
|
|
||||||
|
Spoločný: --subor (PathBuf, default "otazky.json")
|
||||||
|
```
|
||||||
|
|
||||||
|
**10c.** Implementuj kompletný CLI pre **Adresár**:
|
||||||
|
```
|
||||||
|
Štruktúra: Kontakt { meno: String, telefon: String, email: Option<String> }
|
||||||
|
|
||||||
|
Subcommands:
|
||||||
|
- pridaj <meno> <telefon> [--email <email>]
|
||||||
|
- odstran <meno>
|
||||||
|
- hladaj <vyraz>
|
||||||
|
- vypis [--zoradit]
|
||||||
|
- export --format <json|csv>
|
||||||
|
|
||||||
|
Spoločný: --subor (PathBuf, default "kontakty.json")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prehľad: clap atribúty
|
||||||
|
|
||||||
|
| Atribút | Kde | Čo robí |
|
||||||
|
|---------|-----|---------|
|
||||||
|
| `#[derive(Parser)]` | štruktúra | Hlavná CLI štruktúra |
|
||||||
|
| `#[derive(Subcommand)]` | enum | Podpríkazy |
|
||||||
|
| `#[derive(ValueEnum)]` | enum | Enum ako hodnota argumentu |
|
||||||
|
| `#[command(subcommand)]` | pole | Toto pole je subcommand |
|
||||||
|
| `#[command(about, version)]` | štruktúra | Pridaj popis a verziu |
|
||||||
|
| `#[arg(short, long)]` | pole | Pomenovaný argument |
|
||||||
|
| `#[arg(short = 'x')]` | pole | Vlastné short písmeno |
|
||||||
|
| `#[arg(long = "nazov")]` | pole | Vlastný long názov |
|
||||||
|
| `#[arg(default_value = "...")]` | pole | Default pre String/PathBuf |
|
||||||
|
| `#[arg(default_value_t = N)]` | pole | Default pre čísla/bool |
|
||||||
|
| `#[arg(required = true)]` | pole | Vynúť aj Vec |
|
||||||
|
| `#[arg(value_parser = ...)]` | pole | Validácia |
|
||||||
|
| `/// komentár` | štruktúra/pole | Help text |
|
||||||
|
|
||||||
|
## Prehľad: typy polí
|
||||||
|
|
||||||
|
| Typ poľa | Správanie |
|
||||||
|
|-----------|-----------|
|
||||||
|
| `String` | Povinný argument |
|
||||||
|
| `Option<String>` | Voliteľný argument |
|
||||||
|
| `bool` | Flag (true/false) |
|
||||||
|
| `Vec<String>` | Viacero hodnôt |
|
||||||
|
| `PathBuf` | Cesta k súboru |
|
||||||
|
| `u32, i32, f64...` | Automaticky parsované |
|
||||||
|
| `MojEnum` (ValueEnum) | Povolené hodnoty |
|
||||||
Reference in New Issue
Block a user