changed name of trait from TelegramCommandEnum to TelegramBotCommand and divided parse_command into parse_command and parse_command_with_prefix

This commit is contained in:
p0lunin 2020-01-19 15:48:02 +02:00
parent 4af7b9f1f0
commit 5f34d7ffc6
2 changed files with 79 additions and 26 deletions

View file

@ -1,53 +1,106 @@
pub use teloxide_macros::TelegramCommandEnum; pub use teloxide_macros::TelegramBotCommand;
/// Enum for telegram commands /// Enum for telegram commands
/// ///
/// Example: /// Example:
/// ``` /// ```
/// use teloxide::utils::TelegramCommandEnum; /// use teloxide::utils::TelegramBotCommand;
/// use teloxide::utils::parse_command_into_enum; /// use teloxide::utils::parse_command_into_enum;
/// #[derive(TelegramCommandEnum, PartialEq, Debug)] /// #[derive(TelegramBotCommand, PartialEq, Debug)]
/// enum TelegramCommand { /// enum TelegramAdminCommand {
/// Start, /// Ban,
/// Help, /// Kick,
/// } /// }
/// let (command, args) = parse_command_into_enum::<TelegramCommand>("/", "/start arg1 arg2").unwrap(); /// let (command, args) = parse_command_into_enum::<TelegramAdminCommand>("/ban 5 h").unwrap();
/// assert_eq!(command, TelegramCommand::Start); /// assert_eq!(command, TelegramAdminCommand::Ban);
/// assert_eq!(args, vec!["arg1", "arg2"]); /// assert_eq!(args, vec!["5", "h"]);
/// ``` /// ```
pub trait TelegramCommandEnum: Sized { pub trait TelegramBotCommand: Sized {
fn try_from(s: &str) -> Option<Self>; fn try_from(s: &str) -> Option<Self>;
} }
pub fn parse_command_into_enum<'a, T>( /// Function to parse message with command into enum. Command must started with `/`
///
/// Example:
/// ```
/// use teloxide::utils::TelegramBotCommand;
/// use teloxide::utils::parse_command_into_enum;
/// #[derive(TelegramBotCommand, PartialEq, Debug)]
/// enum TelegramAdminCommand {
/// Ban,
/// Kick,
/// }
/// let (command, args) = parse_command_into_enum::<TelegramAdminCommand>("/ban 5 h").unwrap();
/// assert_eq!(command, TelegramAdminCommand::Ban);
/// assert_eq!(args, vec!["5", "h"]);
/// ```
pub fn parse_command_into_enum<T>(
text: &str,
) -> Option<(T, Vec<&str>)>
where
T: TelegramBotCommand,
{
parse_command_into_enum_with_prefix("/", text)
}
/// Function to parse message with command with custom prefix into enum.
///
/// Example:
/// ```
/// use teloxide::utils::TelegramBotCommand;
/// use teloxide::utils::parse_command_into_enum_with_prefix;
/// #[derive(TelegramBotCommand, PartialEq, Debug)]
/// enum TelegramAdminCommand {
/// Ban,
/// Kick,
/// }
/// let (command, args) = parse_command_into_enum_with_prefix::<TelegramAdminCommand>("!", "!ban 5 h").unwrap();
/// assert_eq!(command, TelegramAdminCommand::Ban);
/// assert_eq!(args, vec!["5", "h"]);
/// ```
pub fn parse_command_into_enum_with_prefix<'a, T>(
prefix: &str, prefix: &str,
text: &'a str, text: &'a str,
) -> Option<(T, Vec<&'a str>)> ) -> Option<(T, Vec<&'a str>)>
where where
T: TelegramCommandEnum, T: TelegramBotCommand,
{ {
let (command, args) = parse_command(prefix,text)?; let (command, args) = parse_command_with_prefix(prefix, text)?;
return match T::try_from(command) { match T::try_from(command) {
Some(command) => Some((command, args)), Some(command) => Some((command, args)),
_ => None, _ => None,
}; }
} }
/// Function which parse string and return command with args /// Function which parse string and return command with args. It calls [`parse_command_with_prefix`] with default prefix `/`
/// ///
/// Example: /// Example:
/// ``` /// ```
/// use teloxide::utils::parse_command; /// use teloxide::utils::parse_command;
/// let text = "/ban 5 hours"; /// let text = "/ban 5 hours";
/// let (command, args) = parse_command("/", text).unwrap(); /// let (command, args) = parse_command(text).unwrap();
/// assert_eq!(command, "ban"); /// assert_eq!(command, "ban");
/// assert_eq!(args, vec!["5", "hours"]); /// assert_eq!(args, vec!["5", "hours"]);
/// ``` /// ```
pub fn parse_command<'a>(prefix: &str, text: &'a str) -> Option<(&'a str, Vec<&'a str>)> { pub fn parse_command(text: &str) -> Option<(&str, Vec<&str>)> {
parse_command_with_prefix("/", text)
}
/// Function which parse string and return command with args. Prefix - start symbols which denote start of command
///
/// Example:
/// ```
/// use teloxide::utils::parse_command_with_prefix;
/// let text = "!ban 5 hours";
/// let (command, args) = parse_command_with_prefix("!", text).unwrap();
/// assert_eq!(command, "ban");
/// assert_eq!(args, vec!["5", "hours"]);
/// ```
pub fn parse_command_with_prefix<'a>(prefix: &str, text: &'a str) -> Option<(&'a str, Vec<&'a str>)> {
if !text.starts_with(prefix) { if !text.starts_with(prefix) {
return None; return None;
} }
let mut words = text.split_whitespace(); let mut words = text.split_whitespace();
let command = &words.next()?[1..]; let command = &words.next()?[prefix.len()..];
Some((command, words.collect())) Some((command, words.collect()))
} }
@ -59,7 +112,7 @@ mod tests {
fn parse_command_with_args_() { fn parse_command_with_args_() {
let data = "/command arg1 arg2"; let data = "/command arg1 arg2";
let expected = Some(("command", vec!["arg1", "arg2"])); let expected = Some(("command", vec!["arg1", "arg2"]));
let actual = parse_command("/", data); let actual = parse_command(data);
assert_eq!(actual, expected) assert_eq!(actual, expected)
} }
@ -67,13 +120,13 @@ mod tests {
fn parse_command_with_args_without_args() { fn parse_command_with_args_without_args() {
let data = "/command"; let data = "/command";
let expected = Some(("command", vec![])); let expected = Some(("command", vec![]));
let actual = parse_command("/", data); let actual = parse_command(data);
assert_eq!(actual, expected) assert_eq!(actual, expected)
} }
#[test] #[test]
fn parse_command__with_args() { fn parse_command__with_args() {
#[derive(TelegramCommandEnum, Debug, PartialEq)] #[derive(TelegramBotCommand, Debug, PartialEq)]
enum DefaultCommands { enum DefaultCommands {
Start, Start,
Help, Help,
@ -81,7 +134,7 @@ mod tests {
let data = "/start arg1 arg2"; let data = "/start arg1 arg2";
let expected = Some((DefaultCommands::Start, vec!["arg1", "arg2"])); let expected = Some((DefaultCommands::Start, vec!["arg1", "arg2"]));
let actual = parse_command_into_enum::<DefaultCommands>("/", data); let actual = parse_command_into_enum::<DefaultCommands>(data);
assert_eq!(actual, expected) assert_eq!(actual, expected)
} }
} }

View file

@ -4,7 +4,7 @@ use proc_macro::TokenStream;
use quote::quote; use quote::quote;
use syn::{DeriveInput, parse_macro_input}; use syn::{DeriveInput, parse_macro_input};
#[proc_macro_derive(TelegramCommandEnum)] #[proc_macro_derive(TelegramBotCommand)]
pub fn derive_telegram_command_enum(tokens: TokenStream) -> TokenStream { pub fn derive_telegram_command_enum(tokens: TokenStream) -> TokenStream {
let input = parse_macro_input!(tokens as DeriveInput); let input = parse_macro_input!(tokens as DeriveInput);
@ -15,13 +15,13 @@ pub fn derive_telegram_command_enum(tokens: TokenStream) -> TokenStream {
variant.ident.to_string().to_lowercase() variant.ident.to_string().to_lowercase()
})) }))
} }
_ => panic!("TelegramCommandEnum allowed only for enums") _ => return TokenStream::from(quote! { compile_error!("TelegramBotCommand allowed only for enums") })
}; };
let ident = input.ident; let ident = input.ident;
let expanded = quote! { let expanded = quote! {
impl TelegramCommandEnum for #ident { impl TelegramBotCommand for #ident {
fn try_from(value: &str) -> Option<Self> { fn try_from(value: &str) -> Option<Self> {
match value { match value {
#( #(