Skip to content

Commit 0e89071

Browse files
authored
Merge pull request #94 from shnmorimoto/add_9-4_9_7
Add 9.5.4 - 9.5.7
2 parents e230158 + 5ebdf3d commit 0e89071

File tree

9 files changed

+263
-4
lines changed

9 files changed

+263
-4
lines changed

Cargo.lock

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

chapter9/Cargo.toml

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ edition = "2018"
88

99
[dependencies]
1010
lib = { path = "../lib" }
11+
glob = "0.3.0"
12+
walkdir = "2"
13+
14+
[[bin]]
15+
name = "main_9_2_1"
16+
path = "src/main_9_2_1.rs"
17+
18+
[[bin]]
19+
name = "main_9_2_3"
20+
path = "src/main_9_2_3.rs"
1121

1222
[[bin]]
1323
name = "main_9_2_4"
@@ -26,9 +36,17 @@ name = "9_5_3"
2636
path = "src/9_5_3/main.rs"
2737

2838
[[bin]]
29-
name = "main_9_2_1"
30-
path = "src/main_9_2_1.rs"
39+
name = "9_5_4"
40+
path = "src/9_5_4/main.rs"
3141

3242
[[bin]]
33-
name = "main_9_2_3"
34-
path = "src/main_9_2_3.rs"
43+
name = "9_5_5"
44+
path = "src/9_5_5/main.rs"
45+
46+
[[bin]]
47+
name = "9_5_6"
48+
path = "src/9_5_6/main.rs"
49+
50+
[[bin]]
51+
name = "9_5_7"
52+
path = "src/9_5_7/main.rs"

chapter9/src/9_5_4/main.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use lib::path::*;
2+
use std::path::Path;
3+
4+
fn main() -> Result<(), PathError> {
5+
//存在しないパスを指定した場合、エラーを返す
6+
7+
// パスをそのままクリーンにする
8+
let path = Path::new("./chapter9/src/../src/9_5_4/main.rs").clean()?;
9+
println!("{:?}", path);
10+
11+
// パスを絶対パスに整形
12+
let abs_path = Path::new("./chapter9/src/9_5_4/main.rs").canonicalize()?;
13+
println!("{:?}", abs_path);
14+
15+
// パスを相対パスに整形
16+
let abs_path = Path::new("/usr/local/go/bin/go");
17+
let rel_path = abs_path.strip_prefix("/usr/local/go")?;
18+
println!("{:?}", rel_path);
19+
20+
Ok(())
21+
}

chapter9/src/9_5_5/main.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use lib::path::{ExtendedPath, PathError};
2+
use std::path::{Path, PathBuf};
3+
4+
// パス中のenvを展開した上でcleanする
5+
fn clean2(path: &Path) -> Result<PathBuf, PathError> {
6+
let path = path.expand_env()?;
7+
let path = path.clean()?;
8+
Ok(path)
9+
}
10+
11+
fn main() -> Result<(), PathError> {
12+
//存在しないパスを指定した場合、エラーを返す
13+
14+
let path = Path::new("${HOME}/.bashrc");
15+
println!("{:?}", clean2(path)?);
16+
17+
let path = Path::new("~/.bashrc");
18+
println!("{:?}", clean2(path)?);
19+
20+
Ok(())
21+
}

chapter9/src/9_5_6/main.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use glob::{glob, Pattern, PatternError};
2+
use std::path::PathBuf;
3+
4+
fn main() -> Result<(), PatternError> {
5+
let pattern = Pattern::new("image-*.png")?;
6+
println!("{}", pattern.matches("image-100.png"));
7+
8+
let paths = glob("./*.png")?;
9+
let files: Vec<PathBuf> = paths.into_iter().filter_map(Result::ok).collect();
10+
println!("{:?}", files);
11+
Ok(())
12+
}

chapter9/src/9_5_7/main.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use lib::path::PathError;
2+
use std::{collections::HashSet, env};
3+
use walkdir::WalkDir;
4+
5+
fn main() -> Result<(), PathError> {
6+
let args: Vec<String> = env::args().collect();
7+
if args.len() == 1 {
8+
println!(
9+
"Find images
10+
11+
Usage:
12+
{} [path to find]",
13+
&args[0]
14+
);
15+
std::process::exit(0);
16+
}
17+
let root = &args[1];
18+
let image_suffix: HashSet<&'static str> = ["jpg", "jpeg", "png", "webp", "gif", "tiff", "eps"]
19+
.iter()
20+
.cloned()
21+
.collect();
22+
// ディレクトリのトラバースのためにwalkdir crateを利用する
23+
// ディレクトリ、拡張子が合わないものについては、フィルタして除外する
24+
// walkdir crateでは指定のディレクトリをスキップするような機能は存在しない
25+
for path in WalkDir::new(root)
26+
.into_iter()
27+
.filter_map(Result::ok)
28+
.filter(|f| !f.file_type().is_dir())
29+
.filter(|f| {
30+
let extention_opt = f
31+
.path()
32+
.extension()
33+
.and_then(|ext| ext.to_str())
34+
.map(|ext| ext.to_lowercase());
35+
let extention = extention_opt.as_deref().unwrap_or("");
36+
image_suffix.contains(extention)
37+
})
38+
{
39+
println!("{}", path.into_path().display());
40+
}
41+
42+
Ok(())
43+
}

