mirror of
https://github.com/rust-lang-cn/book-cn.git
synced 2025-02-02 15:28:40 +08:00
Merge remote-tracking branch 'origin/pr/177'
This commit is contained in:
commit
f98fe55965
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,5 @@
|
||||
book/
|
||||
*~
|
||||
.idea
|
||||
.DS_Store
|
||||
target
|
140
Cargo.lock
generated
Normal file
140
Cargo.lock
generated
Normal file
@ -0,0 +1,140 @@
|
||||
[root]
|
||||
name = "rust-book"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"docopt 0.6.82 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "docopt"
|
||||
version = "0.6.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.1.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "thread-id"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9"
|
||||
"checksum docopt 0.6.82 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20016093b4e545dccf6ad4a01099de0b695f9bc99b08210e68f6425db2d37d"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
|
||||
"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2"
|
||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||
"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2"
|
||||
"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199"
|
||||
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
|
||||
"checksum strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4d73a2c36a4d095ed1a6df5cbeac159863173447f7a82b3f4757426844ab825"
|
||||
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
||||
"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d"
|
||||
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
||||
"checksum walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad450634b9022aeb0e8e7f1c79c1ded92d0fc5bee831033d148479771bd218d"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "rust-book"
|
||||
version = "0.0.1"
|
||||
authors = ["Steve Klabnik <steve@steveklabnik.com>"]
|
||||
description = "The Rust Book"
|
||||
|
||||
[dependencies]
|
||||
walkdir = "0.1.5"
|
||||
docopt = "0.6.82"
|
||||
rustc-serialize = "0.3.19"
|
245
src/bin/lfp.rs
Normal file
245
src/bin/lfp.rs
Normal file
@ -0,0 +1,245 @@
|
||||
extern crate rustc_serialize;
|
||||
extern crate docopt;
|
||||
use docopt::Docopt;
|
||||
extern crate walkdir;
|
||||
use std::{path, fs, io};
|
||||
use std::io::{BufRead, Write};
|
||||
|
||||
macro_rules! println_stderr(
|
||||
($($arg:tt)*) => (
|
||||
match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
|
||||
Ok(_) => {},
|
||||
Err(x) => panic!("Unable to write to stderr: {}", x),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
fn main () {
|
||||
let args: Args = Docopt::new(USAGE)
|
||||
.and_then(|d| d.decode())
|
||||
.unwrap_or_else(|e| e.exit());
|
||||
|
||||
let src_dir = &path::Path::new(&args.arg_src_dir);
|
||||
let found_errs = walkdir::WalkDir::new(src_dir)
|
||||
.min_depth(1)
|
||||
.into_iter()
|
||||
.map(|entry| {
|
||||
match entry {
|
||||
Ok(entry) => entry,
|
||||
Err(err) => {
|
||||
println_stderr!("{:?}", err);
|
||||
std::process::exit(911)
|
||||
},
|
||||
}
|
||||
})
|
||||
.map(|entry| {
|
||||
let path = entry.path();
|
||||
if is_file_of_interest(path) {
|
||||
let err_vec = lint_file(path);
|
||||
for err in &err_vec {
|
||||
match *err {
|
||||
LintingError::LineOfInterest(line_num, ref line) =>
|
||||
println_stderr!("{}:{}\t{}", path.display(), line_num, line),
|
||||
LintingError::UnableToOpenFile =>
|
||||
println_stderr!("Unable to open {}.", path.display()),
|
||||
}
|
||||
}
|
||||
!err_vec.is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.iter()
|
||||
.any(|result| *result);
|
||||
|
||||
if found_errs {
|
||||
std::process::exit(1)
|
||||
} else {
|
||||
std::process::exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
const USAGE: &'static str = "
|
||||
counter
|
||||
Usage:
|
||||
lfp <src-dir>
|
||||
lfp (-h | --help)
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
";
|
||||
|
||||
#[derive(Debug, RustcDecodable)]
|
||||
struct Args {
|
||||
arg_src_dir: String,
|
||||
}
|
||||
|
||||
fn lint_file(path: &path::Path) -> Vec<LintingError> {
|
||||
match fs::File::open(path) {
|
||||
Ok(file) => lint_lines(io::BufReader::new(&file).lines()),
|
||||
Err(_) => vec![LintingError::UnableToOpenFile],
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_lines<I>(lines: I) -> Vec<LintingError>
|
||||
where I: Iterator<Item=io::Result<String>> {
|
||||
lines
|
||||
.enumerate()
|
||||
.map(|(line_num, line)| {
|
||||
let raw_line = line.unwrap();
|
||||
if is_line_of_interest(&raw_line) {
|
||||
Err(LintingError::LineOfInterest(line_num, raw_line))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
.filter(|result| result.is_err())
|
||||
.map(|result| result.unwrap_err())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn is_file_of_interest(path: &path::Path) -> bool {
|
||||
path.extension()
|
||||
.map_or(false, |ext| ext == "md")
|
||||
}
|
||||
|
||||
fn is_line_of_interest(line: &str) -> bool {
|
||||
!line.split_whitespace()
|
||||
.filter(|sub_string| sub_string.contains("file://") && !sub_string.contains("file:///projects/"))
|
||||
.collect::<Vec<_>>()
|
||||
.is_empty()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum LintingError {
|
||||
UnableToOpenFile,
|
||||
LineOfInterest(usize, String)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use std::path;
|
||||
|
||||
#[test]
|
||||
fn lint_file_returns_a_vec_with_errs_when_lines_of_interest_are_found() {
|
||||
let string = r#"
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 61
|
||||
Please input your guess.
|
||||
10
|
||||
You guessed: 10
|
||||
Too small!
|
||||
Please input your guess.
|
||||
99
|
||||
You guessed: 99
|
||||
Too big!
|
||||
Please input your guess.
|
||||
foo
|
||||
Please input your guess.
|
||||
61
|
||||
You guessed: 61
|
||||
You win!
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
|
||||
Running `target/debug/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 7
|
||||
Please input your guess.
|
||||
4
|
||||
You guessed: 4
|
||||
$ cargo run
|
||||
Running `target/debug/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 83
|
||||
Please input your guess.
|
||||
5
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
|
||||
Running `target/debug/guessing_game`
|
||||
Hello, world!
|
||||
"#;
|
||||
|
||||
let raw_lines = string.to_string();
|
||||
let lines = raw_lines.lines().map(|line| {
|
||||
Ok(line.to_string())
|
||||
});
|
||||
|
||||
let result_vec = super::lint_lines(lines);
|
||||
|
||||
assert!(!result_vec.is_empty());
|
||||
assert_eq!(3, result_vec.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lint_file_returns_an_empty_vec_when_no_lines_of_interest_are_found() {
|
||||
let string = r#"
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 61
|
||||
Please input your guess.
|
||||
10
|
||||
You guessed: 10
|
||||
Too small!
|
||||
Please input your guess.
|
||||
99
|
||||
You guessed: 99
|
||||
Too big!
|
||||
Please input your guess.
|
||||
foo
|
||||
Please input your guess.
|
||||
61
|
||||
You guessed: 61
|
||||
You win!
|
||||
"#;
|
||||
|
||||
let raw_lines = string.to_string();
|
||||
let lines = raw_lines.lines().map(|line| {
|
||||
Ok(line.to_string())
|
||||
});
|
||||
|
||||
let result_vec = super::lint_lines(lines);
|
||||
|
||||
assert!(result_vec.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_file_of_interest_returns_false_when_the_path_is_a_directory() {
|
||||
let uninteresting_fn = "src/img";
|
||||
|
||||
assert!(!super::is_file_of_interest(path::Path::new(uninteresting_fn)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_file_of_interest_returns_false_when_the_filename_does_not_have_the_md_extension() {
|
||||
let uninteresting_fn = "src/img/foo1.png";
|
||||
|
||||
assert!(!super::is_file_of_interest(path::Path::new(uninteresting_fn)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_file_of_interest_returns_true_when_the_filename_has_the_md_extension() {
|
||||
let interesting_fn = "src/ch01-00-introduction.md";
|
||||
|
||||
assert!(super::is_file_of_interest(path::Path::new(interesting_fn)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_line_of_interest_does_not_report_a_line_if_the_line_contains_a_file_url_which_is_directly_followed_by_the_project_path() {
|
||||
let sample_line = "Compiling guessing_game v0.1.0 (file:///projects/guessing_game)";
|
||||
|
||||
assert!(!super::is_line_of_interest(sample_line));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_line_of_interest_reports_a_line_if_the_line_contains_a_file_url_which_is_not_directly_followed_by_the_project_path() {
|
||||
let sample_line = "Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)";
|
||||
|
||||
assert!(super::is_line_of_interest(sample_line));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user