pub trait Main: Shared + Sized {
    fn subcommand(&self) -> &dyn Execute<Self>;

    fn execute(&self) -> Result<()> { ... }
}
Expand description

A trait for objects which manage the context for application subcommands.

This trait enforces a particular structure and flexibility to applications that implement it. Implementations of this trait are also required to implement io::Shared, making instances effectively all that is needed to execute a subcommand. When coupled with subcommands that use Execute, instances may also be used to share a global state.

use carli::command::{Execute, Main};
use carli::error::Result;
use carli::io::{Shared, Stream};
use std::cell::{RefCell, RefMut};
use std::io::{stderr, stdin, stdout, Write};

/// An example context with global data.
struct Application {
    /// The error output stream.
    error: RefCell<Stream>,

    /// The input stream.
    input: RefCell<Stream>,

    /// The name of the user.
    name: String,

    /// The global output stream.
    output: RefCell<Stream>,

    /// The user requested subcommand.
    subcommand: Subcommand,
}

impl Application {
    /// Returns the name of the user.
    fn name(&self) -> &str {
        &self.name
    }

    /// Creates a new instance of the application.
    fn new(name: String, subcommand: Subcommand) -> Self {
        Self {
            error: RefCell::new(stderr().into()),
            input: RefCell::new(stdin().into()),
            name,
            output: RefCell::new(stdout().into()),
            subcommand,
        }
    }
}

impl Main for Application {
    fn subcommand(&self) -> &dyn Execute<Self> {
        &self.subcommand
    }
}

impl Shared for Application {
    fn error(&self) -> RefMut<Stream> {
        self.error.borrow_mut()
    }

    fn input(&self) -> RefMut<Stream> {
        self.input.borrow_mut()
    }

    fn output(&self) -> RefMut<Stream> {
        self.output.borrow_mut()
    }
}

/// The example subcommands.
enum Subcommand {
    /// Say goodbye to the user.
    Goodbye,

    /// Say hello to the user.
    Hello,
}

impl Execute<Application> for Subcommand {
    fn execute(&self, context: &Application) -> Result<()> {
        match self {
            Self::Goodbye => writeln!(context.output(), "Goodbye, {}!", context.name())?,
            Self::Hello => writeln!(context.output(), "Hello, {}!", context.name())?,
        }

        Ok(())
    }
}

Required methods

Returns the subcommand to be executed.

Provided methods

Executes the requested subcommand for the application.

The implementation of this method should be very simple in that it should only execute the requested subcommand and return its result. Any additional steps required to put the context in a more usable state for the subcommand should probably be done elsewhere in order to keep testing simple.

Implementors