[−][src]Crate ibuilder
Interactive builders for structs.
This crate provides a way to construct structs interactively, prompting the user multiple choices and text inputs.
The builder provides the user with interactive menu-like interfaces, keeping the UI abstract and rust type-safeness.
Rationale
When building an interactive application (e.g. a Telegram bot or a console application) it can be pretty cumbersome to come out with a decent interface without writing tons of code for the logic for handling the parsing and the validation of the input.
This crates provides a useful abstraction that allows an easy connection between the data and the user interface. Just by deriving the struct (or enum) that defines your data you can get a safe interface for building a UI.
The derive API is inspired by the great structopt
crate.
API Overview
The API of this crate is very simple:
- Derive a struct (or an enum) from
IBuilder
, including all the structs/enums that it depends upon; - Call the
builder()
method (from theBuildable
trait) to get an instance ofBuilder<T>
; - Call
get_options()
on the builder to get an object that contains a message to show the user, a list of possible choices (i.e. buttons to press) and eventually the possibility to enter some text (i.e. a text box); - Call
to_node()
on the builder to get a tree-like structure with the state of the builder, highlighting the fields that still need actions; - You choose how to show to the user the options and when the user made the decision call
choose(input)
on the builder. This will apply the choice to the state of the structure if it's valid, or return an error; - When the state is complete (all the required fields are present) a new option is present in
the list: Done. If the user selects it
choose
will return an instance ofT
.
A list of all the possible options for the ibuilder
attribute can be found here.
Supported Features
- Deriving any struct with named fields (or with one unnamed field like
struct Foo(i64)
) - Enums (also with variants with field, but only one if unnamed)
- Default values for the fields and default variant for enums
- Custom message prompt for fields, structs, enums and variants
- Renaming fields, structs and variants for better looking options
- Hidden fields (that takes the value only from the default)
- Nested structures (i.e. custom types)
- Supported field types: all numeric types from rust,
bool
,String
,char
,Box<T>
,Vec<T>
andOption<T>
- Any field type that implementes the
NewBuildableValue
trait
Example of Usage
In this example the data is stored inside a struct named Person
which has 3 fields, one of
which has a default value. Deriving from IBuilder
gives access to the builder()
method that
returns a Builder<Person>
.
Figure 1: main menu | Figure 2: AgeRange menu | Figure 3: main menu again |
use ibuilder::*; #[derive(IBuilder)] pub struct Person { #[ibuilder(rename = "full name")] full_name: String, age: AgeRange, #[ibuilder(default = 2, rename = "number of hands")] num_hands: u64, } #[derive(IBuilder, Debug, Eq, PartialEq)] #[ibuilder(prompt = "How old are you?")] pub enum AgeRange { #[ibuilder(rename = "Less than 13 years old")] Child, #[ibuilder(rename = "From 13 to 19 years old")] Teen, #[ibuilder(rename = "20 years or more")] Adult, #[ibuilder(rename = "I don't want to tell")] Unknown, } let mut builder = Person::builder(); // * figure 1 * let options = builder.get_options(); // main menu: select the field to edit builder.choose(Input::choice("age")).unwrap(); // select the field // * figure 2 * let options = builder.get_options(); // age menu builder.choose(Input::choice("Adult")).unwrap(); // insert the value let options = builder.get_options(); // back to the main menu builder.choose(Input::choice("full_name")).unwrap(); // select the field let options = builder.get_options(); // full_name menu assert!(options.text_input); // for inserting the string value builder.choose(Input::text("edomora97")).unwrap(); // insert the value // * figure 3 * assert!(builder.is_done()); let options = builder.get_options(); // main menu again, but the "Done" option is available // chose the "Done" option, the return value is Ok(Some(Person)) let value = builder.choose(Input::Choice(FINALIZE_ID.to_string())).unwrap().unwrap(); assert_eq!(value.full_name, "edomora97"); assert_eq!(value.age, AgeRange::Adult); assert_eq!(value.num_hands, 2);
Modules
builders | Module with the implementors of |
nodes | Allow generic display of the structures using a tree representation. |
Structs
BuildableValueConfig | The configuration for customizing the aspect of a |
Builder | Interactive builder for creating instances of the struct |
Choice | A single choice that the user can select. |
Options | The options that the user has for the next choice in the |
Enums
ChooseError | The |
FinalizeError | The finalization of the result failed. |
Input | An input of the user to the |
Constants
BACK_ID | The identifier of the "Back" choice. |
FINALIZE_ID | The identifier of the "Done" choice. |
Traits
Buildable | A type that supports being built using a |
BuildableValue | The interactive builder for a base type. |
NewBuildableValue | A type that can be built with a |
Derive Macros
IBuilder | Derive macro for |