cli_boilerplate_automation 0.0.11

Cli Boilerplate Automation: Opiniated Cli Utilities for Basic Tasks
Documentation

CBA Crates.io License

Cli Boilerplate Automation. A small library of assorted utilities for cli tool development.

Modules

Bogger

A stateful logger for displaying messages styled according to their level. The standard initialization method writes a message like the following to stdout/stderr:

[ERROR: tag] my_content.

where the tag is colored.

The logger can be configured at runtime to filter, downcast, pause and forward the messages it recieves.

Additionally, format!-like macros are provided: ebog!("optional_tag"; "{my_content}").

Extension traits for unwrapping

The extension traits and logging macros follow a general naming pattern of {level}{bog/log}. For example, result.elog() calls log::error! on the error. Each such function also has a variant whose name is prefixed with _ which consumes the error, downgrading Results to Options, and Option<T> to T (or else exiting the program with code 1). Additionally, prefix() and context() can be used to add context to the error.

A standard pattern to handle non-fatal errors under this paradigm is like so:

let x = try()
	.prefix("Failed to copy") // {e} -> Failed to copy: {e}
	._wbog() // pretty print the warning and consume the error

There is also a flexible unwrap! macro, which can be slightly more convenient than let/else. It unwraps Result and Option, or otherwise calls return/continue for a never type.

// Unwrap Option or return Default::default()
pub fn check_should_template(path: &Path) -> bool {
	let err_prefix = format!("Failed to read {path:?} for templating");
	let file = unwrap!(fs::File::open(path).prefix(&err_prefix)._ebog());

	// process file

	true
}

// A closure in the second argument unwraps Result:
for binname in list {
	let Action {
		name,
		alias,
		..
	} = unwrap!(
    	binname.parse();
    	|e| { err_count += 1; ebog!("Scan"; "Failed to parse filename of {}: {e}", path.to_string_lossy()) };
    	continue
	);

	println!("{name}");
}

// (This macro also supports a few other sensible input patterns).

Bath/Bo/Broc/Bs

Simple wrappers around standard library modules (path, io, process, fs) for more ergonomic usage. A few of these operations take the liberty of logging (or bogging) errors instead of propogating them, downgrading them to Option or bool.

Macros

  • for defining wrapper types:
// Define a newtype wrapper which can only be be created or modified by methods you implement.
define_restricted_wrapper!(Prefix: u8 = 0);

// Define a newtype wrapper with a custom default.
define_transparent_wrapper!(
	#[derive(Copy)]
	Count: u16 = 1
);

// Define a collection wrapper with a new function and many standard traits such as IntoIterator/Deref/etc. implemented.
define_collection_wrapper!(
    #[derive(Debug, serde::Serialize, serde::Deserialize)]
    #[serde(transparent)]
    Modules: HashMap<String, Module>
);
  • vec_!: map functions over the elements of a vec![] call.
  • prints!: write elements to stdout or a buffer directly, without dynamic dispatch.
  • ... and a few others

Others

  • Some extension traits
    • Float, Option, Result, Bool
    • Mutex: _lock (ignore poisoning)
    • Transform: Blanket impl of some post-fix methods. These are sometimes nice to use particularly with the builder pattern.
  • initialization helpers

For example:

// transform elements
err_count += curr
	.update_from_config_path(dir, lib, &name, targets)?
	.transform(|s| if s == usize::MAX { 0 } else { s });

Optional features

  • text: text utilities (string padding, table formatting, etc.)
  • serde: serde derivations on some types, and some serde utils