15 个版本
0.1.15 | 2024 年 6 月 8 日 |
---|---|
0.1.14 | 2024 年 6 月 6 日 |
0.1.13 | 2024 年 5 月 20 日 |
0.1.8 | 2024 年 4 月 13 日 |
0.1.1 | 2024 年 1 月 24 日 |
137 在 命令行工具 中
122 每月下载量
415KB
7.5K SLoC
RustyDumbTools (v0.1.15)
一系列作为 Rust 模块存在的 简单工具
crate::progress::DumbProgressIndicator
: 一个简单的Iterator
包装器,有助于显示迭代的进度。crate::arg::DumbArgParser
: 一个简单的参数解析器。它可以用于处理 Rust 程序的命令行参数解析。crate::json::DumbJsonProcessor
: 一个简单的 JSON 处理器/流解析器,它处理输入的 JSON(可能是一部分一部分流式传输)。它不像返回解析后的 JSON 为某些对象一样;一旦识别出 JSON 条目,就会为这些识别出的 JSON 条目调用配置的回调。crate::calc::DumbCalcProcessor
: 一个简单的中缀计算处理器,它可以用于在 Rust 中实现简单的计算器。crate::calculator::DumbCalculator
:一个简单的计算器,可以接受像真实计算器一样的输入键。它可以用于在 Rust 中实现简单的计算器用户界面。crate::ltemp::DumbLineTemplate
:一个简单的行模板,用于格式化一行。它可以用于以模板形式打印值。crate::lblscreen::DumbLineByLineScreen
:一个终端/基于文本的“屏幕”更新助手。它扩展自crate::ltemp::DumbLineTemplate
,有助于管理作为“屏幕”的格式化行的更新。
DumbProgressIndicator
的示例代码
简单
use rusty_dumb_tools::prelude::*;
pub fn try_simple_progress_range() {
for i in dpir!(0..6, name = "RANGE", desc = "demo iteration of range") {
println!(" i is {}", i);
thread::sleep(Duration::from_millis(1000));
}
}
注意,dpir
是一个宏,用于将 Range
(0..6
) 包装成一个 DumbProgressIndicator
对象,该对象实现了 Iterator
特性,因此可以在 for 语句中使用。
输出将类似于
💠 RANGE: 1/6 🌑🌓🌕🌕🌕🌕🌕🌕🌕🌕 – demo iteration of range 💠 … i is 0
💠 RANGE: 2/6 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 – demo iteration of range 💠 … i is 1
💠 RANGE: 3/6 🌑🌑🌑🌑🌑🌕🌕🌕🌕🌕 – demo iteration of range 💠 … i is 2
💠 RANGE: 4/6 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 – demo iteration of range 💠 … i is 3
💠 RANGE: 5/6 🌑🌑🌑🌑🌑🌑🌑🌑🌕🌕 – demo iteration of range 💠 … i is 4
💠 RANGE: 6/6 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 – demo iteration of range 💠 … i is 5
嵌套
use rusty_dumb_tools::prelude::*;
pub fn try_nested_progress() {
for i in dpir!(0..3, name = "RANGE") {
let items = vec![
String::from("apple"),
String::from("banana"),
String::from("orange"),
];
for item in dpi_iter!(items, name = "VECTOR") {
println!(" i is {}; item is {}", i, item);
thread::sleep(Duration::from_millis(1000));
}
}
}
注意,dpi_iter
是一个宏,用于将 Vec
items.iter()
包装成一个 DumbProgressIndicator
对象,该对象实现了 Iterator
特性,因此可以在 for 语句中使用。
输出将类似于
💠 RANGE: 1/3 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 💠 VECTOR: 1/3 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 💠 … i is 0; item is apple
💠 RANGE: 1/3 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 💠 VECTOR: 2/3 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 💠 … i is 0; item is banana
💠 RANGE: 1/3 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 💠 VECTOR: 3/3 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 💠 … i is 0; item is orange
💠 RANGE: 2/3 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 💠 VECTOR: 1/3 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 💠 … i is 1; item is apple
💠 RANGE: 2/3 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 💠 VECTOR: 2/3 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 💠 … i is 1; item is banana
💠 RANGE: 2/3 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 💠 VECTOR: 3/3 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 💠 … i is 1; item is orange
💠 RANGE: 3/3 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 💠 VECTOR: 1/3 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 💠 … i is 2; item is apple
💠 RANGE: 3/3 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 💠 VECTOR: 2/3 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 💠 … i is 2; item is banana
💠 RANGE: 3/3 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 💠 VECTOR: 3/3 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 💠 … i is 2; item is orange
DumbArgParser
的示例代码
use rusty_dumb_tools::prelude::*;
pub fn arg_parser_sample(provide_sample_args: bool) {
let mut parser = DumbArgParser::new();
parser.set_description("This is a simple argument parser.");
dap_arg!("-v", flag2 = "--verbose", fixed = true).add_to(&mut parser); // argument flag "-v" / "--verbose" with fixed value (true) when the flag is present
dap_arg!("-n", flag2 = "--name", default = "nobody").add_to(&mut parser); // argument "-n" / "--name" requiring input value, with default "nobody"
dap_arg!("str-arg").add_to(&mut parser); // positional argument "str-arg" (of type String)
dap_arg!("i32-arg", value = 123).add_to(&mut parser); // positional argument "i32-arg" of type i32 (inferred from the value 123)
dap_arg!("multi-arg").set_multi().add_to(&mut parser); // positional multi-argument "multi-arg" that will accept multiple values (one + rest)
if provide_sample_args {
let in_args: Vec<&str> = vec!["-v", "STR", "888", "m1", "m2", "m3"]; // explicitly provide arguments
parser.process_args(in_args); // parse from command-line arguments
} else {
parser.parse_args(); // parse from command-line arguments
}
println!(". -v: {:?}", parser.get::<bool>("-v"));
println!(". --verbose: {:?}", parser.get::<bool>("--verbose")); // will be the same parameter value as "-v"
println!(". --name: {:?}", parser.get::<String>("--name")); // can use "-n" as well
println!(". str-arg: {:?}", parser.get::<String>("str-arg"));
println!(". i32-arg: {:?}", parser.get::<i32>("i32-arg"));
println!(". multi-arg: {:?}", parser.get_multi::<String>("multi-arg"));
}
如果将 provide_sample_args
设置为 false
,即没有提供参数,输出将类似于
| !!!
| !!! INVALID INPUT ARGUMENT: argument [str-arg] not provided
| !!!
| USAGE: rusty_dumb_tools [-h] [-v] [-n name] <str-arg> <i32-arg> <multi-arg>
| : This is a simple argument parser.
| . -h, --help : HELP
| . -v, --verbose : FLAG [true]
| . -n name, --name name : OPTIONAL; default [nobody]
| . <str-arg> : REQUIRED; e.g.
| . <i32-arg> : REQUIRED; e.g. 123
| . <multi-arg> ... : REQUIRED; e.g. ...
如果将 provide_sample_args
设置为 true
,输出将类似于
. -v: Some(true)
. --verbose: Some(true)
. --name: Some("nobody")
. str-arg: Some("STR")
. i32-arg: Some(888)
. multi-arg: Some(["m1", "m2", "m3"])
下一节将展示使用这些工具的示例程序。子示例“选择”实际上是使用 `DumbArgParser` 以及为选中的子示例进行的“子选择”实现的
use rusty_dumb_tools::prelude::*; pub fn run_demo() { let mut parser = create_demo_parser(); parser.parse_args(); handle_sub_demo(parser); } pub fn create_demo_parser() -> DumbArgParser { let mut parser = DumbArgParser::new(); parser.set_description("Demos of rusty_dumb_tools."); dap_arg!("demo", value = "calc") .set_description("a demo") .set_with_desc_enums(vec![ "calc:DumbCalcProcessor command-line input demo", ... ]) .set_rest() .add_to(&mut parser) .unwrap(); parser } pub fn handle_sub_demo(parser: DumbArgParser) { let demo = match parser.get::("demo") { Some(t) => t, None => { panic!("No demo specified."); } }; match demo.as_str() { "calc" => { let mut demo_parser = create_demo_calc_parser(); parser.process_rest_args("demo", &mut demo_parser); handle_demo_calc(demo_parser); } ... _ => panic!("Unknown sub-demo: {}", demo), }; } fn create_demo_calc_parser() -> DumbArgParser { let mut parser = DumbArgParser::new(); parser.set_description("DumbCalcProcessor command-line input demo."); dap_arg!("input", value = "123") .set_multi() .set_description("infix expression") .add_to(&mut parser) .unwrap(); parser } pub fn handle_demo_calc(parser: DumbArgParser) { let input = parser.get_multi::("input").unwrap(); ... }
示例程序
对于演示更多工具的示例程序,您可能想运行包含的示例函数 rusty_dumb_tools::demo::run_demo
,如下所示:
use rusty_dumb_tools::demo;
demo::run_demo(None); // get arguments from command-line
假设有一个新的 Rust 项目,其中包含 Cargo.toml
和 main.rs
,如下所示:
Cargo.toml
...
[dependencies]
rusty_dumb_tools = "0.13"
...
main.rs
use rusty_dumb_tools::demo;
fn main() {
demo::run_demo(None);
}
示例可以通过 cargo 运行,如下所示:
cargorun ---h
输入演示了使用DumbArgParser
来显示“帮助信息”cargorun --calc -h
DumbArgParser
被设置为解析子命令的参数(使用另一个DumbArgParser
对象);上述输入演示了显示子命令的“帮助信息”cargorun --calc 1.1 + 2.2* (4.3 - 2.4) + 5
上述示例演示了如何使用[子命令]DumbArgParser
来解析calc
子命令的参数,进而展示如何使用DumbCalcProcessor
来对子命令参数进行计算。cargorun --calc-repl
上述示例演示了如何调用calc-repl
子命令,进而展示DumbCalcProcessor
如何像REPL一样使用。cargorun --ltemp Trevor
上述示例演示了如何使用DumbLineTemplate
来格式化行以显示数据。cargorun --lblscreen
上述示例演示了如何使用DumbLineByLineScreen
来实现“进度信息面板”。cargorun --arg -f 0.2 5 --string2 VAL1 false 1 2 3
运行 cargo run -- -h
的输出
| USAGE: rusty_dumb_tools [-h] <demo>
| : Demos of rusty_dumb_tools.
| . -h, --help : HELP
| . <demo> ... : REQUIRED; e.g. calc ...
| : a demo
| : . [json] : DumbJsonProcessor demo
| : . [calc] : DumbCalcProcessor command-line input demo
| : . [calc-repl] : DumbCalcProcessor REPL demo
| : . [ltemp] : DumbLineTemplate demo
| : . [lblscreen] : DumbLineByLineScreen demo
| : . [arg] : DumbArgParser demo (more like debugging)
DumbJsonProcessor
的演示 -- json
运行 cargo run -- json 'hong kong'
后,将查询由 universities.hipolabs.com 提供的API的一些国家的大学信息,屏幕将显示类似的内容
*** query universities of country: [hong kong] ...
* `name` => `Hong Kong Chu Hai College`
* `name` => `City University of Hong Kong`
* `name` => `The Chinese University of Hong Kong`
* `name` => `The Hong Kong Academy for Performing Arts`
* `name` => `Hong Kong Baptist University`
* `name` => `Hong Kong Shue Yan University`
* `name` => `The University of Hong Kong`
* `name` => `Lingnan University`
* `name` => `Hong Kong Metropolitan University`
* `name` => `The Hong Kong Polytechnic University`
* `name` => `The Hong Kong University of Science and Technology`
* `name` => `The Education University of Hong Kong`
* `name` => `The Hang Seng University of Hong Kong`
* `name` => `Canadian International School of Hong Kong`
上述 DumbJsonProcessor 示例的核心代码如下
use rusty_dumb_tools::prelude::*; pub fn demo_query_universities(country: &str, show_all: bool) { let stream = make_connection(&country); let result = match stream { Ok(mut stream) => process_connection(&mut stream, show_all), Err(e) => Err(format!("XXX error: [{}]", e)), }; match result { Ok(_) => {} Err(e) => { println!("{}", e); } } } fn make_connection(country: &str) -> Result { let mut stream: TcpStream = TcpStream::connect("universities.hipolabs.com:80")?; let request = format!( "GET /search?country={} HTTP/1.1\r\nHost: universities.hipolabs.com\r\nAccept: application/json\r\nConnection: close\r\n\r\n", country.replace(" ", "%20") ); stream.write_all(request.as_bytes())?; Ok(stream) } fn make_connection_get_response(country: &String) -> Result { match make_connection(country) { Ok(mut stream) => { let mut response = String::new(); stream.read_to_string(&mut response)?; Ok(response) } Err(e) => Err(e), } } fn process_connection(stream: &mut TcpStream, show_all: bool) -> Result<(), String> { let mut handler = InPlaceJsonEntryHandler::new(move |json_entry| { let show = show_all || json_entry.field_name == "name"; if show { println!( "* `{}` => `{}`", json_entry.field_name, json_entry.field_value ); } }); let mut json_processor = DumbJsonProcessor::new(Box::new(&mut handler)); let mut progress = ProcessJsonProgress::new(); let mut buf = [0; 32]; loop { match stream.read(&mut buf) { Ok(size) => { if size == 0 { return Ok(()); } let bytes = &buf[..size]; json_processor.push_json_bytes(bytes, &mut progress); } Err(e) => { return Err(format!("XXX error: [{}]", e)); } } } }
DumbCalcProcessor
的演示 -- calc
运行 cargo run -- calc -h
的输出
| USAGE: rusty_dumb_tools calc [-h] <input>
| : DumbCalcProcessor command-line input demo.
| . -h, --help : HELP
| . <input> ... : REQUIRED; e.g. 123 ...
| : infix expression
运行 cargo run -- calc 1.1 + 2.2 * (4.3 - 2.4) + 5
的输出
|
| = 10.28.
|
DumbCalculator
的 calc-repl
演示
运行 cargo run -- calc-repl
后,演示将进入循环,从提示符获取输入
* enter an infix expression
* can split the infix expression into multiple lines; e.g. a "unit" a line
* finally, enter "=" (or an empty line) to evaluate it
* can then continue to enter another infix expression ...
>
DumbLineTemplate
的 ltemp
演示
运行 cargo run -- ltemp Trevor
后,演示将显示类似的内容
===============================
| NAME : Trevor |
| AGE : <undisclosed> |
| : and counting ... |
| + 1 | # |
===============================
+ 1 | #
起到“进度指示器”的作用;20秒后
===============================
| NAME : Trevor |
| AGE : <undisclosed> |
| : and counting ... |
| + 20 | #################### |
===============================
DumbLineByLineScreen
的 lblscreen
演示
运行 cargo run -- lblscreen
后,屏幕将显示类似的内容
----------------------------------------
| ... wait ... loading 0% ... |
| ........ | : 0% |
----------------------------------------
20秒后,当完成100%时,屏幕将像这样
| ... wait ... loading 100% ... |
| ........ |>>>>>>>>>>>>>>>>>>>>: 100% |
----------------------------------------
上述 DumbLineByLineScreen 演示的代码如下
use rusty_dumb_tools::prelude::*; pub fn demo_lblscreen() { let mut lbl_demo_screen = { let mut comps = dlt_comps![ "| ", dltc!("description", align = 'C').set_truncate_indicator("..."), " |" ]; let temp1 = DumbLineTemplate::new_fixed_width(40, &comps); let mut comps = dlt_comps![ "| ", ".".repeat(8), " |", dltc!("progress-bar"), ": ", dltc!("progress%", fixed_width = 4, align = 'R'), " |" ]; let temp2 = DumbLineTemplate::new_fixed_width(40, &comps); let settings = LBLScreenSettings { top_line: Some("-".repeat(40)), bottom_line: Some("-".repeat(40)), //screen_height_adjustment: 0, ..LBLScreenSettings::default() }; DumbLineByLineScreen::new(vec![temp1, temp2], settings) }; lbl_demo_screen.init(); let mut state = HashMap::<&str, String>::new(); let mut progress_done_percent = 0; loop { let progress_percent = format!("{}%", progress_done_percent); let description = format!("... wait ... loading {} ...", progress_percent); let progress_bar = ">".repeat(progress_done_percent / 5_usize); state.insert("description", description); state.insert("progress-bar", progress_bar); state.insert("progress%", progress_percent); lbl_demo_screen.refresh(&state); thread::sleep(Duration::from_millis(200)); progress_done_percent += 1; if progress_done_percent > 100 { break; } } }
其他演示应用程序
- DumbCalculator 文本演示
- DumbCalculator 基于Web的演示
- 你可以尝试它:
- 并且可能需要参考一些关于如何实现演示的简要介绍
谢谢!
作者Trevor Lee问候
愿和平与你同在!愿上帝保佑你!耶稣爱你!惊人的恩典!
许可证
MIT
变更历史
-
v0.1.15
- 错误修复
-
v0.1.14
- 添加了DumbProgressIndicator
- 错误修复
-
v0.1.13
- 错误修复
-
v0.1.12
- 将供应字节添加到DumbJsonProcessor
- 错误修复
-
v0.1.11
- 向DumbCalculator添加更多功能
- 错误修复
-
v0.1.10
- 错误修复
-
v0.1.9
- 添加了DumbJsonProcessor
- 错误修复
-
v0.1.89
- 错误修复
-
v0.1.8
- 错误修复 ... 对于DumbCalculator,8/2(1+3)现在为1(而非16)
-
v0.1.7
- 错误修复
- 增强了DumbCalcProcessor和DumbCalculator
-
v0.1.6
- 错误修复
-
v0.1.5
- 错误修复
- 移动了演示代码
- 添加了基于Web的计算器
-
v0.1.4
- 错误修复
-
v0.1.3
- 错误修复
- 添加了更丰富的基于文本的计算器演示
-
v0.1.2
- 错误修复
- 添加了
DumbLineTemplate
,DumbLineByLineScreen
和DumbLineByLineScreen
-
v0.1.1
- 错误修复
- 添加了更多文档,并通过
run_demo
函数
-
v0.1.0
- 初始发布