aboutsummaryrefslogtreecommitdiff
path: root/docs/pages/6-argument-parse-picker.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/pages/6-argument-parse-picker.md')
-rw-r--r--docs/pages/6-argument-parse-picker.md116
1 files changed, 51 insertions, 65 deletions
diff --git a/docs/pages/6-argument-parse-picker.md b/docs/pages/6-argument-parse-picker.md
index 398cd3c..01f1c37 100644
--- a/docs/pages/6-argument-parse-picker.md
+++ b/docs/pages/6-argument-parse-picker.md
@@ -3,7 +3,7 @@
Use Picker to perform basic argument parsing
</p>
-In previous tutorials, we extracted args manually from `EntryGreet.inner` (`Vec<String>`).
+In previous tutorials, we manually extracted parameters from `EntryGreet.inner` (`Vec<String>`).
```rust
@@@ fn main() {
@@ -12,7 +12,7 @@ let name = args.first().cloned().unwrap_or_else(|| "World".to_string());
@@@ }
```
-But this approach doesn't scale well for many params. Mingling provides `Picker` — a chaining API to extract and convert args.
+But this approach doesn't scale well when there are many params. Mingling provides `Picker` — a chained API for extracting and transforming params.
To enable `Picker`, update your `Cargo.toml`:
@@ -22,7 +22,7 @@ To enable `Picker`, update your `Cargo.toml`:
features = ["parser"]
```
-Now let's look at `Picker` in action:
+Now let's see how `Picker` is written:
```rust
// Features: ["parser"]
@@ -36,9 +36,9 @@ fn handle_greet_entry(prev: EntryGreet) -> Next {
}
```
-`AsPicker` implements `pick`, `pick_or`, and `pick_or_route` for any type that can convert to `Vec<String>`: they semantically **pick** args from a string list and convert them to structured data.
+`AsPicker` implements `pick`, `pick_or`, and `pick_or_route` for all types convertible to `Vec<String>`. These functions semantically **pick** params from the string list and convert them into structured data.
-Breaking down the example above:
+For the code above:
```rust
// Features: ["parser"]
@@ -62,17 +62,17 @@ Its semantics are:
@@@let name: String =
prev.pick_or((), "World").unpack();
// ~~~~ ~~~~~~~ ~~ ~~~~~~~ ~~~~~~~~
-// | | | | |_ unpack to String
+// | | | | |_ unpack as String
// | | | |__________ default value "World"
// | | |______________ pick the first positional arg (no flag)
// | |______________________ pick or use default
-// |___________________________ from previous input
+// |___________________________ from the previous input
@@@}
```
-## Parsing Flag Args
+## Parsing Flag Arguments
-If your program needs to parse flag args (e.g., `greet --name Alice`), do this:
+If your program needs to parse flag arguments (e.g. `greet --name Alice`), do this:
```rust
// Features: ["parser"]
@@ -97,19 +97,19 @@ Its semantics:
@@@let name: String =
prev.pick_or(["--name", "-n"], "World").unpack();
// ~~~~ ~~~~~~~ ~~~~~~~~~~~~~~~~ ~~~~~~~ ~~~~~~~~
-// | | | | |_ unpack to String
+// | | | | |_ unpack as String
// | | | |__________ default value "World"
-// | | |____________________________ pick arg after "--name" or "-n"
+// | | |____________________________ pick the value after "--name" or "-n"
// | |____________________________________ pick or use default
-// |_________________________________________ from previous input
+// |_________________________________________ from the previous input
@@@}
```
## About `.unpack()`
-You may have noticed that `Picker` calls `.unpack()` at the end of parsing. It converts the accumulated parse results into structured info.
+You may have noticed that `Picker` calls `.unpack()` at the end of parsing. It converts the collected results into structured info.
-For a single pick, `.unpack()` returns a single value; for multiple picks, it returns a tuple:
+For a single pick, `.unpack()` returns the value directly; for multiple picks, it returns a tuple:
```rust
// Features: ["parser"]
@@ -129,16 +129,17 @@ fn handle_test_entry(prev: EntryTest) -> Next {
```
> [!IMPORTANT]
-> `Picker` is very sensitive to parse order, esp. for positional args (they're parsed sequentially). If you need to parse positional args, make sure all **flag args** have been picked and consumed first.
+> `Picker` is sensitive to parse order, especially for positional args — it parses sequentially. If you need to parse positional args, make sure all **flag arguments** are picked and consumed first.
## Handling Edge Cases with `pick_or_route`
-As the old saying goes: "Never trust your users." To handle missing required args, type mismatches, etc., `pick_or_route` routes the execution chain to a dedicated error-handling type.
+As the saying goes: "never trust your users." To handle missing required params, type mismatches, etc., `pick_or_route` routes the chain to a dedicated error handler.
-A simple example:
+Here's a simple example:
```rust
// Features: ["parser", "extra_macros"]
+@@@use mingling::macros::buffer;
@@@use mingling::macros::route;
@@@dispatcher!("greet", CMDGreet => EntryGreet);
@@@pack!(ResultName = String);
@@ -150,29 +151,20 @@ fn handle_greet_entry(prev: EntryGreet) -> Next {
.pick_or_route(["--name", "-n"], ErrorNoName::default())
.unpack();
- // Use route! macro to unpack pick_result
+ // Use route! macro to expand pick_result
let name = route!(pick_result);
ResultName::new(name).into()
}
-#[renderer]
-fn render_no_name(_prev: ErrorNoName) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Error: No name provided.").ok();
- r
-}
-
-#[renderer]
-fn render_name(prev: ResultName) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *prev).ok();
- r
+#[renderer(buffer)]
+fn render_greet(result: ResultName) {
+ r_println!("Hello, {}!", *result);
}
```
-With `pick_or_route`, the code gets a bit more complex: `.unpack()` no longer returns the value directly, but `Result<Value, Route>`.
+With `pick_or_route`, the code becomes more involved: `.unpack()` no longer returns the value directly, but `Result<Value, Route>`.
-However, Mingling's `extra_macros` feature provides the `route!` macro to simplify unwrapping — it just omits some boilerplate:
+However, **Mingling**'s `extra_macros` feature provides the `route!` macro for simplified expansion. It's not complex — it just reduces boilerplate:
```rust
// Features: ["parser", "extra_macros"]
@@ -204,7 +196,7 @@ let name = match pick_result {
## Post-processing Extracted Values
-After picking user input, you can use `after` to process the value immediately:
+After picking user input with `pick`, you can use `after` to process it immediately:
```rust
// Features: ["parser"]
@@ -215,7 +207,7 @@ After picking user input, you can use `after` to process the value immediately:
fn handle_greet_entry(prev: EntryGreet) -> Next {
let name = prev
.pick_or(["--name", "-n"], "World")
- // Format immediately after extracting --name
+ // Format immediately after picking --name
.after(|name: String| {
name.replace(['-', '_', '.'], " ")
.to_lowercase()
@@ -228,10 +220,11 @@ fn handle_greet_entry(prev: EntryGreet) -> Next {
}
```
-Similarly, use `after_or_route` to handle format errors in input args:
+Similarly, you can use `after_or_route` to handle input format errors:
```rust
// Features: ["parser", "extra_macros"]
+@@@use mingling::macros::buffer;
@@@use mingling::macros::route;
@@@dispatcher!("greet", CMDGreet => EntryGreet);
@@@pack!(ResultName = String);
@@ -254,35 +247,31 @@ fn handle_greet_entry(prev: EntryGreet) -> Next {
ResultName::new(name).into()
}
-#[renderer]
-fn render_name_too_long(prev: ErrorNameTooLong) -> RenderResult {
- let mut r = RenderResult::new();
+#[renderer(buffer)]
+fn render_name_too_long(prev: ErrorNameTooLong) {
let len = *prev;
- writeln!(r, "Error: name too long (length: {} > 32)", len).ok();
- r
+ r_println!("Error: name too long (length: {} > 32)", len);
}
-#[renderer]
-fn render_name(prev: ResultName) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Hello, {}!", *prev).ok();
- r
+#[renderer(buffer)]
+fn render_name(prev: ResultName) {
+ r_println!("Hello, {}!", *prev);
}
```
## Boolean Parsing
-`Picker` can parse bools too, with two modes: implicit and explicit.
+`Picker` can also parse booleans, in two modes:
| Mode | Format |
| -------- | ----------------------------------- |
| Implicit | `--confirmed` |
| Explicit | `--confirm true` or `--confirm yes` |
-- Using `.pick::<bool>(flag)` → implicit: flag present means `true`
-- Using `.pick::<Yes>(flag)` or `.pick::<True>(flag)` → explicit
+- `.pick::<bool>(flag)` uses implicit mode: the flag being present means `true`
+- `.pick::<Yes>(flag)` or `.pick::<True>(flag)` uses explicit mode
-Implicit is fine for most cases, but for important confirmations, explicit logic is more semantic.
+Implicit mode is generally sufficient, but for important confirmations, explicit logic is more idiomatic.
```rust
// Features: ["parser"]
@@ -302,7 +291,7 @@ fn handle_entry(prev: EntryTest) -> Next {
## Special Usage: `usize` Parsing
-Mingling provides a special `usize` feature: parsing strings like `25G`, `32mib`, etc.
+**Mingling** provides a special `usize` feature: parsing strings like `25G`, `32mib`, etc.
```rust
// Features: ["parser"]
@@ -315,12 +304,13 @@ fn parse_size() {
}
```
-## Custom Parseable Types
+## Custom Pickable Types
-Implement the `Pickable` trait to make your type parseable by `Picker` — this is where Picker's extensibility comes from.
+You can make your types pickable by `Picker` using the `Pickable` trait — this is where `Picker`'s extensibility comes from.
```rust
// Features: ["parser"]
+@@@use mingling::macros::buffer;
@@@use mingling::parser::{Pickable, Argument};
@@@use mingling::Flag;
#[derive(Default, Clone)]
@@ -348,12 +338,9 @@ fn handle_connect_entry(prev: EntryConnect) -> Next {
ResultConnected::new(address).into()
}
-#[renderer]
-fn render_connected(prev: ResultConnected) -> RenderResult {
- let mut r = RenderResult::new();
- let addr = prev.inner;
- writeln!(r, "Connected: IP: {} PORT: {}", addr.ip, addr.port).ok();
- r
+#[renderer(buffer)]
+fn render_connected(addr: ResultConnected) {
+ r_println!("Connected: IP: {} PORT: {}", addr.ip, addr.port);
}
```
@@ -366,10 +353,11 @@ Connected: IP: 127.0.0.1 PORT: 8080
## Auto-implementing Pickable for Enums
-To implement `Pickable` for an enum, just make it implement `EnumTag`, then implement `PickableEnum`:
+To make an enum `Pickable`, just implement `EnumTag` on it, then implement `PickableEnum`:
```rust
// Features: ["parser"]
+@@@use mingling::macros::buffer;
@@@use mingling::parser::PickableEnum;
@@@use mingling::EnumTag;
#[derive(Debug, Default, EnumTag)]
@@ -390,15 +378,13 @@ fn handle_eat_entry(prev: EntryEat) -> Next {
ResultFruit::new(fruit).into()
}
-#[renderer]
-fn render_fruit(prev: ResultFruit) -> RenderResult {
- let mut r = RenderResult::new();
- writeln!(r, "Picked fruit: {:?}", *prev).ok();
- r
+#[renderer(buffer)]
+fn render_fruit(prev: ResultFruit) {
+ r_println!("Picked fruit: {:?}", *prev);
}
```
-That covers all the features of `Picker`.
+That covers all the usages of `Picker`.
<p align="center" style="font-size: 0.85em; color: gray;">
Written by @Weicao-CatilGrass