lib/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ edition = "2018"
88

99
[dependencies]
1010
crc32fast = "1.2.1"
11+
regex = "1.5"
12+
once_cell = "1.7.2"

lib/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ pub mod binary;
22
pub mod env;
33
pub mod image;
44
pub mod io;
5+
pub mod path;

lib/src/path.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
use once_cell::sync::Lazy;
2+
use regex::Regex;
3+
use std::path::Path;
4+
use std::path::PathBuf;
5+
use std::{env, ffi::OsStr};
6+
7+
#[derive(Debug)]
8+
pub enum PathError {
9+
IoError(std::io::Error),
10+
StripPrefixError(std::path::StripPrefixError),
11+
RegexError(regex::Error),
12+
VarError(std::env::VarError),
13+
}
14+
15+
impl From<std::io::Error> for PathError {
16+
fn from(error: std::io::Error) -> Self {
17+
PathError::IoError(error)
18+
}
19+
}
20+
21+
impl From<std::path::StripPrefixError> for PathError {
22+
fn from(error: std::path::StripPrefixError) -> Self {
23+
PathError::StripPrefixError(error)
24+
}
25+
}
26+
27+
impl From<regex::Error> for PathError {
28+
fn from(error: regex::Error) -> Self {
29+
PathError::RegexError(error)
30+
}
31+
}
32+
33+
impl From<std::env::VarError> for PathError {
34+
fn from(error: std::env::VarError) -> Self {
35+
PathError::VarError(error)
36+
}
37+
}
38+
39+
static RE_VAR: Lazy<Regex> = Lazy::new(|| Regex::new(r"\$\{(.+)\}").unwrap());
40+
41+
static RE_VAR_WITHOUT_BRACES: Lazy<Regex> = Lazy::new(|| Regex::new(r"\$(.+)").unwrap());
42+
43+
static TILDE: Lazy<&OsStr> = Lazy::new(|| OsStr::new("~"));
44+
45+
/// extend path::Path
46+
/// add useful functions to path::Path
47+
///
48+
/// # Examples
49+
///
50+
/// ```
51+
/// use lib::path::{ExtendedPath, PathError};
52+
/// use std::path::Path;
53+
///
54+
/// fn main() -> Result<(), PathError> {
55+
/// let path = Path::new("./src/../Cargo.toml");
56+
/// let cleaned_path = path.clean()?;
57+
/// println!("cleaned path: {:?}", cleaned_path);
58+
///
59+
/// let path = Path::new("~/.cargo");
60+
/// let expanded_path = path.expand_env()?;
61+
/// println!("expanded env path: {:?}", expanded_path);
62+
/// Ok(())
63+
/// }
64+
/// ```
65+
pub trait ExtendedPath {
66+
fn clean(&self) -> Result<PathBuf, PathError>;
67+
fn expand_env(&self) -> Result<PathBuf, PathError>;
68+
}
69+
70+
impl ExtendedPath for Path {
71+
fn clean(&self) -> Result<PathBuf, PathError> {
72+
let abs_path = self.canonicalize()?;
73+
if self.is_absolute() {
74+
return Ok(abs_path);
75+
}
76+
let current_dir = env::current_dir()?;
77+
abs_path
78+
.strip_prefix(current_dir)
79+
.map(|path| path.to_path_buf())
80+
.map_err(|e| e.into())
81+
}
82+
83+
fn expand_env(&self) -> Result<PathBuf, PathError> {
84+
let mut path_buf = PathBuf::new();
85+
for path in self.iter() {
86+
let path_str = path.to_string_lossy();
87+
let caps_opt = RE_VAR
88+
.captures(&path_str)
89+
.or_else(|| RE_VAR_WITHOUT_BRACES.captures(&path_str));
90+
if let Some(caps) = caps_opt {
91+
let expanded_var = env::var(&caps[1])?;
92+
path_buf.push(expanded_var);
93+
continue;
94+
}
95+
if *TILDE == path {
96+
let home_dir = env::var("HOME")?;
97+
path_buf.push(home_dir);
98+
continue;
99+
}
100+
101+
path_buf.push(path);
102+
}
103+
Ok(path_buf)
104+
}
105+
}

0 commit comments

Comments
 (0)