diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-06-06 23:16:51 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-06-06 23:16:51 +0800 |
| commit | 81635b93c597b10282cb14e0873f5e3d22395186 (patch) | |
| tree | 200fd2632653fefe751ab5bfa6ebc7a8d4161638 | |
| parent | a16d1e6f204cc83104ad3dcc4f4266e304214044 (diff) | |
Rename `ExitCode` to `ResExitCode` and `REPL` to `ResREPL`
| -rw-r--r-- | CHANGELOG.md | 13 | ||||
| -rw-r--r-- | docs/_zh_CN/_sidebar.md | 2 | ||||
| -rw-r--r-- | docs/_zh_CN/pages/other/naming_rule.md | 200 | ||||
| -rw-r--r-- | examples/example-exitcode/src/main.rs | 8 | ||||
| -rw-r--r-- | examples/example-repl-basic/src/main.rs | 5 | ||||
| -rw-r--r-- | mingling/src/example_docs.rs | 13 | ||||
| -rw-r--r-- | mingling/src/res.rs | 3 | ||||
| -rw-r--r-- | mingling/src/res/exit_code.rs | 6 | ||||
| -rw-r--r-- | mingling/src/setups/exit_code.rs | 6 | ||||
| -rw-r--r-- | mingling_core/src/lib.rs | 6 | ||||
| -rw-r--r-- | mingling_core/src/program.rs | 5 | ||||
| -rw-r--r-- | mingling_core/src/program/repl_exec.rs | 10 | ||||
| -rw-r--r-- | mingling_core/src/program/repl_exec/res.rs | 2 |
13 files changed, 252 insertions, 27 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c86be4..95db724 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,19 @@ program.with_setup(BasicProgramSetup); 1. **\[core\]** Changed the signature of `ProgramSetup::setup` from `fn setup(&mut self, program: &mut Program<C>) -> S` to `fn setup(self, program: &mut Program<C>)`, consuming `self` instead of taking a mutable reference. Correspondingly, `Program::with_setup` now accepts `S` by value (`&mut self, setup: S`) instead of by mutable reference (`&mut self, setup: &mut S`). +2. **\[core\]** Consolidated resource naming for `ExitCode` and `REPL`: + - Renamed `ExitCode` to `ResExitCode` and moved `ResREPL` from the `mingling` root to `mingling::res::ResREPL` (the `mingling::ResREPL` re-export is removed). + - This aligns with the naming convention where resources are prefixed with `Res`. + - The corresponding setup `ExitCodeSetup` and resource injection remain unchanged. + +```rust +// Before +use mingling::{res::ExitCode, REPL}; + +// After +use mingling::{res::ResExitCode, res::ResREPL}; +``` + ### Release 0.1.9 (2026-05-29) #### Fixes: diff --git a/docs/_zh_CN/_sidebar.md b/docs/_zh_CN/_sidebar.md index 8c854f9..5d0ebe1 100644 --- a/docs/_zh_CN/_sidebar.md +++ b/docs/_zh_CN/_sidebar.md @@ -1,3 +1,5 @@ - [Welcome!](README) * [介绍](pages/1-intro) * [初次上手!](pages/2-step1) +* other + * [命名规范](pages/other/naming_rule) diff --git a/docs/_zh_CN/pages/other/naming_rule.md b/docs/_zh_CN/pages/other/naming_rule.md new file mode 100644 index 0000000..59dc9cd --- /dev/null +++ b/docs/_zh_CN/pages/other/naming_rule.md @@ -0,0 +1,200 @@ +<h1 align="center">命名规范</h1> +<p align="center"> + 让你的 <b>Mingling</b> 项目类型和函数名井井有条 +</p> + +## 前言 + +好的命名是大型 CLI 项目的基石。Mingling 的管线模式引入了几类新的类型(Entry、State、Result、Error、Resource),如果不加约束,项目里很快就会出现 `Data`、`Info`、`Context` 这类无法区分职责的名字。 + +下面这套命名规范来自实践,已在生产项目中使用。它不是框架的强制规则,但建议跟随。 + +## 类型命名 + +### 资源 + +资源是通过资源注入系统共享给所有 chain 和 renderer 的全局实例。 + +``` +Res + 名称 +``` + +| 示例 | 说明 | +|------|------| +| `ResCurrentDir` | 当前工作目录 | +| `ResExitCode` | 进程退出码 | +| `ResREPL` | REPL 状态 | + +### 构建 + +构建是在程序启动时执行的初始化步骤,由 `with_setup` 注册。 + +``` +名称 + Setup +``` + +| 示例 | 说明 | +|------|------| +| `BasicSetup` | 基础初始化(`--quiet`、`--help`、`--confirm`) | +| `GeneralRendererSetup` | 通用渲染器初始化(`--json`、`--yaml` 等) | + +### 分发器 + +分发器是命令的入口点,与 `Node` 名称一一对应。节点名用 `.` 分隔层级,分发器名用 `CMD` 前缀加 PascalCase。 + +``` +CMD + 命令层级 +``` + +| 节点 | 分发器 | +|------|--------| +| `greet` | `CMDGreet` | +| `remote.add` | `CMDRemoteAdd` | +| `remote.rm` | `CMDRemoteRemove` | + +即使节点是缩写,分发器的名称也要写全名。例如节点是 `remote.rm`,分发器是 `CMDRemoteRemove`,不是 `CMDRemoteRm`。 + +### 入口 + +入口是分发器创建的管线起始类型,包裹 `Vec<String>`。 + +``` +Entry + 命令层级 +``` + +| 分发器 | 入口 | +|--------|------| +| `CMDGreet` | `EntryGreet` | +| `CMDRemoteAdd` | `EntryRemoteAdd` | +| `CMDRemoteRemove` | `EntryRemoteRemove` | + +### 状态 + +状态是介于入口和结果之间的管线中间类型,代表经过部分处理后的数据。 + +``` +State + 描述 +``` + +| 示例 | 说明 | +|------|------| +| `StateOperationRemotes` | 正在操作远程仓库列表 | +| `StateCheckRepository` | 正在检查仓库状态 | + +典型的管线链:`EntryRemoteAdd → StateOperationRemotes → StateCheckRepository` + +### 结果 + +结果是管线中由 `to_render()` 发往 Renderer 的最终类型。 + +``` +Result + 内容 +``` + +| 示例 | 说明 | +|------|------| +| `ResultGreetSomeone` | 问候结果 | +| `ResultFruitList` | 水果列表结果 | + +结果结构体期望被 Renderer 消费,内部结构应该为了渲染美观而设计。一般用 `#[derive(Groupped)]` 代替 `pack!()` 包装,以获得更灵活的字段控制。 + +### 错误 + +错误与结果不同。错误可以被 `to_chain()` 或 `to_render()` 发送,用于将执行路由到错误处理路径。 + +``` +Error + 描述 +``` + +| 示例 | 说明 | +|------|------| +| `ErrorRepositoryNotFound` | 仓库未找到 | + +`StateOperationRemotes → ErrorRepositoryNotFound` + + + +## 函数命名 + +### Chain 函数 + +| 处理类型 | 命名模式 | 示例 | +|----------|----------|------| +| Entry | `handle_` + entry 名(snake_case) | `handle_remote_add(prev: EntryRemoteAdd)` | +| State | `handle_state_` + state 名(snake_case) | `handle_state_operation_remotes(prev: StateOperationRemotes)` | +| Error | `handle_error_` + error 名(snake_case) | `handle_error_repository_not_found(prev: ErrorRepositoryNotFound)` | +| Result | ❌ 不要为 Result 写 chain | — | + +### Renderer 函数 + +| 处理类型 | 命名模式 | 示例 | +|----------|----------|------| +| Entry | `render_entry_` + entry 名 | `render_entry_remote_add(prev: EntryRemoteAdd)` | +| State | ❌ 不要为 State 写 renderer | — | +| Error | `render_error_` + error 名 | `render_error_repository_not_found(prev: ErrorRepositoryNotFound)` | +| Result | `render_` + result 名 | `render_greet_someone(prev: ResultGreetSomeone)` | + +**原则**:不要为不会被用户看到或不需要独立渲染的中间类型写 renderer。 + +--- + +## 函数签名参数命名 + +| 类型 | 推荐参数名 | +|------|------------| +| Entry | `args` | +| State | `prev`(或具名如 `remotes`) | +| Result | `result`(或具名如 `fruits`) | +| Error | `err` | +| 资源(不可变) | `cwd`、`db`、`config` 等 | +| 资源(可变) | `counter`、`cache`、`session` 等 | + +```rust +#[chain] +fn handle_remote_add(args: EntryRemoteAdd, cwd: &ResCurrentDir, db: &mut ResDatabase) -> Next { + // args: 入口数据 + // cwd: 注入的不可变资源 + // db: 注入的可变资源 +} +``` + +--- + +## 完整示例 + +```rust +// 分发器 +dispatcher!("remote.add", CMDRemoteAdd => EntryRemoteAdd); + +// 入口 → 状态 +#[chain] +fn handle_remote_add(args: EntryRemoteAdd) -> Next { + StateOperationRemotes::new(...).to_chain() +} + +// 状态 → 错误或结果 +#[chain] +fn handle_state_operation_remotes(state: StateOperationRemotes, db: &ResDatabase) -> Next { + if db.has_remote(&state.name) { + ErrorRepositoryNotFound::new(...).to_render() + } else { + ResultRemoteAdded::new(...).to_render() + } +} + +// 结果渲染 +#[renderer] +fn render_remote_added(result: ResultRemoteAdded) { + r_println!("Remote added: {}", result.name); +} + +// 错误渲染 +#[renderer] +fn render_error_repository_not_found(err: ErrorRepositoryNotFound) { + r_println!("Error: remote '{}' not found", err.name); +} +``` + +<p align="center" style="font-size: 0.85em; color: gray;"> + Written by @Weicao-CatilGrass +</p> diff --git a/examples/example-exitcode/src/main.rs b/examples/example-exitcode/src/main.rs index e1f60ee..0e7a019 100644 --- a/examples/example-exitcode/src/main.rs +++ b/examples/example-exitcode/src/main.rs @@ -14,7 +14,7 @@ //! No name provided (with exit code 1) //! ``` -use mingling::{prelude::*, res::ExitCode, setup::ExitCodeSetup}; +use mingling::{prelude::*, res::ResExitCode, setup::ExitCodeSetup}; fn main() { let mut program = ThisProgram::new(); @@ -50,11 +50,11 @@ fn render_result_name(name: ResultName) { r_println!("Hello, {}", *name); } -// Define renderer, render error message _____________ Inject exit code resource +// Define renderer, render error message _______________ Inject exit code resource // / /// Renders the error when no name is provided | -#[renderer] // vvvvvvvvvvvvv -fn render_error_no_name_provided(_: ErrorNoNameProvided, ec: &mut ExitCode) { +#[renderer] // vvvvvvvvvvvvvvvv +fn render_error_no_name_provided(_: ErrorNoNameProvided, ec: &mut ResExitCode) { ec.exit_code = 1; // Prompt when no name is provided diff --git a/examples/example-repl-basic/src/main.rs b/examples/example-repl-basic/src/main.rs index d44c92a..abea141 100644 --- a/examples/example-repl-basic/src/main.rs +++ b/examples/example-repl-basic/src/main.rs @@ -10,8 +10,9 @@ use mingling::{ hook::ProgramHook, prelude::*, + res::ResREPL, setup::{BasicREPLOutputSetup, BasicREPLPromptSetup, BasicREPLReadlineSetup}, - this, REPL, + this, }; use std::{env::current_dir, path::PathBuf}; @@ -145,7 +146,7 @@ fn render_list(list: ResultList) { #[chain] fn handle_exit( _prev: EntryExit, - repl: &mut REPL, // Import REPL resource, registered in `exec_repl`, usable directly + repl: &mut ResREPL, // Import REPL resource, registered in `exec_repl`, usable directly ) { // Set the REPL exit flag; REPL will exit after this loop iteration repl.exit = true; diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs index 903abf8..3755553 100644 --- a/mingling/src/example_docs.rs +++ b/mingling/src/example_docs.rs @@ -1088,7 +1088,7 @@ pub mod example_error_handling {} /// /// Source code (./src/main.rs) /// ```ignore -/// use mingling::{prelude::*, res::ExitCode, setup::ExitCodeSetup}; +/// use mingling::{prelude::*, res::ResExitCode, setup::ExitCodeSetup}; /// /// fn main() { /// let mut program = ThisProgram::new(); @@ -1124,11 +1124,11 @@ pub mod example_error_handling {} /// r_println!("Hello, {}", *name); /// } /// -/// // Define renderer, render error message _____________ Inject exit code resource +/// // Define renderer, render error message _______________ Inject exit code resource /// // / /// /// Renders the error when no name is provided | -/// #[renderer] // vvvvvvvvvvvvv -/// fn render_error_no_name_provided(_: ErrorNoNameProvided, ec: &mut ExitCode) { +/// #[renderer] // vvvvvvvvvvvvvvvv +/// fn render_error_no_name_provided(_: ErrorNoNameProvided, ec: &mut ResExitCode) { /// ec.exit_code = 1; /// /// // Prompt when no name is provided @@ -1521,8 +1521,9 @@ pub mod example_panic_unwind {} /// use mingling::{ /// hook::ProgramHook, /// prelude::*, +/// res::ResREPL, /// setup::{BasicREPLOutputSetup, BasicREPLPromptSetup, BasicREPLReadlineSetup}, -/// this, REPL, +/// this, /// }; /// use std::{env::current_dir, path::PathBuf}; /// @@ -1656,7 +1657,7 @@ pub mod example_panic_unwind {} /// #[chain] /// fn handle_exit( /// _prev: EntryExit, -/// repl: &mut REPL, // Import REPL resource, registered in `exec_repl`, usable directly +/// repl: &mut ResREPL, // Import REPL resource, registered in `exec_repl`, usable directly /// ) { /// // Set the REPL exit flag; REPL will exit after this loop iteration /// repl.exit = true; diff --git a/mingling/src/res.rs b/mingling/src/res.rs index d625f8f..982fe91 100644 --- a/mingling/src/res.rs +++ b/mingling/src/res.rs @@ -1,2 +1,5 @@ mod exit_code; pub use exit_code::*; + +#[allow(unused_imports)] +pub use mingling_core::core_res::*; diff --git a/mingling/src/res/exit_code.rs b/mingling/src/res/exit_code.rs index e90d067..93ce98b 100644 --- a/mingling/src/res/exit_code.rs +++ b/mingling/src/res/exit_code.rs @@ -9,7 +9,7 @@ use mingling_core::{ProgramCollect, this}; /// The exit code is stored globally per `ProgramCollect` type and can be /// retrieved via [`exit_code()`] or updated via [`update_exit_code()`]. #[derive(Debug, Default, Clone, Copy)] -pub struct ExitCode { +pub struct ResExitCode { /// The numeric exit code value. pub exit_code: i32, } @@ -19,7 +19,7 @@ pub fn update_exit_code<C>(exit_code: i32) where C: ProgramCollect<Enum = C> + 'static, { - this::<C>().modify_res(|e: &mut ExitCode| e.exit_code = exit_code); + this::<C>().modify_res(|e: &mut ResExitCode| e.exit_code = exit_code); } /// Retrieves the globally stored exit code for the given `ProgramCollect` type. @@ -29,7 +29,7 @@ pub fn exit_code<C>() -> i32 where C: ProgramCollect<Enum = C> + 'static, { - match this::<C>().res::<ExitCode>() { + match this::<C>().res::<ResExitCode>() { Some(e) => e.exit_code, None => 0, } diff --git a/mingling/src/setups/exit_code.rs b/mingling/src/setups/exit_code.rs index 88742d5..ed8204c 100644 --- a/mingling/src/setups/exit_code.rs +++ b/mingling/src/setups/exit_code.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use mingling_core::{ProgramCollect, hook::ProgramHook, setup::ProgramSetup, this}; -use crate::res::ExitCode; +use crate::res::ResExitCode; /// Provides the ability to control the program's exit code, which is returned when the program ends. /// @@ -29,11 +29,11 @@ where { fn setup(self, program: &mut crate::Program<C>) { // Insert resource - program.with_resource(ExitCode { exit_code: 0 }); + program.with_resource(ResExitCode { exit_code: 0 }); // Insert hook to override exit code before program ends program.with_hook(ProgramHook::empty().on_finish(|| { - let this = this::<C>().res_or_default::<ExitCode>(); + let this = this::<C>().res_or_default::<ResExitCode>(); this.exit_code })); } diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs index 373df52..6e1e90c 100644 --- a/mingling_core/src/lib.rs +++ b/mingling_core/src/lib.rs @@ -70,3 +70,9 @@ pub use crate::comp::*; pub mod setup { pub use crate::program::setup::ProgramSetup; } + +#[doc(hidden)] +pub mod core_res { + #[cfg(feature = "repl")] + pub use crate::program::repl_exec::res::ResREPL; +} diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs index 2e861e4..096f292 100644 --- a/mingling_core/src/program.rs +++ b/mingling_core/src/program.rs @@ -25,9 +25,8 @@ pub use collection::*; mod once_exec; #[cfg(feature = "repl")] -mod repl_exec; -#[cfg(feature = "repl")] -pub use repl_exec::res::REPL; +#[doc(hidden)] +pub mod repl_exec; mod single_instance; pub use single_instance::*; diff --git a/mingling_core/src/program/repl_exec.rs b/mingling_core/src/program/repl_exec.rs index 033c5a3..d6b3f00 100644 --- a/mingling_core/src/program/repl_exec.rs +++ b/mingling_core/src/program/repl_exec.rs @@ -11,7 +11,7 @@ mod splitter; use crate::error::{ProgramInternalExecuteError, ProgramPanic}; use crate::program::repl_exec::splitter::split_input_string; use crate::{Program, ProgramCollect, RenderResult}; -use crate::{program::repl_exec::res::REPL, this}; +use crate::{program::repl_exec::res::ResREPL, this}; #[cfg(not(feature = "async"))] impl<C> Program<C> @@ -24,7 +24,7 @@ where /// and displays the execution result or error message. It is suitable for scenarios requiring command-line interaction with the user. pub fn exec_repl(mut self) { // Inject default REPL resource - self.with_resource(REPL::default()); + self.with_resource(ResREPL::default()); self.run_hook_repl_on_begin(); @@ -48,7 +48,7 @@ where } p.run_hook_repl_post_exec(); - if this::<C>().res::<REPL>().unwrap().exit { + if this::<C>().res::<ResREPL>().unwrap().exit { p.run_hook_repl_exit(); break; } @@ -73,7 +73,7 @@ where /// Any panics during command execution will result in an abort rather than being caught and handled gracefully. pub async fn exec_repl(mut self) { // Inject default REPL resource - self.with_resource(REPL::default()); + self.with_resource(ResREPL::default()); self.run_hook_repl_on_begin(); @@ -94,7 +94,7 @@ where } p.run_hook_repl_post_exec(); - if this::<C>().res::<REPL>().unwrap().exit { + if this::<C>().res::<ResREPL>().unwrap().exit { p.run_hook_repl_exit(); break; } diff --git a/mingling_core/src/program/repl_exec/res.rs b/mingling_core/src/program/repl_exec/res.rs index 1295652..53e82d8 100644 --- a/mingling_core/src/program/repl_exec/res.rs +++ b/mingling_core/src/program/repl_exec/res.rs @@ -1,6 +1,6 @@ /// Internal resource for the REPL runtime, used to control the REPL's state during execution #[derive(Default, Clone)] -pub struct REPL { +pub struct ResREPL { /// Marks whether the REPL should exit after the current loop ends pub exit: bool, } |
