<style> /* basic design */ .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6, .reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p { font-family: 'Meiryo UI', 'Source Sans Pro', Helvetica, sans-serif, 'Helvetica Neue', 'Helvetica', 'Arial', 'Hiragino Sans', 'ヒラギノ角ゴシック', YuGothic, 'Yu Gothic'; text-align: left; line-height: 1.6; letter-spacing: normal; text-shadow: none; word-wrap: break-word; color: #444; } .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {font-weight: bold;} .reveal h1, .reveal h2, .reveal h3 {color: #2980b9;} .reveal th {background: #DDD;} .reveal section img {background:none; border:none; box-shadow:none; max-width: 95%; max-height: 95%;} .reveal blockquote {width: 90%; padding: 0.5vw 3.0vw;} .reveal table {margin: 1.0vw auto;} .reveal code {line-height: 1.2;} .reveal p, .reveal li {padding: 0vw; margin: 0vw;} .reveal .box {margin: -0.5vw 1.5vw 2.0vw -1.5vw; padding: 0.5vw 1.5vw 0.5vw 1.5vw; background: #EEE; border-radius: 1.5vw;} /* table design */ .reveal table {background: #f5f5f5;} .reveal th {background: #444; color: #fff;} .reveal td {position: relative; transition: all 300ms;} .reveal tbody:hover td { color: transparent; text-shadow: 0 0 3px #aaa;} .reveal tbody:hover tr:hover td {color: #444; text-shadow: 0 1px 0 #fff;} /* blockquote design */ .reveal blockquote { width: 90%; padding: 0.5vw 0 0.5vw 6.0vw; font-style: italic; background: #f5f5f5; } .reveal blockquote:before{ position: absolute; top: 0.1vw; left: 1vw; content: "\f10d"; font-family: FontAwesome; color: #2980b9; font-size: 3.0vw; } /* font size */ .reveal h1 {font-size: 5.0vw;} .reveal h2 {font-size: 4.0vw;} .reveal h3 {font-size: 2.8vw;} .reveal h4 {font-size: 2.6vw;} .reveal h5 {font-size: 2.4vw;} .reveal h6 {font-size: 2.2vw;} .reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {font-size: 2.2vw;} .reveal code {font-size: 1.6vw;} /* new color */ .red {color: #EE6557;} .blue {color: #16A6B6;} /* split slide */ #right {left: -18.33%; text-align: left; float: left; width: 50%; z-index: -10;} #left {left: 31.25%; text-align: left; float: left; width: 50%; z-index: -10;} </style> <style> /* specific design */ .reveal h2 { padding: 0 1.5vw; margin: 0.0vw 0 2.0vw -2.0vw; border-left: solid 1.2vw #2980b9; border-bottom: solid 0.8vw #d7d7d7; } </style> <!-- --------------------------------------------------------------------------------------- --> # Rust勉強会 第12回 ## 12章 入出力プロジェクト 後半 ### 2020/10/23 岡本拓海 --- ## 本日のメニュー 1. テスト駆動開発でのライブラリの機能を開発する 2. 環境変数を取り扱う 3. 標準出力ではなく、標準エラーにエラーメッセージを書き込む プレゼン20分くらい+議論10分位で18:30前後終了を目指します。 --- ## テスト駆動開発でライブラリの機能を開発する ### 前回 minigrepクレートを作成してちょっとしたRustのプロジェクトを作りました。 ```rust use std::error::Error; use std::fs::File; use std::io::prelude::*; pub struct Config { pub query: String, pub filename: String, } impl Config { pub fn new(args: &[String]) -> Result<Config, &'static str> { // --snip-- } } pub fn run(config: Config) -> Result<(), Box<Error>> { // --snip-- } ``` ---- ## テストを書いてみよう!! * ```#[cfg(test)]```でテストモジュールの定義 * ```#[test]``` でユニットテストを記述できます ```rust #[cfg(test)] mod test { use super::*; #[test] fn one_result() { let query = "duct"; let contents = "\ Rust: safe, fast, productive. Pick three."; assert_eq!( vec!["safe, fast, productive."], search(query, contents) ); } } ``` ---- ## search関数の最低限の実装 ```rust= pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { vec![] } ``` ---- ## テストを走らせてみよう ```bash $ cargo test Compiling minigrep v0.1.0 (file:///projects/minigrep) --warnings-- Finished dev [unoptimized + debuginfo] target(s) in 0.43 secs Running target/debug/deps/minigrep-abcabcabc running 1 test test test::one_result ... FAILED failures: ---- test::one_result stdout ---- thread 'test::one_result' panicked at 'assertion failed: `(left == right)` left: `["safe, fast, productive."]`, right: `[]`)', src/lib.rs:48:8 note: Run with `RUST_BACKTRACE=1` for a backtrace. failures: test::one_result test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out error: test failed, to rerun pass '--li ``` 想定どおりテストは失敗しましたね!! ---- ## テストを通過させるコードを書く 実装する操作は以下の通り * 中身を各行ごとに繰り返す。 * 行にクエリ文字列が含まれるか確認する。 * するなら、それを返却する値のリストに追加する。 * しないなら、何もしない。 * 一致する結果のリストを返す。 ---- ## テストを通過するコード ```rust pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { let mut results = Vec::new(); for line in contents.lines() { if line.contains(query) { results.push(line); } } results } ``` ---- ## 再度テスト ```bash $ cargo test --snip-- running 1 test test test::one_result ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` 成功しました!! --- ## 環境変数を取り扱う 環境変数を取り扱うのには```std::env```を使用します ```rust let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); ``` ---- ## 環境変数を使用した場合のテスト ```rust=#[cfg(test)] mod test { use super::*; // ---snip--- #[test] fn case_insensitive() { let query = "rUsT"; let contents = "\ Rust: safe, fast, productive. Pick three. Trust me."; assert_eq!( vec!["Rust:", "Trust me."], search_case_insensitive(query, contents) ); } } ``` ---- ## search_case_insensitive関数を実装する ```rust pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { let query = query.to_lowercase(); let mut results = Vec::new(); for line in contents.lines() { if line.to_lowercase().contains(&query) { results.push(line); } } results } ``` ---- ## 実行する ```bash $ CASE_INSENSITIVE=1 cargo run to poem.txt Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/minigrep to poem.txt` Are you nobody, too? How dreary to be somebody! To tell your name the livelong day To an admiring bog! ``` --- ## 標準出力ではなく、標準エラー出力にエラーメッセージを書き込む プログラムの正常な出力以外のエラーなどが表示されることを避けたい場合があります。 例えば、リダイレクトで結果をファイルに保存した場合等 現行のプログラムではpanicした内容も出力されてしまうのでエラー出力に出力しましょう。 ---- ## eprintln!マクロで標準エラー出力に書き込む eprintln!マクロを使うことで標準エラー出力に書き込むことができます。 ``` rust eprintln!("This is some error!! caused by {}", err); ``` ```rust= fn main() { let args: Vec<String> = env::args().collect(); let config = Config::new(&args).unwrap_or_else(|err| { eprintln!("Problem parsing arguments: {}", err); process::exit(1); }); if let Err(e) = minigrep::run(config) { eprintln!("Application error: {}", e); process::exit(1); } } ``` --- ## 参考資料 https://doc.rust-jp.rs/book-ja/ch12-00-an-io-project.html --- # ご清聴ありがとうございました
{"metaMigratedAt":"2023-06-15T14:28:42.987Z","metaMigratedFrom":"YAML","title":"第12回 12章後半 テスト,環境変数,標準エラー","breaks":true,"description":"Rust勉強会第7回のスライド","slideOptions":"{\"theme\":\"white\",\"slideNumber\":\"c/t\",\"center\":false,\"transition\":\"none\",\"keyboard\":true}","contributors":"[{\"id\":\"610cfd52-ad2b-46e8-81e2-a79a85a7f06f\",\"add\":7308,\"del\":180}]"}
    256 views