pub struct CliBuilder { /* private fields */ }Expand description
Fluent builder for creating CLI/REPL applications
Provides a chainable API for configuring and building applications. Automatically loads configuration, registers handlers, and creates the appropriate interface (CLI or REPL).
§Builder Pattern
The builder follows the standard Rust builder pattern:
- Methods consume
selfand returnSelf - Final
build()method consumes the builder and returns the app
§Example
use dynamic_cli::prelude::*;
let app = CliBuilder::new()
.config_file("commands.yaml")
.context(Box::new(MyContext::default()))
.register_sync_handler("my_handler", Box::new(MyHandler))
.prompt("myapp")
.build()?;Implementations§
Source§impl CliBuilder
impl CliBuilder
Sourcepub fn config_file<P: Into<PathBuf>>(self, path: P) -> Self
pub fn config_file<P: Into<PathBuf>>(self, path: P) -> Self
Sourcepub fn config(self, config: CommandsConfig) -> Self
pub fn config(self, config: CommandsConfig) -> Self
Provide a pre-loaded configuration
Use this instead of config_file() if you want to load and potentially
modify the configuration before building.
§Arguments
config- Loaded and validated configuration
§Example
use dynamic_cli::{CliBuilder, config::loader::load_config};
let mut config = load_config("commands.yaml")?;
// Modify config if needed...
let builder = CliBuilder::new()
.config(config);Sourcepub fn context(self, context: Box<dyn ExecutionContext>) -> Self
pub fn context(self, context: Box<dyn ExecutionContext>) -> Self
Set the execution context
The context will be passed to all command handlers and can store application state.
§Arguments
context- Boxed execution context implementingExecutionContext
§Example
use dynamic_cli::prelude::*;
#[derive(Default)]
struct MyContext {
count: u32,
}
impl ExecutionContext for MyContext {
fn as_any(&self) -> &dyn std::any::Any { self }
fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
}
let builder = CliBuilder::new()
.context(Box::new(MyContext::default()));Sourcepub fn register_sync_handler(
self,
name: impl Into<String>,
handler: Box<dyn CommandHandler>,
) -> Self
pub fn register_sync_handler( self, name: impl Into<String>, handler: Box<dyn CommandHandler>, ) -> Self
Register a (sync) command handler
Associates a handler with the command’s implementation name from the config.
The name must match the implementation field in the command definition.
Renamed from register_handler() in v0.5.0 for symmetry with
register_async_handler.
register_handler() remains available as a deprecated alias until
v1.0.0 (DD-022).
§Arguments
name- Implementation name from the configurationhandler- Boxed command handler implementingCommandHandler
§Example
use dynamic_cli::prelude::*;
use std::collections::HashMap;
struct MyCommand;
impl CommandHandler for MyCommand {
fn execute(
&self,
_ctx: &mut dyn ExecutionContext,
_args: &HashMap<String, String>,
) -> dynamic_cli::Result<()> {
println!("Executed!");
Ok(())
}
}
let builder = CliBuilder::new()
.register_sync_handler("my_command", Box::new(MyCommand));Sourcepub fn register_handler(
self,
name: impl Into<String>,
handler: Box<dyn CommandHandler>,
) -> Self
👎Deprecated since 0.5.0: renamed to register_sync_handler for symmetry with register_async_handler; will be removed in 1.0.0
pub fn register_handler( self, name: impl Into<String>, handler: Box<dyn CommandHandler>, ) -> Self
renamed to register_sync_handler for symmetry with register_async_handler; will be removed in 1.0.0
Deprecated alias for register_sync_handler.
Scheduled for removal in v1.0.0 alongside CommandRegistry::register.
Sourcepub fn register_async_handler(
self,
name: impl Into<String>,
handler: Box<dyn AsyncCommandHandler>,
) -> Self
pub fn register_async_handler( self, name: impl Into<String>, handler: Box<dyn AsyncCommandHandler>, ) -> Self
Register an async command handler (DD-022)
Additive counterpart of register_sync_handler.
Associates an async handler with the command’s implementation name
from the config, exactly like its sync counterpart. Registering both
a sync and an async handler for the same implementation name is
detected as an error at build() time, not here —
this method, like register_sync_handler, always succeeds (it just
stores the handler for build() to consume).
§Arguments
name- Implementation name from the configurationhandler- Boxed async command handler implementingAsyncCommandHandler
§Example
use dynamic_cli::prelude::*;
use dynamic_cli::executor::AsyncCommandHandler;
use std::collections::HashMap;
use async_trait::async_trait;
struct FetchCommand;
#[async_trait]
impl AsyncCommandHandler for FetchCommand {
async fn execute(
&self,
_ctx: &mut dyn ExecutionContext,
_args: &HashMap<String, String>,
) -> dynamic_cli::Result<()> {
println!("Fetched!");
Ok(())
}
}
let builder = CliBuilder::new()
.register_async_handler("fetch_command", Box::new(FetchCommand));Sourcepub fn register_plugin(self, plugin: Box<dyn Plugin>) -> Self
pub fn register_plugin(self, plugin: Box<dyn Plugin>) -> Self
Register a plugin
A plugin groups related handlers under a single unit. During
build(), each handler declared by the plugin is
merged into the handler map. Conflicts with already-registered
handler names (whether from another plugin or from
register_sync_handler) produce a
build-time error.
The YAML config remains the sole source of truth for command
definitions. Plugin handlers are matched by their implementation
name, exactly as with register_sync_handler.
Plugins remain sync-only for now — out of scope for DD-022.
§Example
use dynamic_cli::CliBuilder;
use dynamic_cli::plugin::SystemPlugin;
let builder = CliBuilder::new()
.register_plugin(Box::new(SystemPlugin::new()));Sourcepub fn register_wasm_plugin(
self,
path: &Path,
function_map: &[(&str, &str)],
) -> Result<Self>
pub fn register_wasm_plugin( self, path: &Path, function_map: &[(&str, &str)], ) -> Result<Self>
Load a WASM plugin from disk, map its business functions, and register it
Convenience wrapper around WasmPlugin::load,
WasmPlugin::with_function_map,
and register_plugin. Only available with
the wasm-plugins feature.
function_map is mandatory here, unlike the other WasmPlugin
builder methods (with_format, with_metadata), which have
reasonable defaults (YAML, file-name-derived metadata). A
WasmPlugin with an empty function map registers zero handlers —
silently inert — so this wrapper does not offer a path that skips
mapping. Applications that also need a non-default format or
explicit metadata should build the WasmPlugin directly and pass it
to register_plugin instead.
§Errors
Returns an error if the module cannot be loaded or fails mandatory
export validation. See WASM_PLUGIN_INTERFACE.md for the ABI
contract.
§Example
use dynamic_cli::CliBuilder;
use std::path::Path;
let builder = CliBuilder::new()
.register_wasm_plugin(
Path::new("plugins/greet.wasm"),
&[("greet_hello", "say_hello")],
)?;Sourcepub fn help_formatter(self, formatter: Box<dyn HelpFormatter>) -> Self
pub fn help_formatter(self, formatter: Box<dyn HelpFormatter>) -> Self
Set a custom help formatter.
By default, DefaultHelpFormatter is used lazily when --help is
detected. Call this method to supply your own implementation.
The formatter is stored and transferred to CliApp during build().
It is instantiated only when --help is detected in run_cli().
§Arguments
formatter- Boxed implementation ofHelpFormatter
§Example
use dynamic_cli::CliBuilder;
use dynamic_cli::help::{HelpFormatter, DefaultHelpFormatter};
use dynamic_cli::config::schema::CommandsConfig;
struct MyFormatter;
impl HelpFormatter for MyFormatter {
fn format_app(&self, config: &CommandsConfig) -> String {
format!("Help for {}", config.metadata.prompt)
}
fn format_command(&self, config: &CommandsConfig, command: &str) -> String {
format!("Help for command '{command}'")
}
}
let builder = CliBuilder::new()
.help_formatter(Box::new(MyFormatter));Sourcepub fn build(self) -> Result<CliApp>
pub fn build(self) -> Result<CliApp>
Build the application
Performs the following steps:
- Load configuration (if
config_file()was used) - Validate that a context was provided
- Create the command registry
- Register all command handlers
- Verify that all required commands have handlers
- Create the
CliApp
§Returns
A configured CliApp ready to run
§Errors
- Configuration errors (file not found, invalid format, etc.)
- Missing context
- Missing required handlers
- Registry errors
§Example
use dynamic_cli::prelude::*;
let app = CliBuilder::new()
.config_file("commands.yaml")
.context(Box::new(MyContext::default()))
.register_sync_handler("handler", Box::new(MyHandler))
.build()?;
// Now app is ready to runTrait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for CliBuilder
impl !Send for CliBuilder
impl !Sync for CliBuilder
impl !UnwindSafe for CliBuilder
impl Freeze for CliBuilder
impl Unpin for CliBuilder
impl UnsafeUnpin for CliBuilder
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more