1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use crate::error::*;
use crate::hero::*;
use crate::output::Output;
use clap::{App, Arg, ArgGroup, ArgMatches, SubCommand};

/// A command line action providing usage and call functionality.
///
/// The `usage()` method returns the [*clap*](https://crates.io/crates/clap) definition of a command line subcommand.
/// The call function is then to be called with the corresponding *ArgMatches* and the *Hero* to act on, returning a *Result* of an arbitrary list of *Outputs*.
pub trait Action
{
	/// Command line argument definition of the subcommand of the action.
	///
	/// This *App* determines determines the *ArgMatches* of the `call()` method.
	fn usage<'a,'b>(&'a self) -> App<'b,'b>;
	/// A method which maps self, as well as the current *Hero* and the result of the `usage()`-invocation into zero or more *Output*s.
	fn call(&mut self,hero: &Hero, matches: &ArgMatches) -> Result<Vec<Output>>;
}

/// The commands which can be plugged into the command line *App*.
///
/// Each command is an *Action* and provides a `new_action()` method to safe the user some casting.
/// The commands can therefore be used to generate an *App* which has all of these commands as subcommands.
/// The call to the subcommand can then further be processed by the very same command via its `call()` method.
/// This enables each command to modularly contain both its usage definition and the actual processing.
pub mod commands
{
	use super::*;

	mod cli;
	pub use cli::Cli;
	mod roll;
	pub use roll::Roll;
	mod tracker;
	pub use tracker::Tracker;

	/// Simply dumps the hero, ready to be displayed by the used *Formatter*.
	///
	/// Really nothing more to it than that.
	pub struct Dump;

	impl Dump
	{
		fn new_action() -> Box<dyn Action>
		{
			Box::new(Dump)
		}
	}

	impl Action for Dump
	{
		fn usage<'a,'b>(&'a self) -> App<'b,'b>
		{
			SubCommand::with_name("dump")
				.about("dump hero information")
		}

		fn call(&mut self,hero: &Hero,_: &ArgMatches) -> Result<Vec<Output>>
		{
			Ok(vec![Output::Dump(hero.clone())])
		}
	}
}