aboutsummaryrefslogtreecommitdiff
path: root/src/utils
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/utils
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/utils')
-rw-r--r--src/utils/colour.rs19
-rw-r--r--src/utils/message_builder.rs208
-rw-r--r--src/utils/mod.rs154
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;