aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZeyla Hellyer <[email protected]>2017-05-23 10:15:26 -0700
committerZeyla Hellyer <[email protected]>2017-05-23 10:15:26 -0700
commit8c0aeacadb93d3b56fb98beb882eaef1f79cd652 (patch)
tree7c1d26addbf15537c6f69a6ac9623276002b155a /src
parentFix {Invite,RichInvite}::url tests (diff)
downloadserenity-8c0aeacadb93d3b56fb98beb882eaef1f79cd652.tar.xz
serenity-8c0aeacadb93d3b56fb98beb882eaef1f79cd652.zip
Add more examples and improve some others
Add examples to some functions, and update some of the old examples to use the `?` operator instead of unwrapping.
Diffstat (limited to 'src')
-rw-r--r--src/builder/create_invite.rs142
-rw-r--r--src/builder/edit_guild.rs35
-rw-r--r--src/builder/edit_profile.rs9
-rw-r--r--src/builder/edit_role.rs10
-rw-r--r--src/builder/execute_webhook.rs74
-rw-r--r--src/builder/get_messages.rs32
-rw-r--r--src/cache/mod.rs69
-rw-r--r--src/client/context.rs166
-rw-r--r--src/client/mod.rs313
-rw-r--r--src/gateway/shard.rs151
-rw-r--r--src/model/misc.rs2
-rw-r--r--src/utils/colour.rs19
-rw-r--r--src/utils/message_builder.rs208
-rw-r--r--src/utils/mod.rs154
14 files changed, 1278 insertions, 106 deletions
diff --git a/src/builder/create_invite.rs b/src/builder/create_invite.rs
index 67e33fc..98fc2b9 100644
--- a/src/builder/create_invite.rs
+++ b/src/builder/create_invite.rs
@@ -11,17 +11,43 @@ use ::internal::prelude::*;
///
/// Create an invite with a max age of 3600 seconds and 10 max uses:
///
-/// ```rust,ignore
-/// use serenity::Client;
-/// use std::env;
+/// ```rust,no_run
+/// # use serenity::Client;
+/// #
+/// # let mut client = Client::login("");
+/// #
+/// use serenity::client::CACHE;
///
-/// let mut client = Client::login(&env::var("DISCORD_BOT_TOKEN").unwrap());
+/// client.on_message(|_, msg| {
+/// if msg.content == "!createinvite" {
+/// let channel = match CACHE.read().unwrap().guild_channel(msg.channel_id) {
+/// Some(channel) => channel,
+/// None => {
+/// let _ = msg.channel_id.say("Error creating invite");
///
-/// client.on_message(|_, message| {
-/// if message.content == "!invite" {
-/// let invite = message.channel_id.create_invite(|i| i
-/// .max_age(3600)
-/// .max_uses(10));
+/// return;
+/// },
+/// };
+///
+/// let reader = channel.read().unwrap();
+///
+/// let invite = match reader.create_invite(|i| i.max_age(3600).max_uses(10)) {
+/// Ok(invite) => invite,
+/// Err(why) => {
+/// println!("Err creating invite: {:?}", why);
+///
+/// if let Err(why) = msg.channel_id.say("Error creating invite") {
+/// println!("Err sending err msg: {:?}", why);
+/// }
+///
+/// return;
+/// },
+/// };
+///
+/// drop(reader);
+///
+/// let content = format!("Here's your invite: {}", invite.url());
+/// let _ = msg.channel_id.say(&content);
/// }
/// });
/// ```
@@ -37,6 +63,28 @@ impl CreateInvite {
/// Set to `0` for an invite which does not expire after an amount of time.
///
/// Defaults to `86400`, or 24 hours.
+ ///
+ /// # Examples
+ ///
+ /// Create an invite with a max age of `3600` seconds, or 1 hour:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::CACHE;
+ /// # use serenity::model::ChannelId;
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let channel = CACHE.read().unwrap().guild_channel(81384788765712384).unwrap();
+ /// # let channel = channel.read().unwrap();
+ /// #
+ /// let invite = channel.create_invite(|i| i.max_age(3600))?;
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
pub fn max_age(mut self, max_age: u64) -> Self {
self.0.insert("max_age".to_owned(), Value::Number(Number::from(max_age)));
@@ -48,6 +96,28 @@ impl CreateInvite {
/// Set to `0` for an invite which does not expire after a number of uses.
///
/// Defaults to `0`.
+ ///
+ /// # Examples
+ ///
+ /// Create an invite with a max use limit of `5`:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::CACHE;
+ /// # use serenity::model::ChannelId;
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let channel = CACHE.read().unwrap().guild_channel(81384788765712384).unwrap();
+ /// # let channel = channel.read().unwrap();
+ /// #
+ /// let invite = channel.create_invite(|i| i.max_uses(5))?;
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
pub fn max_uses(mut self, max_uses: u64) -> Self {
self.0.insert("max_uses".to_owned(), Value::Number(Number::from(max_uses)));
@@ -57,6 +127,28 @@ impl CreateInvite {
/// Whether an invite grants a temporary membership.
///
/// Defaults to `false`.
+ ///
+ /// # Examples
+ ///
+ /// Create an invite which is temporary:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::CACHE;
+ /// # use serenity::model::ChannelId;
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let channel = CACHE.read().unwrap().guild_channel(81384788765712384).unwrap();
+ /// # let channel = channel.read().unwrap();
+ /// #
+ /// let invite = channel.create_invite(|i| i.temporary(true))?;
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
pub fn temporary(mut self, temporary: bool) -> Self {
self.0.insert("temporary".to_owned(), Value::Bool(temporary));
@@ -66,6 +158,28 @@ impl CreateInvite {
/// Whether or not to try to reuse a similar invite.
///
/// Defaults to `false`.
+ ///
+ /// # Examples
+ ///
+ /// Create an invite which is unique:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::CACHE;
+ /// # use serenity::model::ChannelId;
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let channel = CACHE.read().unwrap().guild_channel(81384788765712384).unwrap();
+ /// # let channel = channel.read().unwrap();
+ /// #
+ /// let invite = channel.create_invite(|i| i.unique(true))?;
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
pub fn unique(mut self, unique: bool) -> Self {
self.0.insert("unique".to_owned(), Value::Bool(unique));
@@ -75,6 +189,16 @@ impl CreateInvite {
impl Default for CreateInvite {
/// Creates a builder with default values, setting `validate` to `null`.
+ ///
+ /// # Examples
+ ///
+ /// Create a default `CreateInvite` builder:
+ ///
+ /// ```rust
+ /// use serenity::utils::builder::CreateInvite;
+ ///
+ /// let invite_builder = CreateInvite::default();
+ /// ```
fn default() -> CreateInvite {
let mut map = Map::new();
map.insert("validate".to_owned(), Value::Null);
diff --git a/src/builder/edit_guild.rs b/src/builder/edit_guild.rs
index aa08341..c01b8ea 100644
--- a/src/builder/edit_guild.rs
+++ b/src/builder/edit_guild.rs
@@ -49,15 +49,25 @@ impl EditGuild {
/// Using the utility function - [`utils::read_image`] - to read an image
/// from the cwd and encode it in base64 to send to Discord.
///
- /// ```rust,ignore
+ /// ```rust,no_run
+ /// # use serenity::model::GuildId;
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let mut guild = GuildId(0).get()?;
/// use serenity::utils;
///
/// // assuming a `guild` has already been bound
///
- /// let base64_icon = utils::read_image("./guild_icon.png")
- /// .expect("Failed to read image");
+ /// let base64_icon = utils::read_image("./guild_icon.png")?;
///
- /// let _ = guild.edit(|g| g.icon(base64_icon));
+ /// guild.edit(|g| g.icon(Some(&base64_icon)))?;
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
/// ```
///
/// [`utils::read_image`]: ../utils/fn.read_image.html
@@ -91,14 +101,23 @@ impl EditGuild {
///
/// Setting the region to [`Region::UsWest`]:
///
- /// ```rust,ignore
+ /// ```rust,no_run
+ /// # use serenity::model::GuildId;
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let mut guild = GuildId(0).get()?;
/// use serenity::model::Region;
///
/// // assuming a `guild` has already been bound
///
- /// if let Err(why) = guild.edit(|g| g.region(Region::UsWest)) {
- /// println!("Error editing guild's region: {:?}", why);
- /// }
+ /// guild.edit(|g| g.region(Region::UsWest))?;
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
/// ```
///
/// [`Region::UsWest`]: ../model/enum.Region.html#variant.UsWest
diff --git a/src/builder/edit_profile.rs b/src/builder/edit_profile.rs
index d63a512..a4b5c99 100644
--- a/src/builder/edit_profile.rs
+++ b/src/builder/edit_profile.rs
@@ -18,7 +18,13 @@ impl EditProfile {
/// A utility method - [`utils::read_image`] - is provided to read an
/// image from a file and return its contents in base64-encoded form:
///
- /// ```rust,ignore
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// #
+ /// # client.on_message(|context, _| {
+ /// #
/// use serenity::utils;
///
/// // assuming a `context` has been bound
@@ -29,6 +35,7 @@ impl EditProfile {
/// let _ = context.edit_profile(|profile| {
/// profile.avatar(Some(&base64))
/// });
+ /// # });
/// ```
///
/// [`utils::read_image`]: ../fn.read_image.html
diff --git a/src/builder/edit_role.rs b/src/builder/edit_role.rs
index 64cc42b..f17947a 100644
--- a/src/builder/edit_role.rs
+++ b/src/builder/edit_role.rs
@@ -16,11 +16,15 @@ use ::model::{Permissions, Role, permissions};
///
/// # Examples
///
-/// Create a hoisted, mentionable role named "a test role":
+/// Create a hoisted, mentionable role named `"a test role"`:
///
-/// ```rust,ignore
+/// ```rust,no_run
+/// # use serenity::model::{ChannelId, GuildId};
+/// # let (channel_id, guild_id) = (ChannelId(1), GuildId(2));
+/// #
/// // assuming a `channel_id` and `guild_id` has been bound
-/// let role = channel_id.create_role(guild_id, |r| r
+///
+/// let role = guild_id.create_role(|r| r
/// .hoist(true)
/// .mentionable(true)
/// .name("a test role"));
diff --git a/src/builder/execute_webhook.rs b/src/builder/execute_webhook.rs
index 67e10be..68a39fc 100644
--- a/src/builder/execute_webhook.rs
+++ b/src/builder/execute_webhook.rs
@@ -15,7 +15,7 @@ use ::internal::prelude::*;
/// Creating two embeds, and then sending them as part of the delivery
/// payload of [`Webhook::execute`]:
///
-/// ```rust,ignore
+/// ```rust,no_run
/// use serenity::http;
/// use serenity::model::Embed;
/// use serenity::utils::Colour;
@@ -57,6 +57,22 @@ pub struct ExecuteWebhook(pub JsonMap);
impl ExecuteWebhook {
/// Override the default avatar of the webhook with an image URL.
+ ///
+ /// # Examples
+ ///
+ /// Overriding the default avatar:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::http;
+ /// #
+ /// # let webhook = http::get_webhook_with_token(0, "").unwrap();
+ /// #
+ /// let avatar_url = "https://i.imgur.com/KTs6whd.jpg";
+ ///
+ /// let _ = webhook.execute(|w| w
+ /// .avatar_url(avatar_url)
+ /// .content("Here's a webhook"));
+ /// ```
pub fn avatar_url(mut self, avatar_url: &str) -> Self {
self.0.insert("avatar_url".to_owned(), Value::String(avatar_url.to_owned()));
@@ -68,6 +84,20 @@ impl ExecuteWebhook {
/// Note that when setting at least one embed via [`embeds`], this may be
/// omitted.
///
+ /// # Examples
+ ///
+ /// Sending a webhook with a content of `"foo"`:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::rest;
+ /// #
+ /// # let webhook = rest::get_webhook_with_token(0, "").unwrap();
+ /// #
+ /// if let Err(why) = webhook.execute(|w| w.content("foo")) {
+ /// println!("Err sending webhook: {:?}", why);
+ /// }
+ /// ```
+ ///
/// [`embeds`]: #method.embeds
pub fn content(mut self, content: &str) -> Self {
self.0.insert("content".to_owned(), Value::String(content.to_owned()));
@@ -96,7 +126,19 @@ impl ExecuteWebhook {
/// Whether the message is a text-to-speech message.
///
- /// Think carefully before setting this to `true`.
+ /// # Examples
+ ///
+ /// Sending a webhook with text-to-speech enabled:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::rest;
+ /// #
+ /// # let webhook = rest::get_webhook_with_token(0, "").unwrap();
+ /// #
+ /// if let Err(why) = webhook.execute(|w| w.content("hello").tts(true)) {
+ /// println!("Err sending webhook: {:?}", why);
+ /// }
+ /// ```
pub fn tts(mut self, tts: bool) -> Self {
self.0.insert("tts".to_owned(), Value::Bool(tts));
@@ -104,6 +146,20 @@ impl ExecuteWebhook {
}
/// Override the default username of the webhook.
+ ///
+ /// # Examples
+ ///
+ /// Overriuding the username to `"hakase"`:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::rest;
+ /// #
+ /// # let webhook = rest::get_webhook_with_token(0, "").unwrap();
+ /// #
+ /// if let Err(why) = webhook.execute(|w| w.content("hello").username("hakase")) {
+ /// println!("Err sending webhook: {:?}", why);
+ /// }
+ /// ```
pub fn username(mut self, username: &str) -> Self {
self.0.insert("username".to_owned(), Value::String(username.to_owned()));
@@ -114,9 +170,17 @@ impl ExecuteWebhook {
impl Default for ExecuteWebhook {
/// Returns a default set of values for a [`Webhook`] execution.
///
- /// The only default value is [`tts`] being set to `true`. In the event that
- /// there is a bug that Discord defaults `tts` to `true`, at least
- /// serenity won't be a part of it.
+ /// The only default value is [`tts`] being set to `false`.
+ ///
+ /// # Examples
+ ///
+ /// Creating an `ExecuteWebhook` builder:
+ ///
+ /// ```rust
+ /// use serenity::utils::builder::ExecuteWebhook;
+ ///
+ /// let executer = ExecuteWebhook::default();
+ /// ```
///
/// [`Webhook`]: ../model/struct.Webhook.html
/// [`tts`]: #method.tts
diff --git a/src/builder/get_messages.rs b/src/builder/get_messages.rs
index b9142a1..193adca 100644
--- a/src/builder/get_messages.rs
+++ b/src/builder/get_messages.rs
@@ -18,9 +18,37 @@ use ::model::MessageId;
/// does not _need_ to be called and defaults to a value of 50.
///
/// This should be used only for retrieving messages; see
-/// [`Client::get_messages`] for examples.
+/// [`GuildChannel::messages`] for examples.
///
-/// [`Client::get_messages`]: ../client/struct.Client.html#method.get_messages
+/// # Examples
+///
+/// Creating a `GetMessages` builder to retrieve the first 25 messages after the
+/// message with an Id of `158339864557912064`:
+///
+/// ```rust,no_run
+/// # use std::error::Error;
+/// #
+/// # fn try_main() -> Result<(), Box<Error>> {
+/// use serenity::model::{ChannelId, MessageId};
+/// use serenity::builder::GetMessages;
+///
+/// let retriever = GetMessages::default()
+/// .after(MessageId(158339864557912064))
+/// .limit(25);
+///
+/// // you can then pass it into a function which retrieves messages:
+/// let channel_id = ChannelId(81384788765712384);
+///
+/// let _messages = channel_id.messages(|_| retriever)?;
+/// # Ok(())
+/// # }
+/// #
+/// # fn main() {
+/// # try_main().unwrap();
+/// # }
+/// ```
+///
+/// [`GuildChannel::messages`]: ../model/struct.GuildChannel.html#method.messages
#[derive(Clone, Debug, Default)]
pub struct GetMessages(pub BTreeMap<String, u64>);
diff --git a/src/cache/mod.rs b/src/cache/mod.rs
index 7bea675..bbd1a88 100644
--- a/src/cache/mod.rs
+++ b/src/cache/mod.rs
@@ -186,7 +186,7 @@ pub struct Cache {
/// [`GuildMembersChunkEvent`]: ../model/event/struct.GuildMembersChunkEvent.html
/// [`GuildSyncEvent`]: ../model/event/struct.GuildSyncEvent.html
/// [`PresenceUpdateEvent`]: ../model/event/struct.PresenceUpdateEvent.html
- /// [`Ready`]: ../model/event/struct.ReadyEvent.html
+ /// [`ReadyEvent`]: ../model/event/struct.ReadyEvent.html
pub users: HashMap<UserId, Arc<RwLock<User>>>,
}
@@ -194,13 +194,39 @@ impl Cache {
/// Fetches the number of [`Member`]s that have not had data received.
///
/// The important detail to note here is that this is the number of
- /// _member_s that have not had data downloaded. A single [`User`] may have
+ /// _member_s that have not had data received. A single [`User`] may have
/// multiple associated member objects that have not been received.
///
/// This can be used in combination with [`Shard::chunk_guilds`], and can be
- /// used to determine how many members have not yet been downloaded.
+ /// used to determine how many members have not yet been received.
+ ///
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// #
+ /// use serenity::client::CACHE;
+ /// use std::thread;
+ /// use std::time::Duration;
+ ///
+ /// client.on_ready(|ctx, _| {
+ /// // Wait some time for guilds to be received.
+ /// //
+ /// // You should keep track of this in a better fashion by tracking how
+ /// // many guilds each `ready` has, and incrementing a counter on
+ /// // GUILD_CREATEs. Once the number is equal, print the number of
+ /// // unknown members.
+ /// //
+ /// // For demonstrative purposes we're just sleeping the thread for 5
+ /// // seconds.
+ /// thread::sleep(Duration::from_secs(5));
+ ///
+ /// println!("{} unknown members", CACHE.read().unwrap().unknown_members());
+ /// });
+ /// ```
///
/// [`Member`]: ../model/struct.Member.html
+ /// [`Shard::chunk_guilds`]: ../gateway/struct.Shard.html#method.chunk_guilds
/// [`User`]: ../model/struct.User.html
pub fn unknown_members(&self) -> u64 {
let mut total = 0;
@@ -226,6 +252,16 @@ impl Cache {
/// If there are 6 private channels and 2 groups in the cache, then `8` Ids
/// will be returned.
///
+ /// Printing the count of all private channels and groups:
+ ///
+ /// ```rust,no_run
+ /// use serenity::client::CACHE;
+ ///
+ /// let amount = CACHE.read().unwrap().all_private_channels().len();
+ ///
+ /// println!("There are {} private channels", amount);
+ /// ```
+ ///
/// [`Group`]: ../model/struct.Group.html
/// [`PrivateChannel`]: ../model/struct.PrivateChannel.html
pub fn all_private_channels(&self) -> Vec<ChannelId> {
@@ -242,6 +278,22 @@ impl Cache {
/// retrieved over all shards are included in this count -- not just the
/// current [`Context`]'s shard, if accessing from one.
///
+ /// # Examples
+ ///
+ /// Print all of the Ids of guilds in the Cache:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// #
+ /// use serenity::client::CACHE;
+ ///
+ /// client.on_ready(|_, _| {
+ /// println!("Guilds in the Cache: {:?}", CACHE.read().unwrap().all_guilds());
+ /// });
+ /// ```
+ ///
/// [`Context`]: ../client/struct.Context.html
/// [`Guild`]: ../model/struct.Guild.html
/// [`Shard`]: ../gateway/struct.Shard.html
@@ -314,8 +366,14 @@ impl Cache {
/// Getting a guild's channel via the Id of the message received through a
/// [`Client::on_message`] event dispatch:
///
- /// ```rust,ignore
- /// use serenity::CACHE;
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// #
+ /// # client.on_message(|ctx, message| {
+ /// #
+ /// use serenity::client::CACHE;
///
/// let cache = CACHE.read().unwrap();
///
@@ -329,6 +387,7 @@ impl Cache {
/// return;
/// },
/// };
+ /// # });
/// ```
///
/// [`ChannelId`]: ../model/struct.ChannelId.html
diff --git a/src/client/context.rs b/src/client/context.rs
index 22216b1..9cb76b7 100644
--- a/src/client/context.rs
+++ b/src/client/context.rs
@@ -74,8 +74,16 @@ impl Context {
///
/// Change the current user's username:
///
- /// ```rust,ignore
- /// context.edit_profile(|p| p.username("Hakase"));
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// #
+ /// # client.on_message(|ctx, msg| {
+ /// # if msg.content == "!changename" {
+ /// ctx.edit_profile(|p| p.username("Hakase"));
+ /// # }
+ /// # });
/// ```
#[cfg(feature="builder")]
pub fn edit_profile<F: FnOnce(EditProfile) -> EditProfile>(&self, f: F) -> Result<CurrentUser> {
@@ -105,7 +113,22 @@ impl Context {
}
/// Sets the current user as being [`Online`]. This maintains the current
- /// game and `afk` setting.
+ /// game.
+ ///
+ /// # Examples
+ ///
+ /// Set the current user to being online on the shard:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// client.on_message(|ctx, msg| {
+ /// if msg.content == "!online" {
+ /// ctx.online();
+ /// }
+ /// });
+ /// ```
///
/// [`Online`]: ../model/enum.OnlineStatus.html#variant.Online
pub fn online(&self) {
@@ -113,7 +136,22 @@ impl Context {
}
/// Sets the current user as being [`Idle`]. This maintains the current
- /// game and `afk` setting.
+ /// game.
+ ///
+ /// # Examples
+ ///
+ /// Set the current user to being idle on the shard:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// client.on_message(|ctx, msg| {
+ /// if msg.content == "!idle" {
+ /// ctx.idle();
+ /// }
+ /// });
+ /// ```
///
/// [`Idle`]: ../model/enum.OnlineStatus.html#variant.Idle
pub fn idle(&self) {
@@ -121,7 +159,22 @@ impl Context {
}
/// Sets the current user as being [`DoNotDisturb`]. This maintains the
- /// current game and `afk` setting.
+ /// current game.
+ ///
+ /// # Examples
+ ///
+ /// Set the current user to being Do Not Disturb on the shard:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// client.on_message(|ctx, msg| {
+ /// if msg.content == "!dnd" {
+ /// ctx.dnd();
+ /// }
+ /// });
+ /// ```
///
/// [`DoNotDisturb`]: ../model/enum.OnlineStatus.html#variant.DoNotDisturb
pub fn dnd(&self) {
@@ -129,18 +182,47 @@ impl Context {
}
/// Sets the current user as being [`Invisible`]. This maintains the current
- /// game and `afk` setting.
+ /// game.
///
+ /// # Examples
+ ///
+ /// Set the current user to being invisible on the shard when an
+ /// [`Event::Ready`] is received:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// client.on_ready(|ctx, _| {
+ /// ctx.invisible();
+ /// });
+ /// ```
+ ///
+ /// [`Event::Ready`]: ../model/event/enum.Event.html#variant.Ready
/// [`Invisible`]: ../model/enum.OnlineStatus.html#variant.Invisible
pub fn invisible(&self) {
self.shard.lock().unwrap().set_status(OnlineStatus::Invisible);
}
- /// "Resets" the current user's presence, by setting the game to `None`,
- /// the online status to [`Online`], and `afk` to `false`.
+ /// "Resets" the current user's presence, by setting the game to `None` and
+ /// the online status to [`Online`].
///
/// Use [`set_presence`] for fine-grained control over individual details.
///
+ /// # Examples
+ ///
+ /// Reset the presence when an [`Event::Resumed`] is received:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// client.on_resume(|ctx, _| {
+ /// ctx.reset_presence();
+ /// });
+ /// ```
+ ///
+ /// [`Event::Resumed`]: ../model/event/enum.Event.html#variant.Resumed
/// [`Online`]: ../model/enum.OnlineStatus.html#variant.Online
/// [`set_presence`]: #method.set_presence
pub fn reset_presence(&self) {
@@ -149,19 +231,29 @@ impl Context {
.set_presence(None, OnlineStatus::Online, false)
}
- /// Sets the current game, defaulting to an online status of [`Online`], and
- /// setting `afk` to `false`.
+ /// Sets the current game, defaulting to an online status of [`Online`].
///
/// # Examples
///
- /// Set the current user as playing "Heroes of the Storm":
+ /// Create a command named `~setgame` that accepts a name of a game to be
+ /// playing:
///
- /// ```rust,ignore
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// #
/// use serenity::model::Game;
///
- /// // assuming you are in a context
+ /// client.on_message(|ctx, msg| {
+ /// let args = msg.content.splitn(2, ' ').collect::<Vec<&str>>();
+ ///
+ /// if args.len() < 2 || *unsafe { args.get_unchecked(0) } != "~setgame" {
+ /// return;
+ /// }
///
- /// context.set_game(Game::playing("Heroes of the Storm"));
+ /// ctx.set_game(Game::playing(*unsafe { args.get_unchecked(1) }));
+ /// });
/// ```
///
/// [`Online`]: ../model/enum.OnlineStatus.html#variant.Online
@@ -180,6 +272,21 @@ impl Context {
///
/// **Note**: Maximum length is 128.
///
+ /// # Examples
+ ///
+ /// When an [`Event::Ready`] is received, set the game name to `"test"`:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// #
+ /// client.on_ready(|ctx, _| {
+ /// ctx.set_game_name("test");
+ /// });
+ /// ```
+ ///
+ /// [`Event::Ready`]: ../model/event/enum.Event.html#variant.Ready
/// [`GameType`]: ../model/enum.GameType.html
/// [`Online`]: ../model/enum.OnlineStatus.html#variant.Online
/// [`OnlineStatus`]: ../model/enum.OnlineStatus.html
@@ -202,29 +309,38 @@ impl Context {
///
/// # Examples
///
- /// Setting the current user as having no game, being [`Idle`],
- /// and setting `afk` to `true`:
+ /// Setting the current user as having no game and being [`Idle`]:
///
- /// ```rust,ignore
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// #
+ /// # client.on_ready(|ctx, _| {
+ /// #
/// use serenity::model::OnlineStatus;
///
- /// // assuming you are in a context
- ///
- /// context.set_game(None, OnlineStatus::Idle, true);
+ /// ctx.set_presence(None, OnlineStatus::Idle, false);
+ /// # });
/// ```
///
- /// Setting the current user as playing "Heroes of the Storm", being
- /// [`DoNotDisturb`], and setting `afk` to `false`:
+ /// Setting the current user as playing `"Heroes of the Storm"`, while being
+ /// [`DoNotDisturb`]:
///
/// ```rust,ignore
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// #
+ /// # client.on_ready(|ctx, _| {
+ /// #
/// use serenity::model::{Game, OnlineStatus};
///
- /// // assuming you are in a context
- ///
/// let game = Game::playing("Heroes of the Storm");
/// let status = OnlineStatus::DoNotDisturb;
///
- /// context.set_game(Some(game), status, false);
+ /// context.set_presence(Some(game), status, false);
+ /// # });
/// ```
///
/// [`DoNotDisturb`]: ../model/enum.OnlineStatus.html#variant.DoNotDisturb
diff --git a/src/client/mod.rs b/src/client/mod.rs
index 1ba555a..bdaa2aa 100644
--- a/src/client/mod.rs
+++ b/src/client/mod.rs
@@ -105,9 +105,61 @@ pub struct Client {
/// In the meaning of a context, this data can be accessed through
/// [`Context::data`].
///
+ /// # Examples
+ ///
+ /// Create a `MessageEventCounter` to track the following events:
+ ///
+ /// - [`Event::MessageCreate`]
+ /// - [`Event::MessageDelete`]
+ /// - [`Event::MessageDeleteBulk`]
+ /// - [`Event::MessageUpdate`]
+ ///
+ /// ```rust,ignore
+ /// extern crate serenity;
+ /// extern crate typemap;
+ ///
+ /// use serenity::Client;
+ /// use std::collections::HashMap;
+ /// use std::env;
+ /// use typemap::Key;
+ ///
+ /// struct MessageEventCounter;
+ ///
+ /// impl Key for MessageEventCounter {
+ /// type Value = HashMap<String, u64>;
+ /// }
+ ///
+ /// let mut client = Client::login(&env::var("DISCORD_TOKEN").unwrap());
+ ///
+ /// {
+ /// let mut data = client.data.lock().unwrap();
+ /// data.insert::<MessageEventCounter>(HashMap::default());
+ /// }
+ ///
+ /// macro_rules! reg {
+ /// ($ctx:ident $name:expr) => {
+ /// {
+ /// let mut data = $ctx.data.lock().unwrap();
+ /// let counter = data.get_mut::<MessageEventCounter>().unwrap();
+ /// let entry = counter.entry($name).or_insert(0);
+ /// *entry += 1;
+ /// }
+ /// };
+ /// }
+ ///
+ /// client.on_message(|ctx, _| reg!(ctx "MessageCreate"));
+ /// client.on_message_delete(|ctx, _| reg!(ctx "MessageDelete"));
+ /// client.on_message_delete_bulk(|ctx, _| reg!(ctx "MessageDeleteBulk"));
+ /// client.on_message_update(|ctx, _| reg!(ctx "MessageUpdate"));
+ /// ```
+ ///
/// Refer to [example 05] for an example on using the `data` field.
///
/// [`Context::data`]: struct.Context.html#method.data
+ /// [`Event::MessageCreate`]: ../model/event/enum.Event.html#variant.MessageCreate
+ /// [`Event::MessageDelete`]: ../model/event/enum.Event.html#variant.MessageDelete
+ /// [`Event::MessageDeleteBulk`]: ../model/event/enum.Event.html#variant.MessageDeleteBulk
+ /// [`Event::MessageUpdate`]: ../model/event/enum.Event.html#variant.MessageUpdate
/// [example 05]: https://github.com/zeyla/serenity/tree/master/examples/05_command_framework
pub data: Arc<Mutex<ShareMap>>,
/// A vector of all active shards that have received their [`Event::Ready`]
@@ -137,6 +189,27 @@ impl Client {
///
/// Discord has a requirement of prefixing bot tokens with `"Bot "`, which
/// this function will automatically do for you if not already included.
+ ///
+ /// # Examples
+ ///
+ /// Create a Client, using a token from an environment variable:
+ ///
+ /// ```rust,no_run
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// use serenity::Client;
+ /// use std::env;
+ ///
+ /// let token = env::var("DISCORD_TOKEN")?;
+ /// let client = Client::login(&token);
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
pub fn login(bot_token: &str) -> Self {
let token = if bot_token.starts_with("Bot ") {
bot_token.to_owned()
@@ -154,6 +227,32 @@ impl Client {
/// See the [framework module-level documentation][framework docs] for more
/// information on usage.
///
+ /// # Examples
+ ///
+ /// Create a simple framework that responds to a `~ping` command:
+ ///
+ /// ```rust,no_run
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// use serenity::Client;
+ /// use std::env;
+ ///
+ /// let mut client = Client::login(&env::var("DISCORD_TOKEN")?);
+ /// client.with_framework(|f| f
+ /// .configure(|c| c.prefix("~"))
+ /// .command("ping", |c| c.exec_str("Pong!")));
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
+ ///
+ /// Refer to the documentation for the `framework` module for more in-depth
+ /// information.
+ ///
/// [`on_message`]: #method.on_message
/// [framework docs]: ../framework/index.html
#[cfg(feature="framework")]
@@ -174,6 +273,30 @@ impl Client {
/// Refer to the [Gateway documentation][gateway docs] for more information
/// on effectively using sharding.
///
+ /// # Examples
+ ///
+ /// Starting a Client with only 1 shard, out of 1 total:
+ ///
+ /// ```rust,no_run
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// use serenity::client::Client;
+ /// use std::env;
+ ///
+ /// let mut client = Client::login(&env::var("DISCORD_TOKEN")?);
+ ///
+ /// if let Err(why) = client.start() {
+ /// println!("Err with client: {:?}", why);
+ /// }
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
+ ///
/// [gateway docs]: gateway/index.html#sharding
pub fn start(&mut self) -> Result<()> {
self.start_connection(None, http::get_gateway()?.url)
@@ -191,6 +314,30 @@ impl Client {
/// Refer to the [Gateway documentation][gateway docs] for more information
/// on effectively using sharding.
///
+ /// # Examples
+ ///
+ /// Start as many shards as needed using autosharding:
+ ///
+ /// ```rust,no_run
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// use serenity::Client;
+ /// use std::env;
+ ///
+ /// let mut client = Client::login(&env::var("DISCORD_TOKEN")?);
+ ///
+ /// if let Err(why) = client.start_autosharded() {
+ /// println!("Err with client: {:?}", why);
+ /// }
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
+ ///
/// [gateway docs]: gateway/index.html#sharding
pub fn start_autosharded(&mut self) -> Result<()> {
let mut res = http::get_bot_gateway()?;
@@ -216,6 +363,55 @@ impl Client {
/// Refer to the [Gateway documentation][gateway docs] for more information
/// on effectively using sharding.
///
+ /// # Examples
+ ///
+ /// Start shard 3 of 5:
+ ///
+ /// ```rust,no_run
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// use serenity::Client;
+ /// use std::env;
+ ///
+ /// let mut client = Client::login(&env::var("DISCORD_TOKEN")?);
+ ///
+ /// if let Err(why) = client.start_shard(3, 5) {
+ /// println!("Err with client: {:?}", why);
+ /// }
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
+ ///
+ /// Start shard 0 of 1 (you may also be interested in [`start`] or
+ /// [`start_autosharded`]):
+ ///
+ /// ```rust,no_run
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// use serenity::Client;
+ /// use std::env;
+ ///
+ /// let mut client = Client::login(&env::var("DISCORD_TOKEN")?);
+ ///
+ /// if let Err(why) = client.start_shard(0, 1) {
+ /// println!("Err with client: {:?}", why);
+ /// }
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
+ ///
+ /// [`start`]: #method.start
+ /// [`start_autosharded`]: #method.start_autosharded
/// [gateway docs]: gateway/index.html#sharding
pub fn start_shard(&mut self, shard: u64, shards: u64) -> Result<()> {
self.start_connection(Some([shard, shard, shards]), http::get_gateway()?.url)
@@ -233,8 +429,32 @@ impl Client {
/// Refer to the [Gateway documentation][gateway docs] for more information
/// on effectively using sharding.
///
+ /// # Examples
+ ///
+ /// Start all of 8 shards:
+ ///
+ /// ```rust,no_run
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// use serenity::Client;
+ /// use std::env;
+ ///
+ /// let mut client = Client::login(&env::var("DISCORD_TOKEN")?);
+ ///
+ /// if let Err(why) = client.start_shards(8) {
+ /// println!("Err with client: {:?}", why);
+ /// }
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
+ ///
/// [`start_shard`]: #method.start_shard
- /// [`start_shard_range`]: #method.start_shards
+ /// [`start_shard_range`]: #method.start_shard_range
/// [Gateway docs]: gateway/index.html#sharding
pub fn start_shards(&mut self, total_shards: u64) -> Result<()> {
self.start_connection(Some([0, total_shards - 1, total_shards]), http::get_gateway()?.url)
@@ -267,6 +487,26 @@ impl Client {
/// let _ = client.start_shard_range([4, 7], 10);
/// ```
///
+ /// ```rust,no_run
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// use serenity::Client;
+ /// use std::env;
+ ///
+ /// let mut client = Client::login(&env::var("DISCORD_TOKEN")?);
+ ///
+ /// if let Err(why) = client.start_shard_range([4, 7], 10) {
+ /// println!("Err with client: {:?}", why);
+ /// }
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
+ /// ```
+ ///
/// [`start_shard`]: #method.start_shard
/// [`start_shards`]: #method.start_shards
/// [Gateway docs]: gateway/index.html#sharding
@@ -276,6 +516,26 @@ impl Client {
/// Attaches a handler for when a [`ChannelCreate`] is received.
///
+ /// # Examples
+ ///
+ /// If the channel is a guild channel, send `"first"` to the channel when
+ /// one is created:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// use serenity::model::Channel;
+ ///
+ /// client.on_channel_create(|ctx, channel| {
+ /// if let Channel::Guild(ch) = channel {
+ /// if let Err(why) = ch.read().unwrap().say("first") {
+ /// println!("Err sending first message: {:?}", why);
+ /// }
+ /// }
+ /// });
+ /// ```
+ ///
/// [`ChannelCreate`]: ../model/event/enum.Event.html#variant.ChannelCreate
pub fn on_channel_create<F>(&mut self, handler: F)
where F: Fn(Context, Channel) + Send + Sync + 'static {
@@ -286,6 +546,34 @@ impl Client {
/// Attaches a handler for when a [`ChannelDelete`] is received.
///
+ /// # Examples
+ ///
+ /// If the channel is a guild channel, send the name of the channel to the
+ /// guild's default channel.
+ ///
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// #
+ /// # let mut client = Client::login("");
+ /// use serenity::model::{Channel, ChannelId};
+ ///
+ /// client.on_channel_delete(|ctx, channel| {
+ /// if let Channel::Guild(channel) = channel {
+ /// let (content, default_channel_id) = {
+ /// let reader = channel.read().unwrap();
+ /// let content = format!("A channel named '{}' was deleted.", reader.name);
+ /// let id = ChannelId(reader.guild_id.0);
+ ///
+ /// (content, id)
+ /// };
+ ///
+ /// if let Err(why) = default_channel_id.say(&content) {
+ /// println!("Err sending message to default channel: {:?}", why);
+ /// }
+ /// }
+ /// });
+ /// ```
+ ///
/// [`ChannelDelete`]: ../model/event/enum.Event.html#variant.ChannelDelete
pub fn on_channel_delete<F>(&mut self, handler: F)
where F: Fn(Context, Channel) + Send + Sync + 'static {
@@ -1127,6 +1415,29 @@ fn login(token: String) -> Client {
/// - The second part of the token is at least 6 characters long;
/// - The token does not contain any whitespace prior to or after the token.
///
+/// # Examples
+///
+/// Validate that a token is valid and that a number of invalid tokens are
+/// actually invalid:
+///
+/// ```rust,no_run
+/// use serenity::client::validate_token;
+///
+/// // ensure a valid token is in fact valid:
+/// assert!(validate_token("Mjg4NzYwMjQxMzYzODc3ODg4.C_ikow.j3VupLBuE1QWZng3TMGH0z_UAwg").is_ok());
+///
+/// // "cat" isn't a valid token:
+/// assert!(validate_token("cat").is_err());
+///
+/// // tokens must have three parts, separated by periods (this is still
+/// // actually an invalid token):
+/// assert!(validate_token("aaa.abcdefgh.bbb").is_ok());
+///
+/// // the second part must be _at least_ 6 characters long:
+/// assert!(validate_token("a.abcdef.b").is_ok());
+/// assert!(validate_token("a.abcde.b").is_err());
+/// ```
+///
/// # Errors
///
/// Returns a [`ClientError::InvalidToken`] when one of the above checks fail.
diff --git a/src/gateway/shard.rs b/src/gateway/shard.rs
index c9886c4..9c635ec 100644
--- a/src/gateway/shard.rs
+++ b/src/gateway/shard.rs
@@ -188,6 +188,18 @@ impl Shard {
///
/// For example, if using 3 shards in total, and if this is shard 1, then it
/// can be read as "the second of three shards".
+ ///
+ /// # Examples
+ ///
+ /// Retrieving the shard info for the second shard, out of two shards total:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::gateway::Shard;
+ /// #
+ /// # let (shard, _, _) = Shard::new("", "", Some([1, 2])).unwrap();
+ /// #
+ /// assert_eq!(shard.shard_info(), Some([1, 2]));
+ /// ```
pub fn shard_info(&self) -> Option<[u64; 2]> {
self.shard_info
}
@@ -205,6 +217,20 @@ impl Shard {
/// Sets the user's current game, if any.
///
/// Other presence settings are maintained.
+ ///
+ /// # Examples
+ ///
+ /// Setting the current game to playing `"Heroes of the Storm"`:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::gateway::Shard;
+ /// #
+ /// # let (mut shard, _, _) = Shard::new("", "", Some([0, 1])).unwrap();
+ /// #
+ /// use serenity::model::Game;
+ ///
+ /// shard.set_game(Some(Game::playing("Heroes of the Storm")));
+ /// ```
pub fn set_game(&mut self, game: Option<Game>) {
self.current_presence.0 = game;
@@ -213,11 +239,26 @@ impl Shard {
/// Sets the user's current online status.
///
- /// Note that [`Offline`] is not a valid presence, so it is automatically
- /// converted to [`Invisible`].
+ /// Note that [`Offline`] is not a valid online status, so it is
+ /// automatically converted to [`Invisible`].
///
/// Other presence settings are maintained.
///
+ /// # Examples
+ ///
+ /// Setting the current online status for the shard to [`DoNotDisturb`].
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::gateway::Shard;
+ /// #
+ /// # let (mut shard, _, _) = Shard::new("", "", Some([0, 1])).unwrap();
+ /// #
+ /// use serenity::model::OnlineStatus;
+ ///
+ /// shard.set_status(OnlineStatus::DoNotDisturb);
+ /// ```
+ ///
+ /// [`DoNotDisturb`]: ../../model/enum.OnlineStatus.html#variant.DoNotDisturb
/// [`Invisible`]: ../../model/enum.OnlineStatus.html#variant.Invisible
/// [`Offline`]: ../../model/enum.OnlineStatus.html#variant.Offline
pub fn set_status(&mut self, online_status: OnlineStatus) {
@@ -239,16 +280,14 @@ impl Shard {
/// Set the current user as playing `"Heroes of the Storm"`, being online,
/// and not being afk:
///
- /// ```rust,ignore
+ /// ```rust,no_run
+ /// # use serenity::client::gateway::Shard;
+ /// #
+ /// # let (mut shard, _, _) = Shard::new("", "", Some([0, 1])).unwrap();
+ /// #
/// use serenity::model::{Game, OnlineStatus};
///
- /// // assuming you are in a context
- ///
- /// context.shard.lock()
- /// .unwrap()
- /// .set_presence(Some(Game::playing("Heroes of the Storm")),
- /// OnlineStatus::Online,
- /// false);
+ /// shard.set_presence(Some(Game::playing("Heroes of the Storm")), OnlineStatus::Online, false);
/// ```
pub fn set_presence(&mut self,
game: Option<Game>,
@@ -444,8 +483,32 @@ impl Shard {
}
}
- /// Calculates the heartbeat latency (in nanoseconds) between the shard and
- /// Discord.
+ /// Calculates the heartbeat latency between the shard and the gateway.
+ ///
+ /// # Examples
+ ///
+ /// When using the [`Client`], output the latency in response to a `"~ping"`
+ /// message handled through [`Client::on_message`].
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::Client;
+ /// #
+ /// # let mut client = Client::login("hello source code viewer <3");
+ /// client.on_message(|ctx, msg| {
+ /// if msg.content == "~ping" {
+ /// if let Some(latency) = ctx.shard.lock().unwrap().latency() {
+ /// let s = format!("{}.{}s", latency.as_secs(), latency.subsec_nanos());
+ ///
+ /// let _ = msg.channel_id.say(&s);
+ /// } else {
+ /// let _ = msg.channel_id.say("N/A");
+ /// }
+ /// }
+ /// });
+ /// ```
+ ///
+ /// [`Client`]: ../struct.Client.html
+ /// [`Client::on_message`]: ../struct.Client.html#method.on_message
// Shamelessly stolen from brayzure's commit in eris:
// <https://github.com/abalabahaha/eris/commit/0ce296ae9a542bcec0edf1c999ee2d9986bed5a6>
pub fn latency(&self) -> Option<StdDuration> {
@@ -487,16 +550,52 @@ impl Shard {
/// Requests that one or multiple [`Guild`]s be chunked.
///
- /// This will ask Discord to start sending member chunks for large guilds
- /// (250 members+). If a guild is over 250 members, then a full member list
- /// will not be downloaded, and must instead be requested to be sent in
- /// "chunks" containing members.
+ /// This will ask the gateway to start sending member chunks for large
+ /// guilds (250 members+). If a guild is over 250 members, then a full
+ /// member list will not be downloaded, and must instead be requested to be
+ /// sent in "chunks" containing members.
///
/// Member chunks are sent as the [`Event::GuildMembersChunk`] event. Each
/// chunk only contains a partial amount of the total members.
///
/// If the `cache` feature is enabled, the cache will automatically be
/// updated with member chunks.
+ ///
+ /// # Examples
+ ///
+ /// Chunk a single guild by Id, limiting to 2000 [`Member`]s, and not
+ /// specifying a query parameter:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::gateway::Shard;
+ /// #
+ /// # let (shard, _, _) = Shard::new("", "", Some([0, 1])).unwrap();
+ /// #
+ /// use serenity::model::GuildId;
+ ///
+ /// let guild_ids = vec![GuildId(81384788765712384)];
+ ///
+ /// shard.chunk_guilds(&guild_ids, Some(2000), None);
+ /// ```
+ ///
+ /// Chunk a single guild by Id, limiting to 20 members, and specifying a
+ /// query parameter of `"do"`:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::gateway::Shard;
+ /// #
+ /// # let (shard, _, _) = Shard::new("", "", Some([0, 1])).unwrap();
+ /// #
+ /// use serenity::model::GuildId;
+ ///
+ /// let guild_ids = vec![GuildId(81384788765712384)];
+ ///
+ /// shard.chunk_guilds(&guild_ids, Some(20), Some("do"));
+ /// ```
+ ///
+ /// [`Event::GuildMembersChunk`]: ../../model/event/enum.Event.html#variant.GuildMembersChunk
+ /// [`Guild`]: ../../model/struct.Guild.html
+ /// [`Member`]: ../../model/struct.Member.html
pub fn chunk_guilds(&self, guild_ids: &[GuildId], limit: Option<u16>, query: Option<&str>) {
let msg = json!({
"op": OpCode::GetGuildMembers.num(),
@@ -513,11 +612,27 @@ impl Shard {
/// Calculates the number of guilds that the shard is responsible for.
///
/// If sharding is not being used (i.e. 1 shard), then the total number of
- /// guilds in the [`Cache`] will be used.
+ /// [`Guild`] in the [`Cache`] will be used.
///
/// **Note**: Requires the `cache` feature be enabled.
///
- /// [`Cache`]: ../cache/struct.Cache.html
+ /// # Examples
+ ///
+ /// Retrieve the number of guilds a shard is responsible for:
+ ///
+ /// ```rust,no_run
+ /// # use serenity::client::gateway::Shard;
+ /// #
+ /// # let (shard, _, _) = Shard::new("will anyone read this", "", Some([0, 1])).unwrap();
+ /// #
+ /// let info = shard.shard_info();
+ /// let guilds = shard.guilds_handled();
+ ///
+ /// println!("Shard {:?} is responsible for {} guilds", info, guilds);
+ /// ```
+ ///
+ /// [`Cache`]: ../ext/cache/struct.Cache.html
+ /// [`Guild`]: ../model/struct.Guild.html
#[cfg(feature="cache")]
pub fn guilds_handled(&self) -> u16 {
let cache = CACHE.read().unwrap();
diff --git a/src/model/misc.rs b/src/model/misc.rs
index 4da3c01..3ac8f47 100644
--- a/src/model/misc.rs
+++ b/src/model/misc.rs
@@ -123,7 +123,7 @@ impl FromStr for RoleId {
}
/// A version of an emoji used only when solely the Id and name are known.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct EmojiIdentifier {
/// The Id of the emoji.
pub id: EmojiId,
diff --git a/src/utils/colour.rs b/src/utils/colour.rs
index 1a4e856..71fc25a 100644
--- a/src/utils/colour.rs
+++ b/src/utils/colour.rs
@@ -24,13 +24,24 @@ macro_rules! colour {
/// Passing in a role's colour, and then retrieving its green component
/// via [`g`]:
///
-/// ```rust,ignore
+/// ```rust
+/// # use serenity::model::{Role, RoleId, permissions};
/// use serenity::utils::Colour;
+/// #
+/// # let role = Role {
+/// # colour: Colour::blurple(),
+/// # hoist: false,
+/// # id: RoleId(1),
+/// # managed: false,
+/// # mentionable: false,
+/// # name: "test".to_owned(),
+/// # permissions: permissions::PRESET_GENERAL,
+/// # position: 7,
+/// # };
///
/// // assuming a `role` has already been bound
///
-/// let colour = Colour::new(role.colour);
-/// let green = colour.g();
+/// let green = role.colour.g();
///
/// println!("The green component is: {}", green);
/// ```
@@ -45,7 +56,7 @@ macro_rules! colour {
/// assert_eq!(colour.tuple(), (17, 128, 106));
/// ```
///
-/// Colours can also be directly compared for equivilance:
+/// Colours can also be directly compared for equivalence:
///
/// ```rust
/// use serenity::utils::Colour;
diff --git a/src/utils/message_builder.rs b/src/utils/message_builder.rs
index a6e7e0b..3029226 100644
--- a/src/utils/message_builder.rs
+++ b/src/utils/message_builder.rs
@@ -12,7 +12,18 @@ use ::model::{ChannelId, Emoji, Mentionable, RoleId, UserId};
/// Build a message, mentioning a [`user`] and an [`emoji`], and retrieving the
/// value:
///
-/// ```rust,ignore
+/// ```rust,no_run
+/// # use serenity::model::{Emoji, EmojiId, UserId};
+/// #
+/// # let user = UserId(1);
+/// # let emoji = Emoji {
+/// # id: EmojiId(2),
+/// # name: "test".to_owned(),
+/// # managed: false,
+/// # require_colons: true,
+/// # roles: vec![],
+/// # };
+/// #
/// use serenity::utils::MessageBuilder;
///
/// // assuming an `emoji` and `user` have already been bound
@@ -32,7 +43,20 @@ use ::model::{ChannelId, Emoji, Mentionable, RoleId, UserId};
pub struct MessageBuilder(pub String);
impl MessageBuilder {
- /// Creates a new, empty-content builder.
+ /// Creates a new, empty builder.
+ ///
+ /// # Examples
+ ///
+ /// Create a new `MessageBuilder`:
+ ///
+ /// ```rust
+ /// use serenity::utils::MessageBuilder;
+ ///
+ /// let message = MessageBuilder::new();
+ ///
+ /// // alternatively:
+ /// let message = MessageBuilder::default();
+ /// ```
pub fn new() -> MessageBuilder {
MessageBuilder::default()
}
@@ -41,6 +65,23 @@ impl MessageBuilder {
///
/// # Examples
///
+ /// Create a string mentioning a channel by Id, and then suffixing `"!"`,
+ /// and finally building it to retrieve the inner String:
+ ///
+ /// ```rust
+ /// use serenity::model::ChannelId;
+ /// use serenity::utils::MessageBuilder;
+ ///
+ /// let channel_id = ChannelId(81384788765712384);
+ ///
+ /// let content = MessageBuilder::new()
+ /// .channel(channel_id)
+ /// .push("!")
+ /// .build();
+ ///
+ /// assert_eq!(content, "<#81384788765712384>!");
+ /// ```
+ ///
/// This is equivalent to simply retrieving the tuple struct's first value:
///
/// ```rust
@@ -62,6 +103,25 @@ impl MessageBuilder {
/// Refer to `ChannelId`'s [Display implementation] for more information on
/// how this is formatted.
///
+ /// # Examples
+ ///
+ /// Mentioning a [`Channel`] by Id:
+ ///
+ /// ```rust
+ /// use serenity::model::ChannelId;
+ /// use serenity::utils::MessageBuilder;
+ ///
+ /// let channel_id = ChannelId(81384788765712384);
+ ///
+ /// let content = MessageBuilder::new()
+ /// .push("The channel is: ")
+ /// .channel(channel_id)
+ /// .build();
+ ///
+ /// assert_eq!(content, "The channel is: <#81384788765712384>");
+ /// ```
+ ///
+ /// [`Channel`]: ../model/enum.Channel.html
/// [`ChannelId`]: ../model/struct.ChannelId.html
/// [`GuildChannel`]: ../model/struct.GuildChannel.html
/// [Display implementation]: ../model/struct.ChannelId.html#method.fmt-1
@@ -76,6 +136,31 @@ impl MessageBuilder {
/// Refer to `Emoji`s [Display implementation] for more information on how
/// this is formatted.
///
+ /// # Examples
+ ///
+ /// Mention an emoji in a message's content:
+ ///
+ /// ```rust
+ /// use serenity::model::{Emoji, EmojiId};
+ /// use serenity::utils::MessageBuilder;
+ ///
+ /// let emoji = Emoji {
+ /// id: EmojiId(302516740095606785),
+ /// managed: true,
+ /// name: "smugAnimeFace".to_owned(),
+ /// require_colons: true,
+ /// roles: vec![],
+ /// };
+ ///
+ /// let message = MessageBuilder::new()
+ /// .push("foo ")
+ /// .emoji(emoji)
+ /// .push(".")
+ /// .build();
+ ///
+ /// assert_eq!(message, "foo <:smugAnimeFace:302516740095606785>.");
+ /// ```
+ ///
/// [Display implementation]: ../model/struct.Emoji.html#method.fmt
pub fn emoji(mut self, emoji: Emoji) -> Self {
let _ = write!(self.0, "{}", emoji);
@@ -113,7 +198,45 @@ impl MessageBuilder {
self
}
- /// Pushes a code-block to your message, with optional syntax highlighting.
+ /// Pushes a codeblock to the content, with optional syntax highlighting.
+ ///
+ /// # Examples
+ ///
+ /// Pushing a Rust codeblock:
+ ///
+ /// ```rust,ignore
+ /// use serenity::utils::MessageBuilder;
+ ///
+ /// let code = r#"
+ /// fn main() {
+ /// println!("Hello, world!");
+ /// }
+ /// "#;
+ ///
+ /// let content = MessageBuilder::new()
+ /// .push_codeblock(code, Some("rust"))
+ /// .build();
+ ///
+ /// let expected = r#"```rust
+ /// fn main() {
+ /// println!("Hello, world!");
+ /// }
+ /// ```"#;
+ ///
+ /// assert_eq!(content, expected);
+ /// ```
+ ///
+ /// Pushing a codeblock without a language:
+ ///
+ /// ```rust
+ /// use serenity::utils::MessageBuilder;
+ ///
+ /// let content = MessageBuilder::new()
+ /// .push_codeblock("hello", None)
+ /// .build();
+ ///
+ /// assert_eq!(content, "```\nhello\n```");
+ /// ```
pub fn push_codeblock(mut self, content: &str, language: Option<&str>) -> Self {
self.0.push_str("```");
@@ -128,7 +251,32 @@ impl MessageBuilder {
self
}
- /// Pushes an inline monospaced text to your message.
+ /// Pushes inlined monospaced text to the content.
+ ///
+ /// # Examples
+ ///
+ /// Display a server configuration value to the user:
+ ///
+ /// ```rust
+ /// use serenity::utils::MessageBuilder;
+ ///
+ /// let key = "prefix";
+ /// let value = "&";
+ ///
+ /// let content = MessageBuilder::new()
+ /// .push("The setting ")
+ /// .push_mono(key)
+ /// .push(" for this server is ")
+ /// .push_mono(value)
+ /// .push(".")
+ /// .build();
+ ///
+ /// let expected = format!("The setting `{}` for this server is `{}`.",
+ /// key,
+ /// value);
+ ///
+ /// assert_eq!(content, expected);
+ /// ```
pub fn push_mono(mut self, content: &str) -> Self {
self.0.push('`');
self.0.push_str(content);
@@ -137,7 +285,27 @@ impl MessageBuilder {
self
}
- /// Pushes an inline italicized text to your message.
+ /// Pushes inlined italicized text to the content.
+ ///
+ /// # Examples
+ ///
+ /// Emphasize information to the user:
+ ///
+ /// ```rust
+ /// use serenity::utils::MessageBuilder;
+ ///
+ /// let content = MessageBuilder::new()
+ /// .push("You don't ")
+ /// .push_italic("always need")
+ /// .push(" to italicize ")
+ /// .push_italic("everything")
+ /// .push(".")
+ /// .build();
+ ///
+ /// let expected = "You don't _always need_ to italicize _everything_.";
+ ///
+ /// assert_eq!(content, expected);
+ /// ```
pub fn push_italic(mut self, content: &str) -> Self {
self.0.push('_');
self.0.push_str(content);
@@ -146,7 +314,7 @@ impl MessageBuilder {
self
}
- /// Pushes an inline bold text to your message.
+ /// Pushes an inline bold text to the content.
pub fn push_bold(mut self, content: &str) -> Self {
self.0.push_str("**");
self.0.push_str(content);
@@ -155,7 +323,7 @@ impl MessageBuilder {
self
}
- /// Pushes an underlined inline text to your message.
+ /// Pushes an underlined inline text to the content.
pub fn push_underline(mut self, content: &str) -> Self {
self.0.push_str("__");
self.0.push_str(content);
@@ -164,7 +332,7 @@ impl MessageBuilder {
self
}
- /// Pushes a strikethrough inline text to your message.
+ /// Pushes a strikethrough inline text to the content.
pub fn push_strike(mut self, content: &str) -> Self {
self.0.push_str("~~");
self.0.push_str(content);
@@ -205,7 +373,7 @@ impl MessageBuilder {
self
}
- /// Pushes an inline monospaced text to your message normalizing content.
+ /// Pushes an inline monospaced text to the content normalizing content.
pub fn push_mono_safe(mut self, content: &str) -> Self {
self.0.push('`');
self.0.push_str(&normalize(content).replace('`', "'"));
@@ -214,7 +382,7 @@ impl MessageBuilder {
self
}
- /// Pushes an inline italicized text to your message normalizing content.
+ /// Pushes an inline italicized text to the content normalizing content.
pub fn push_italic_safe(mut self, content: &str) -> Self {
self.0.push('_');
self.0.push_str(&normalize(content).replace('_', " "));
@@ -223,7 +391,7 @@ impl MessageBuilder {
self
}
- /// Pushes an inline bold text to your message normalizing content.
+ /// Pushes an inline bold text to the content normalizing content.
pub fn push_bold_safe(mut self, content: &str) -> Self {
self.0.push_str("**");
self.0.push_str(&normalize(content).replace("**", " "));
@@ -232,7 +400,7 @@ impl MessageBuilder {
self
}
- /// Pushes an underlined inline text to your message normalizing content.
+ /// Pushes an underlined inline text to the content normalizing content.
pub fn push_underline_safe(mut self, content: &str) -> Self {
self.0.push_str("__");
self.0.push_str(&normalize(content).replace("__", " "));
@@ -241,7 +409,7 @@ impl MessageBuilder {
self
}
- /// Pushes a strikethrough inline text to your message normalizing content.
+ /// Pushes a strikethrough inline text to the content normalizing content.
pub fn push_strike_safe(mut self, content: &str) -> Self {
self.0.push_str("~~");
self.0.push_str(&normalize(content).replace("~~", " "));
@@ -286,6 +454,20 @@ impl MessageBuilder {
}
impl fmt::Display for MessageBuilder {
+ /// Formats the message builder into a string.
+ ///
+ /// This is done by simply taking the internal value of the tuple-struct and
+ /// writing it into the formatter.
+ ///
+ /// # Examples
+ ///
+ /// Create a message builder, and format it into a string via the `format!`
+ /// macro:
+ ///
+ /// ```rust
+ /// use serenity::utils::MessageBuilder;
+ ///
+ ///
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index 6ae937e..0ca3e65 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -74,11 +74,11 @@ pub fn is_nsfw(name: &str) -> bool {
}
}
-/// Retrieves the "code" part of an [invite][`RichInvite`] out of a URL.
+/// Retrieves the "code" part of an invite out of a URL.
///
/// # Examples
///
-/// Three formats of codes are supported:
+/// Three formats of [invite][`RichInvite`] codes are supported:
///
/// 1. Retrieving the code from the URL `"https://discord.gg/0cDvIgU2voY8RSYL"`:
///
@@ -123,7 +123,34 @@ pub fn parse_invite(code: &str) -> &str {
}
}
-/// Retreives Id from a username mention.
+/// Retreives an Id from a user mention.
+///
+/// If the mention is invalid, then `None` is returned.
+///
+/// # Examples
+///
+/// Retrieving an Id from a valid [`User`] mention:
+///
+/// ```rust
+/// use serenity::utils::parse_username;
+///
+/// // regular username mention
+/// assert_eq!(parse_username("<@114941315417899012>"), Some(114941315417899012));
+///
+/// // nickname mention
+/// assert_eq!(parse_username("<@!114941315417899012>"), Some(114941315417899012));
+/// ```
+///
+/// Asserting that an invalid username or nickname mention returns `None`:
+///
+/// ```rust
+/// use serenity::utils::parse_username;
+///
+/// assert!(parse_username("<@1149413154aa17899012").is_none());
+/// assert!(parse_username("<@!11494131541789a90b1c2").is_none());
+/// ```
+///
+/// [`User`]: ../model/struct.User.html
pub fn parse_username(mention: &str) -> Option<u64> {
if mention.len() < 4 {
return None;
@@ -140,13 +167,35 @@ pub fn parse_username(mention: &str) -> Option<u64> {
}
}
-/// Retreives Id from a role mention.
+/// Retreives an Id from a role mention.
+///
+/// If the mention is invalid, then `None` is returned.
+///
+/// # Examples
+///
+/// Retrieving an Id from a valid [`Role`] mention:
+///
+/// ```rust
+/// use serenity::utils::parse_role;
+///
+/// assert_eq!(parse_role("<@&136107769680887808>"), Some(136107769680887808));
+/// ```
+///
+/// Asserting that an invalid role mention returns `None`:
+///
+/// ```rust
+/// use serenity::utils::parse_role;
+///
+/// assert!(parse_role("<@&136107769680887808").is_none());
+/// ```
+///
+/// [`Role`]: ../model/struct.Role.html
pub fn parse_role(mention: &str) -> Option<u64> {
if mention.len() < 4 {
return None;
}
- if mention.starts_with("<@&") {
+ if mention.starts_with("<@&") && mention.ends_with('>') {
let len = mention.len() - 1;
mention[3..len].parse::<u64>().ok()
} else {
@@ -154,13 +203,36 @@ pub fn parse_role(mention: &str) -> Option<u64> {
}
}
-/// Retreives Id from a channel mention.
+/// Retreives an Id from a channel mention.
+///
+/// If the channel mention is invalid, then `None` is returned.
+///
+/// # Examples
+///
+/// Retrieving an Id from a valid [`Channel`] mention:
+///
+/// ```rust
+/// use serenity::utils::parse_channel;
+///
+/// assert_eq!(parse_channel("<#81384788765712384>"), Some(81384788765712384));
+/// ```
+///
+/// Asserting that an invalid channel mention returns `None`:
+///
+/// ```rust
+/// use serenity::utils::parse_channel;
+///
+/// assert!(parse_channel("<#!81384788765712384>").is_none());
+/// assert!(parse_channel("<#81384788765712384").is_none());
+/// ```
+///
+/// [`Channel`]: ../model/enum.Channel.html
pub fn parse_channel(mention: &str) -> Option<u64> {
if mention.len() < 4 {
return None;
}
- if mention.starts_with("<#") {
+ if mention.starts_with("<#") && mention.ends_with('>') {
let len = mention.len() - 1;
mention[2..len].parse::<u64>().ok()
} else {
@@ -168,19 +240,51 @@ pub fn parse_channel(mention: &str) -> Option<u64> {
}
}
-/// Retreives name and Id from an emoji mention.
+/// Retreives the name and Id from an emoji mention, in the form of an
+/// `EmojiIdentifier`.
+///
+/// If the emoji usage is invalid, then `None` is returned.
+///
+/// # Examples
+///
+/// Ensure that a valid [`Emoji`] usage is correctly parsed:
+///
+/// ```rust
+/// use serenity::model::{EmojiId, EmojiIdentifier};
+/// use serenity::utils::parse_emoji;
+///
+/// let expected = EmojiIdentifier {
+/// id: EmojiId(302516740095606785),
+/// name: "smugAnimeFace".to_owned(),
+/// };
+///
+/// assert_eq!(parse_emoji("<:smugAnimeFace:302516740095606785>").unwrap(), expected);
+/// ```
+///
+/// Asserting that an invalid emoji usage returns `None`:
+///
+/// ```rust
+/// use serenity::utils::parse_emoji;
+///
+/// assert!(parse_emoji("<:smugAnimeFace:302516740095606785").is_none());
+/// ```
+///
+/// [`Emoji`]: ../model/struct.Emoji.html
pub fn parse_emoji(mention: &str) -> Option<EmojiIdentifier> {
let len = mention.len();
+
if len < 6 || len > 56 {
return None;
}
- if mention.starts_with("<:") {
+ if mention.starts_with("<:") && mention.ends_with('>') {
let mut name = String::default();
let mut id = String::default();
+
for (i, x) in mention[2..].chars().enumerate() {
if x == ':' {
let from = i + 3;
+
for y in mention[from..].chars() {
if y == '>' {
break;
@@ -188,11 +292,13 @@ pub fn parse_emoji(mention: &str) -> Option<EmojiIdentifier> {
id.push(y);
}
}
+
break;
} else {
name.push(x);
}
}
+
match id.parse::<u64>() {
Ok(x) => Some(EmojiIdentifier {
name: name,
@@ -216,8 +322,7 @@ pub fn parse_emoji(mention: &str) -> Option<EmojiIdentifier> {
/// ```rust,no_run
/// use serenity::utils;
///
-/// let image = utils::read_image("./cat.png")
-/// .expect("Failed to read image");
+/// let image = utils::read_image("./cat.png").expect("Failed to read image");
/// ```
///
/// [`EditProfile::avatar`]: ../builder/struct.EditProfile.html#method.avatar
@@ -240,6 +345,33 @@ pub fn read_image<P: AsRef<Path>>(path: P) -> Result<String> {
/// Turns a string into a vector of string arguments, splitting by spaces, but
/// parsing content within quotes as one individual argument.
+///
+/// # Examples
+///
+/// Parsing two quoted commands:
+///
+/// ```rust
+/// use serenity::utils::parse_quotes;
+///
+/// let command = r#""this is the first" "this is the second""#;
+/// let expected = vec![
+/// "this is the first".to_owned(),
+/// "this is the second".to_owned()
+/// ];
+///
+/// assert_eq!(parse_quotes(command), expected);
+/// ```
+///
+/// ```rust
+/// use serenity::utils::parse_quotes;
+///
+/// let command = r#""this is a quoted command that doesn't have an ending quotation"#;
+/// let expected = vec![
+/// "this is a quoted command that doesn't have an ending quotation".to_owned(),
+/// ];
+///
+/// assert_eq!(parse_quotes(command), expected);
+/// ```
pub fn parse_quotes(s: &str) -> Vec<String> {
let mut args = vec![];
let mut in_string = false;