<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}]"}