diff options
| author | Zeyla Hellyer <[email protected]> | 2017-05-23 10:15:26 -0700 |
|---|---|---|
| committer | Zeyla Hellyer <[email protected]> | 2017-05-23 10:15:26 -0700 |
| commit | 8c0aeacadb93d3b56fb98beb882eaef1f79cd652 (patch) | |
| tree | 7c1d26addbf15537c6f69a6ac9623276002b155a /src/utils | |
| parent | Fix {Invite,RichInvite}::url tests (diff) | |
| download | serenity-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/utils')
| -rw-r--r-- | src/utils/colour.rs | 19 | ||||
| -rw-r--r-- | src/utils/message_builder.rs | 208 | ||||
| -rw-r--r-- | src/utils/mod.rs | 154 |
3 files changed, 353 insertions, 28 deletions
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; |