[][src]Crate ibuilder

Rust crates.io Docs

Interactive builders for structs.

This crate provides a way to construct structs interactively, starting from an "empty" state and filling the values of the fields of the struct prompting the user with multiple choices and text inputs. After each choice the internal state of the builder changes.

The builder provides the user with interactive menu-like interfaces, keeping the UI abstract and rust type-safeness.

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 the Buildable trait) to get an instance of Builder<T>;
  • By calling get_options() on the builder you'll 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);
  • By calling to_node() on the builder you'll 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 you 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 of T.

Rationale

When building an interactive application (e.g. a Telegram bot or a console application) which needs many configurations it can be pretty cumbersome to come out with a decent interface without spending loads of time writing 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 over a possible UI.

The derive API is inspired by the great structopt crate.

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> and Option<T>
  • Any field type that implementes the NewBuildableValue trait

A list of all the possible options for the ibuilder attribute can be found here.

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 1Figure 2Figure 3
Figure 1: main menuFigure 2: AgeRange menuFigure 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 BuildableValue for the various standard types.

nodes

Allow generic display of the structures using a tree representation.

Structs

BuildableValueConfig

The configuration for customizing the aspect of a BuildableValue that produces a value of type T.

Builder

Interactive builder for creating instances of the struct T by communicating. To instantiate a new Builder for the type T, make T derive from IBuilder and call builder() on it from the Buildable trait.

Choice

A single choice that the user can select.

Options

The options that the user has for the next choice in the Builder.

Enums

ChooseError

The Input provided to Builder::choose was is invalid.

FinalizeError

The finalization of the result failed.

Input

An input of the user to the Builder.

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 Builder. Deriving IBuilder an auto-generated implementation for this trait is provided.

BuildableValue

The interactive builder for a base type.

NewBuildableValue

A type that can be built with a BuildableValue inside a Builder. Keep in mind that the semantics of the generated builder must be compatible with this type, especially looking at the get_value_any method.

Derive Macros

IBuilder

Derive macro for IBuilder.