diff --git a/Cargo.toml b/Cargo.toml index 2da1c4e..1e16028 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "smurf" -version = "0.1.1" +version = "0.2.0" edition = "2021" authors = ["Ivan Bushchik "] description = "SMall Useful Rust Functions" diff --git a/README.md b/README.md index d735809..81c2dc2 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,51 @@ > SMall Useful Rust Functions -## Components +## Components + +### IO + +- macros input!(T) and input_vec!(T), that could be used to simplify stdin process +- read_file_to_str() basically reads file to string (yes.) ### Shell -- macro `shell!` +- macros shell!() +## Usage -### File +Add this to your `Cargo.toml`: -- function `read_to_str` \ No newline at end of file +```toml +[dependencies] +smurf = "0.2" +``` + +and this to your crate root: + +```rust +extern crate smurf; +``` + +## Example + +```rust +use smurf; +use std::io::Write; + +fn main() { + print!("What is your name? "); + std::io::stdout().flush().unwrap(); + let user_name = input!(String); + print!("What is your age? "); + std::io::stdout().flush().unwrap(); + let user_age = input!(u8); + let shell_output = shell!("echo Hello {} of age {}", user_name, user_age); // Returns ShellResult {code: i32, stdout: String, stderr: String} + println!("Shell output: {}", shell_output.stdout); + println!("Shell stderr: {}", shell_output.stderr); + println!("Shell exit code: {}", shell_output.code); +} +``` + +## License + +[MIT](LICENSE-MIT) diff --git a/src/file.rs b/src/file.rs deleted file mode 100644 index 1b6d47f..0000000 --- a/src/file.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::fs::File; -use std::io::{prelude::*, BufReader}; - -pub fn read_to_str(path: &std::path::PathBuf) -> String { - let file = File::open(&path); - let file = match file { - Ok(data) => data, - Err(_) => { - eprintln!("Cannot open file \"{}\"", path.display()); - std::process::exit(2) - } - }; - let mut buf_reader = BufReader::new(file); - let mut content = String::new(); - buf_reader.read_to_string(&mut content).unwrap(); - content -} diff --git a/src/io.rs b/src/io.rs new file mode 100644 index 0000000..01a2c4e --- /dev/null +++ b/src/io.rs @@ -0,0 +1,40 @@ +use std::fs::File; +use std::io::{prelude::*, BufReader}; + +pub fn read_file_to_str(path: &std::path::PathBuf) -> Option { + let file = File::open(&path); + let file = match file { + Ok(data) => data, + Err(_) => { + eprintln!("Cannot open file \"{}\"", path.display()); + return None + } + }; + let mut buf_reader = BufReader::new(file); + let mut content = String::new(); + buf_reader.read_to_string(&mut content).unwrap(); + Some(content) +} + + +#[macro_export] +macro_rules! input { + ($t:ty) => { + { + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + input.trim().parse::<$t>().unwrap() + } + } +} + +#[macro_export] +macro_rules! input_vec { + ($t:ty) => { + { + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + input.trim().split_whitespace().map(|x| x.parse::<$t>().unwrap()).collect::>() + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 902f3dd..d734cd4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,2 @@ -pub mod file; +pub mod io; pub mod shell; diff --git a/src/shell.rs b/src/shell.rs index eec40ad..5b6c647 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -12,8 +12,7 @@ pub struct ShellResult { pub stdout: String, pub stderr: String, } - -#[allow(dead_code)] + pub fn run(command: String) -> ShellResult { let mut iter = command.split_whitespace(); let mut current = iter.next(); @@ -24,6 +23,7 @@ pub fn run(command: String) -> ShellResult { } let command = Command::new(&words[0]) .args(&words[1..]) + .env("PATH", "/bin:/usr/bin") // TODO: Make this configurable .output() .expect(&format!("Failed to execute '{}'", command)); return ShellResult { @@ -32,3 +32,44 @@ pub fn run(command: String) -> ShellResult { stderr: String::from_utf8(command.stderr).unwrap(), }; } + +#[cfg(test)] +mod tests { + #[test] + fn test_shell_macro() { + let result = shell!("echo hello"); + assert_eq!(result.code, 0); + assert_eq!(result.stdout, "hello\n"); + assert_eq!(result.stderr, ""); + } + + /* You literally can't use pipe using std::process::Command */ + // TODO: figure out how to test this + #[ignore] + #[test] + fn test_shell_macro_with_stderr() { + let result = shell!("echo hello 1>&2"); + assert_eq!(result.code, 0); + assert_eq!(result.stdout, ""); + assert_eq!(result.stderr, "hello\n"); + } + + #[test] + fn test_shell_macro_with_args() { + let result = shell!("echo {} {}", "hello", "world"); + assert_eq!(result.code, 0); + assert_eq!(result.stdout, "hello world\n"); + assert_eq!(result.stderr, ""); + } + + // TODO: figure out how to test this + #[ignore] + #[test] + fn test_shell_macro_with_code() { + let result = shell!("sh -c exit 1"); + assert_eq!(result.code, 1); + assert_eq!(result.stdout, ""); + assert_eq!(result.stderr, ""); + } + +} \ No newline at end of file