Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation and tests for framework #101

Merged
14 commits merged into from May 31, 2017
101 changes: 97 additions & 4 deletions src/framework/configuration.rs
Expand Up @@ -93,6 +93,19 @@ impl Configuration {
}

/// HashSet of guild Ids where commands will be ignored.
///
/// # Examples
///
/// Create a HashSet in-place:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// use serenity::model::GuildId;
///
/// client.with_framework(|f| f.configure(|c| c
/// .blocked_guilds(vec![GuildId(7), GuildId(77)].into_iter().collect())));
/// ```
pub fn blocked_guilds(mut self, guilds: HashSet<GuildId>) -> Self {
self.blocked_guilds = guilds;

Expand All @@ -101,6 +114,19 @@ impl Configuration {

/// HashSet of user Ids whose commands will be ignored.
/// Guilds owned by user Ids will also be ignored.
///
/// # Examples
///
/// Create a HashSet in-place:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// use serenity::model::UserId;
///
/// client.with_framework(|f| f.configure(|c| c
/// .blocked_users(vec![UserId(7), UserId(77)].into_iter().collect())));
/// ```
pub fn blocked_users(mut self, users: HashSet<UserId>) -> Self {
self.blocked_users = users;

Expand All @@ -122,6 +148,21 @@ impl Configuration {
}

/// HashSet of command names that won't be run.
///
/// # Examples
///
/// Ignore a set of commands, assuming they exist:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
///
/// let disabled = vec!["ping"].into_iter().map(|x| x.to_owned()).collect();
///
/// client.with_framework(|f| f
/// .command("ping", |c| c.exec_str("pong!"))
/// .configure(|c| c.disabled_commands(disabled)));
/// ```
pub fn disabled_commands(mut self, commands: HashSet<String>) -> Self {
self.disabled_commands = commands;

Expand Down Expand Up @@ -213,22 +254,74 @@ impl Configuration {
}

/// A `HashSet` of user Ids checks won't apply to.
///
/// # Examples
///
/// Create a HashSet in-place:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// use serenity::model::UserId;
///
/// client.with_framework(|f| f.configure(|c| c
/// .owners(vec![UserId(7), UserId(77)].into_iter().collect())));
/// ```
///
/// Create a HashSet beforehand:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// use serenity::model::UserId;
/// use std::collections::HashSet;
///
/// let mut set = HashSet::new();
/// set.insert(UserId(7));
/// set.insert(UserId(77));
///
/// client.with_framework(|f| f.configure(|c| c.owners(set)));
/// ```
pub fn owners(mut self, user_ids: HashSet<UserId>) -> Self {
self.owners = user_ids;

self
}

/// Sets the prefix to respond to. This can either be a single-char or
/// multi-char string.
/// Sets the prefix to respond to. A prefix can be a string slice of any
/// non-zero length.
///
/// # Examples
///
/// Assign a basic prefix:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// #
/// client.with_framework(|f| f.configure(|c| c
/// .prefix("!")));
/// ```
pub fn prefix(mut self, prefix: &str) -> Self {
self.prefixes = vec![prefix.to_owned()];

self
}

/// Sets the prefixes to respond to. Those can either be single-chararacter or
/// multi-chararacter strings.
/// Sets the prefixes to respond to. Each can be a string slice of any
/// non-zero length.
///
/// # Examples
///
/// Assign a set of prefixes the bot can respond to:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// #
/// client.with_framework(|f| f.configure(|c| c
/// .prefixes(vec!["!", ">", "+"])));
/// ```
pub fn prefixes(mut self, prefixes: Vec<&str>) -> Self {
self.prefixes = prefixes.iter().map(|x| x.to_string()).collect();

Expand Down
28 changes: 28 additions & 0 deletions src/framework/help_commands.rs
Expand Up @@ -51,6 +51,20 @@ fn remove_aliases(cmds: &HashMap<String, CommandOrAlias>) -> HashMap<&String, &I
result
}

/// Posts an embed showing each individual command group and its commands.
///
/// # Examples
///
/// Use the command with `exec_help`:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// use serenity::ext::framework::help_commands;
///
/// client.with_framework(|f| f
/// .command("help", |c| c.exec_help(help_commands::with_embeds)));
/// ```
pub fn with_embeds(ctx: &mut Context,
_: &Message,
groups: HashMap<String, Arc<CommandGroup>>,
Expand Down Expand Up @@ -186,6 +200,20 @@ pub fn with_embeds(ctx: &mut Context,
Ok(())
}

/// Posts formatted text displaying each individual command group and its commands.
///
/// # Examples
///
/// Use the command with `exec_help`:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// use serenity::ext::framework::help_commands;
///
/// client.with_framework(|f| f
/// .command("help", |c| c.exec_help(help_commands::plain)));
/// ```
pub fn plain(ctx: &mut Context,
_: &Message,
groups: HashMap<String, Arc<CommandGroup>>,
Expand Down
141 changes: 141 additions & 0 deletions src/framework/mod.rs
Expand Up @@ -277,6 +277,22 @@ impl Framework {

/// Defines a bucket with `delay` between each command, and the `limit` of uses
/// per `time_span`.
///
/// # Examples
///
/// Create and use a bucket that limits a command to 3 uses per 10 seconds with
/// a 2 second delay inbetween invocations:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// #
/// client.with_framework(|f| f
/// .bucket("basic", 2, 10, 3)
/// .command("ping", |c| c
/// .bucket("basic")
/// .exec_str("pong!")));
/// ```
pub fn bucket<S>(mut self, s: S, delay: i64, time_span: i64, limit: i32) -> Self
where S: Into<String> {
self.buckets.insert(s.into(), Bucket {
Expand All @@ -291,6 +307,21 @@ impl Framework {
}

/// Defines a bucket with only a `delay` between each command.
///
/// # Examples
///
/// Create and use a simple bucket that has a 2 second delay between invocations:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// #
/// client.with_framework(|f| f
/// .simple_bucket("simple", 2)
/// .command("ping", |c| c
/// .bucket("simple")
/// .exec_str("pong!")));
/// ```
pub fn simple_bucket<S>(mut self, s: S, delay: i64) -> Self
where S: Into<String> {
self.buckets.insert(s.into(), Bucket {
Expand Down Expand Up @@ -552,6 +583,24 @@ impl Framework {
///
/// [`command`]: #method.command
/// [module-level documentation]: index.html
///
/// # Examples
///
/// Create and use a simple command:
///
/// ```rust
/// # #[macro_use] extern crate serenity;
/// command!(ping(_ctx, msg) {
/// msg.channel_id.say("pong!");
/// });
/// #
/// # fn main() {
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// #
/// client.with_framework(|f| f.on("ping", ping));
/// # }
/// ```
pub fn on<F, S>(mut self, command_name: S, f: F) -> Self
where F: Fn(&mut Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static,
S: Into<String> {
Expand Down Expand Up @@ -612,6 +661,22 @@ impl Framework {
self
}

/// Adds a group which can organize several related commands.
/// Groups are taken into account when using `serenity::framework::help_commands`.
///
/// # Examples
///
/// Creating a simple group:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// #
/// client.with_framework(|f| f
/// .group("ping-pong", |g| g
/// .command("ping", |c| c.exec_str("pong!"))
/// .command("pong", |c| c.exec_str("ping!"))));
/// ```
pub fn group<F, S>(mut self, group_name: S, f: F) -> Self
where F: FnOnce(CreateGroup) -> CreateGroup,
S: Into<String> {
Expand All @@ -626,6 +691,29 @@ impl Framework {
/// Specify the function that's called in case a command wasn't executed for one reason or another.
///
/// DispatchError represents all possible fail conditions.
///
/// # Examples
///
/// Making a simple argument error responder:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// use serenity::framework::DispatchError::{NotEnoughArguments, TooManyArguments};
///
/// client.with_framework(|f| f
/// .on_dispatch_error(|ctx, msg, error| {
/// match error {
/// NotEnoughArguments { min, given } => {
/// msg.channel_id.say(&format!("Need {} arguments, but only got {}.", min, given));
/// }
/// TooManyArguments { max, given } => {
/// msg.channel_id.say(&format!("Max arguments allowed is {}, but got {}.", max, given));
/// }
/// _ => println!("Unhandled dispatch error.")
/// }
/// }));
/// ```
pub fn on_dispatch_error<F>(mut self, f: F) -> Self
where F: Fn(Context, Message, DispatchError) + Send + Sync + 'static {
self.dispatch_error_handler = Some(Arc::new(f));
Expand All @@ -635,6 +723,42 @@ impl Framework {

/// Specify the function to be called prior to every command's execution.
/// If that function returns true, the command will be executed.
///
/// # Examples
///
/// Using `before` to log command usage:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// #
/// client.with_framework(|f| f
/// .before(|ctx, msg, cmd_name| {
/// println!("Running command {}", cmd_name);
/// true
/// }));
/// ```
///
/// Using before to prevent command usage:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// #
/// client.with_framework(|f| f
/// .before(|ctx, msg, cmd_name| {
/// if let Ok(channel) = msg.channel_id.get() {
/// // Don't run unless in nsfw channel
/// if !channel.is_nsfw() {
/// return false;
/// }
/// }
///
/// println!("Running command {}", cmd_name);
/// true
/// }));
/// ```
///
pub fn before<F>(mut self, f: F) -> Self
where F: Fn(&mut Context, &Message, &String) -> bool + Send + Sync + 'static {
self.before = Some(Arc::new(f));
Expand All @@ -644,6 +768,23 @@ impl Framework {

/// Specify the function to be called after every command's execution.
/// Fourth argument exists if command returned an error which you can handle.
///
/// # Examples
///
/// Using `after` to log command usage:
///
/// ```rust
/// # use serenity::Client;
/// # let mut client = Client::login("token");
/// #
/// client.with_framework(|f| f
/// .after(|ctx, msg, cmd_name, error| {
/// // Print out an error if it happened
/// if let Err(why) = error {
/// println!("Error in {}: {:?}", cmd_name, why);
/// }
/// }));
/// ```
pub fn after<F>(mut self, f: F) -> Self
where F: Fn(&mut Context, &Message, &String, Result<(), String>) + Send + Sync + 'static {
self.after = Some(Arc::new(f));
Expand Down