Procedural macros for generating cmdkit command strategies from plain Rust functions.
This crate provides one attribute macro:
#[strategy]
It transforms a free function into a concrete type that implements cmdkit::CommandStrategy.
Given a function like create_directory, the macro generates:
- A strategy type named
CreateDirectory - A constructor
CreateDirectory::new() - A helper factory function
create_directory_strategy() - An
impl cmdkit::CommandStrategywithexecute(...)
Add to your Cargo.toml:
[dependencies]
cmdkit = "0.3"
cmdkit-macros = "0.3"use cmdkit::{CMDKit, Command, InvocationArgs, StrategyError};
use cmdkit_macros::strategy;
#[strategy]
fn create_directory(
_ctx: cmdkit::ExecutionContext,
invocation_args: cmdkit::InvocationArgs,
) -> Result<(), cmdkit::StrategyError> {
let path = invocation_args.args
.iter()
.find(|argument| argument.name == "path")
.and_then(|argument| argument.value.as_deref())
.ok_or_else(|| StrategyError::invalid_arguments("missing path"))?;
std::fs::create_dir(std::path::Path::new(path))
.map_err(|e| StrategyError::execution(format!("Failed to create directory: {e}")))
}
fn main() {
let core = CMDKit::builder()
.register(Command::new(
"create",
"Create a directory",
CreateDirectory::new(),
))
.build();
// You can also use create_directory_strategy()
// generated by the macro.
let _ = core;
}A function annotated with #[strategy] must:
- Be a free function (not a method).
- Not be
async. - Accept exactly these two parameters in this order:
ctx: cmdkit::ExecutionContext(or&cmdkit::ExecutionContext)args: cmdkit::InvocationArgs
- Return
Result<(), cmdkit::StrategyError>.
Example accepted shape:
#[strategy]
fn my_command(
_ctx: cmdkit::ExecutionContext,
_args: cmdkit::InvocationArgs,
) -> Result<(), cmdkit::StrategyError> {
Ok(())
}The generated type name is UpperCamelCase from the function name.
simple_cli_strategy->SimpleCliStrategycreate_directory->CreateDirectory
For:
#[strategy]
fn sample_name(
ctx: cmdkit::ExecutionContext,
args: cmdkit::InvocationArgs,
) -> Result<(), cmdkit::StrategyError> {
Ok(())
}The macro generates equivalents of:
pub struct SampleName;
impl SampleName {
pub fn new() -> Self {
Self
}
}
impl cmdkit::CommandStrategy for SampleName {
fn execute(
&self,
ctx: &cmdkit::ExecutionContext,
args: cmdkit::InvocationArgs,
) -> Result<(), cmdkit::StrategyError> {
Ok(())
}
}
pub fn sample_name_strategy() -> SampleName {
SampleName::new()
}Run tests:
cargo testThis project is licensed under Apache-2.0. See LICENSE for details.