Rename BotCommand -> BotCommands (the trait)

This removes the ambiguity with `types::BotCommand` and also the new
name just makes more sense, since this trait is usually implemented for
enums that can be many different commands and not a single one.

Note: this requires changes in the `teloxide-macro` crate.
This commit is contained in:
Maybe Waffle 2022-03-13 19:37:11 +04:00
parent 8116059ba3
commit b3b8073a12
12 changed files with 44 additions and 42 deletions

View file

@ -59,7 +59,8 @@ full = [
[dependencies] [dependencies]
teloxide-core = { version = "0.4", default-features = false } teloxide-core = { version = "0.4", default-features = false }
teloxide-macros = { version = "0.5.1", optional = true } #teloxide-macros = { version = "0.5.1", optional = true }
teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", rev = "7e000b9", optional = true }
serde_json = "1.0" serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }

View file

@ -1,7 +1,7 @@
use std::{error::Error, str::FromStr}; use std::{error::Error, str::FromStr};
use chrono::Duration; use chrono::Duration;
use teloxide::{prelude2::*, types::ChatPermissions, utils::command::BotCommand}; use teloxide::{prelude2::*, types::ChatPermissions, utils::command::BotCommands};
// Derive BotCommand to parse text with a command into this enumeration. // Derive BotCommand to parse text with a command into this enumeration.
// //
@ -12,7 +12,7 @@ use teloxide::{prelude2::*, types::ChatPermissions, utils::command::BotCommand};
// your commands in this format: // your commands in this format:
// %GENERAL-DESCRIPTION% // %GENERAL-DESCRIPTION%
// %PREFIX%%COMMAND% - %DESCRIPTION% // %PREFIX%%COMMAND% - %DESCRIPTION%
#[derive(BotCommand, Clone)] #[derive(BotCommands, Clone)]
#[command( #[command(
rename = "lowercase", rename = "lowercase",
description = "Use commands in format /%command% %num% %unit%", description = "Use commands in format /%command% %num% %unit%",

View file

@ -6,10 +6,10 @@ use teloxide::{
InlineKeyboardButton, InlineKeyboardMarkup, InlineQueryResultArticle, InputMessageContent, InlineKeyboardButton, InlineKeyboardMarkup, InlineQueryResultArticle, InputMessageContent,
InputMessageContentText, InputMessageContentText,
}, },
utils::command::BotCommand, utils::command::BotCommands,
}; };
#[derive(BotCommand)] #[derive(BotCommands)]
#[command(rename = "lowercase", description = "These commands are supported:")] #[command(rename = "lowercase", description = "These commands are supported:")]
enum Command { enum Command {
#[command(description = "Display this text")] #[command(description = "Display this text")]
@ -47,7 +47,7 @@ async fn message_handler(
bot: AutoSend<Bot>, bot: AutoSend<Bot>,
) -> Result<(), Box<dyn Error + Send + Sync>> { ) -> Result<(), Box<dyn Error + Send + Sync>> {
if let Some(text) = m.text() { if let Some(text) = m.text() {
match BotCommand::parse(text, "buttons") { match BotCommands::parse(text, "buttons") {
Ok(Command::Help) => { Ok(Command::Help) => {
// Just send the description of all commands. // Just send the description of all commands.
bot.send_message(m.chat.id, Command::descriptions()).await?; bot.send_message(m.chat.id, Command::descriptions()).await?;

View file

@ -9,7 +9,7 @@ use teloxide::{
macros::DialogueState, macros::DialogueState,
prelude2::*, prelude2::*,
types::Me, types::Me,
utils::command::BotCommand, utils::command::BotCommands,
}; };
type MyDialogue = Dialogue<State, ErasedStorage<State>>; type MyDialogue = Dialogue<State, ErasedStorage<State>>;
@ -32,7 +32,7 @@ impl Default for State {
} }
} }
#[derive(BotCommand)] #[derive(BotCommands)]
#[command(rename = "lowercase", description = "These commands are supported:")] #[command(rename = "lowercase", description = "These commands are supported:")]
pub enum Command { pub enum Command {
#[command(description = "get your number.")] #[command(description = "get your number.")]

View file

@ -8,7 +8,7 @@ use rand::Rng;
use teloxide::{ use teloxide::{
prelude2::*, prelude2::*,
types::{Dice, Update}, types::{Dice, Update},
utils::command::BotCommand, utils::command::BotCommands,
}; };
#[tokio::main] #[tokio::main]
@ -101,7 +101,7 @@ struct ConfigParameters {
maintainer_username: Option<String>, maintainer_username: Option<String>,
} }
#[derive(BotCommand, Clone)] #[derive(BotCommands, Clone)]
#[command(rename = "lowercase", description = "Simple commands")] #[command(rename = "lowercase", description = "Simple commands")]
enum SimpleCommand { enum SimpleCommand {
#[command(description = "shows this message.")] #[command(description = "shows this message.")]
@ -112,7 +112,7 @@ enum SimpleCommand {
MyId, MyId,
} }
#[derive(BotCommand, Clone)] #[derive(BotCommands, Clone)]
#[command(rename = "lowercase", description = "Maintainer commands")] #[command(rename = "lowercase", description = "Maintainer commands")]
enum MaintainerCommands { enum MaintainerCommands {
#[command(parse_with = "split", description = "generate a number within range")] #[command(parse_with = "split", description = "generate a number within range")]

View file

@ -1,8 +1,8 @@
use teloxide::{prelude2::*, utils::command::BotCommand}; use teloxide::{prelude2::*, utils::command::BotCommands};
use std::error::Error; use std::error::Error;
#[derive(BotCommand, Clone)] #[derive(BotCommands, Clone)]
#[command(rename = "lowercase", description = "These commands are supported:")] #[command(rename = "lowercase", description = "These commands are supported:")]
enum Command { enum Command {
#[command(description = "display this text.")] #[command(description = "display this text.")]

View file

@ -1,4 +1,4 @@
use crate::{dispatching::UpdateWithCx, utils::command::BotCommand}; use crate::{dispatching::UpdateWithCx, utils::command::BotCommands};
use futures::{stream::BoxStream, Stream, StreamExt}; use futures::{stream::BoxStream, Stream, StreamExt};
use teloxide_core::types::Message; use teloxide_core::types::Message;
@ -21,7 +21,7 @@ pub trait DispatcherHandlerRxExt<R> {
fn commands<C, N>(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx<R, Message>, C)> fn commands<C, N>(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx<R, Message>, C)>
where where
Self: Stream<Item = UpdateWithCx<R, Message>>, Self: Stream<Item = UpdateWithCx<R, Message>>,
C: BotCommand, C: BotCommands,
N: Into<String> + Send, N: Into<String> + Send,
R: Send + 'static; R: Send + 'static;
} }
@ -45,7 +45,7 @@ where
fn commands<C, N>(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx<R, Message>, C)> fn commands<C, N>(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx<R, Message>, C)>
where where
Self: Stream<Item = UpdateWithCx<R, Message>>, Self: Stream<Item = UpdateWithCx<R, Message>>,
C: BotCommand, C: BotCommands,
N: Into<String> + Send, N: Into<String> + Send,
R: Send + 'static, R: Send + 'static,
{ {

View file

@ -4,7 +4,7 @@ use crate::{
DispatcherHandlerRxExt, UpdateWithCx, DispatcherHandlerRxExt, UpdateWithCx,
}, },
error_handlers::{LoggingErrorHandler, OnError}, error_handlers::{LoggingErrorHandler, OnError},
utils::command::BotCommand, utils::command::BotCommands,
}; };
use futures::StreamExt; use futures::StreamExt;
use std::{fmt::Debug, future::Future, sync::Arc}; use std::{fmt::Debug, future::Future, sync::Arc};
@ -25,7 +25,7 @@ use tokio_stream::wrappers::UnboundedReceiverStream;
#[cfg(feature = "ctrlc_handler")] #[cfg(feature = "ctrlc_handler")]
pub async fn commands_repl<R, Cmd, H, Fut, HandlerE, N>(requester: R, bot_name: N, handler: H) pub async fn commands_repl<R, Cmd, H, Fut, HandlerE, N>(requester: R, bot_name: N, handler: H)
where where
Cmd: BotCommand + Send + 'static, Cmd: BotCommands + Send + 'static,
H: Fn(UpdateWithCx<R, Message>, Cmd) -> Fut + Send + Sync + 'static, H: Fn(UpdateWithCx<R, Message>, Cmd) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<(), HandlerE>> + Send + 'static, Fut: Future<Output = Result<(), HandlerE>> + Send + 'static,
Result<(), HandlerE>: OnError<HandlerE>, Result<(), HandlerE>: OnError<HandlerE>,
@ -64,7 +64,7 @@ pub async fn commands_repl_with_listener<'a, R, Cmd, H, Fut, L, ListenerE, Handl
handler: H, handler: H,
listener: L, listener: L,
) where ) where
Cmd: BotCommand + Send + 'static, Cmd: BotCommands + Send + 'static,
H: Fn(UpdateWithCx<R, Message>, Cmd) -> Fut + Send + Sync + 'static, H: Fn(UpdateWithCx<R, Message>, Cmd) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<(), HandlerE>> + Send + 'static, Fut: Future<Output = Result<(), HandlerE>> + Send + 'static,
L: UpdateListener<ListenerE> + Send + 'a, L: UpdateListener<ListenerE> + Send + 'a,

View file

@ -6,7 +6,7 @@ use crate::{
HandlerFactory, HandlerFactory,
}, },
types::{Me, Message}, types::{Me, Message},
utils::command::BotCommand, utils::command::BotCommands,
}; };
use dptree::{di::DependencyMap, Handler}; use dptree::{di::DependencyMap, Handler};
@ -23,7 +23,7 @@ pub trait HandlerExt<Output> {
#[must_use] #[must_use]
fn filter_command<C>(self) -> Self fn filter_command<C>(self) -> Self
where where
C: BotCommand + Send + Sync + 'static; C: BotCommands + Send + Sync + 'static;
/// Passes [`Dialogue<D, S>`] and `D` as handler dependencies. /// Passes [`Dialogue<D, S>`] and `D` as handler dependencies.
/// ///
@ -62,7 +62,7 @@ where
{ {
fn filter_command<C>(self) -> Self fn filter_command<C>(self) -> Self
where where
C: BotCommand + Send + Sync + 'static, C: BotCommands + Send + Sync + 'static,
{ {
self.chain(dptree::filter_map(move |message: Message, me: Me| { self.chain(dptree::filter_map(move |message: Message, me: Me| {
let bot_name = me.user.username.expect("Bots must have a username"); let bot_name = me.user.username.expect("Bots must have a username");

View file

@ -3,7 +3,7 @@ use crate::{
dispatching2::{HandlerExt, UpdateFilterExt}, dispatching2::{HandlerExt, UpdateFilterExt},
error_handlers::LoggingErrorHandler, error_handlers::LoggingErrorHandler,
types::Update, types::Update,
utils::command::BotCommand, utils::command::BotCommands,
}; };
use dptree::di::{DependencyMap, Injectable}; use dptree::di::{DependencyMap, Injectable};
use std::{fmt::Debug, marker::PhantomData}; use std::{fmt::Debug, marker::PhantomData};
@ -27,7 +27,7 @@ use teloxide_core::requests::Requester;
#[cfg(feature = "ctrlc_handler")] #[cfg(feature = "ctrlc_handler")]
pub async fn commands_repl<'a, R, Cmd, H, E, Args>(bot: R, handler: H, cmd: PhantomData<Cmd>) pub async fn commands_repl<'a, R, Cmd, H, E, Args>(bot: R, handler: H, cmd: PhantomData<Cmd>)
where where
Cmd: BotCommand + Send + Sync + 'static, Cmd: BotCommands + Send + Sync + 'static,
H: Injectable<DependencyMap, Result<(), E>, Args> + Send + Sync + 'static, H: Injectable<DependencyMap, Result<(), E>, Args> + Send + Sync + 'static,
R: Requester + Clone + Send + Sync + 'static, R: Requester + Clone + Send + Sync + 'static,
<R as Requester>::GetUpdates: Send, <R as Requester>::GetUpdates: Send,
@ -67,7 +67,7 @@ pub async fn commands_repl_with_listener<'a, R, Cmd, H, L, ListenerE, E, Args>(
listener: L, listener: L,
_cmd: PhantomData<Cmd>, _cmd: PhantomData<Cmd>,
) where ) where
Cmd: BotCommand + Send + Sync + 'static, Cmd: BotCommands + Send + Sync + 'static,
H: Injectable<DependencyMap, Result<(), E>, Args> + Send + Sync + 'static, H: Injectable<DependencyMap, Result<(), E>, Args> + Send + Sync + 'static,
L: UpdateListener<ListenerE> + Send + 'a, L: UpdateListener<ListenerE> + Send + 'a,
ListenerE: Debug + Send + 'a, ListenerE: Debug + Send + 'a,

View file

@ -52,8 +52,9 @@ use std::{
}; };
use std::marker::PhantomData; use std::marker::PhantomData;
use teloxide_core::types::BotCommand;
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
pub use teloxide_macros::BotCommand; pub use teloxide_macros::BotCommands;
/// An enumeration of bot's commands. /// An enumeration of bot's commands.
/// ///
@ -205,7 +206,7 @@ pub use teloxide_macros::BotCommand;
/// ///
/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html /// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
/// [`BotCommand`]: crate::utils::command::BotCommand /// [`BotCommand`]: crate::utils::command::BotCommand
pub trait BotCommand: Sized { pub trait BotCommands: Sized {
/// Parses a command. /// Parses a command.
/// ///
/// `bot_username` is required to parse commands like /// `bot_username` is required to parse commands like
@ -218,12 +219,12 @@ pub trait BotCommand: Sized {
/// (for example when `/help` command is used). /// (for example when `/help` command is used).
fn descriptions() -> String; fn descriptions() -> String;
/// Returns a vector of [`types::BotCommand`] that can be used with /// Returns a vector of [`BotCommand`] that can be used with
/// [`set_my_commands`]. /// [`set_my_commands`].
/// ///
/// [`types::BotCommand`]: crate::types::BotCommand /// [`BotCommand`]: crate::types::BotCommand
/// [`set_my_commands`]: crate::requests::Requester::set_my_commands /// [`set_my_commands`]: crate::requests::Requester::set_my_commands
fn bot_commands() -> Vec<crate::types::BotCommand>; fn bot_commands() -> Vec<BotCommand>;
/// Returns `PhantomData<Self>` that is used as a param of [`commands_repl`] /// Returns `PhantomData<Self>` that is used as a param of [`commands_repl`]
/// ///

View file

@ -2,7 +2,7 @@
#![allow(clippy::nonstandard_macro_braces)] #![allow(clippy::nonstandard_macro_braces)]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
use teloxide::utils::command::{BotCommand, ParseError}; use teloxide::utils::command::{BotCommands, ParseError};
// We put tests here because macro expand in unit tests in module // We put tests here because macro expand in unit tests in module
// teloxide::utils::command was a failure // teloxide::utils::command was a failure
@ -10,7 +10,7 @@ use teloxide::utils::command::{BotCommand, ParseError};
#[test] #[test]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
fn parse_command_with_args() { fn parse_command_with_args() {
#[derive(BotCommand, Debug, PartialEq)] #[derive(BotCommands, Debug, PartialEq)]
#[command(rename = "lowercase")] #[command(rename = "lowercase")]
enum DefaultCommands { enum DefaultCommands {
Start(String), Start(String),
@ -26,7 +26,7 @@ fn parse_command_with_args() {
#[test] #[test]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
fn parse_command_with_non_string_arg() { fn parse_command_with_non_string_arg() {
#[derive(BotCommand, Debug, PartialEq)] #[derive(BotCommands, Debug, PartialEq)]
#[command(rename = "lowercase")] #[command(rename = "lowercase")]
enum DefaultCommands { enum DefaultCommands {
Start(i32), Start(i32),
@ -42,7 +42,7 @@ fn parse_command_with_non_string_arg() {
#[test] #[test]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
fn attribute_prefix() { fn attribute_prefix() {
#[derive(BotCommand, Debug, PartialEq)] #[derive(BotCommands, Debug, PartialEq)]
#[command(rename = "lowercase")] #[command(rename = "lowercase")]
enum DefaultCommands { enum DefaultCommands {
#[command(prefix = "!")] #[command(prefix = "!")]
@ -59,7 +59,7 @@ fn attribute_prefix() {
#[test] #[test]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
fn many_attributes() { fn many_attributes() {
#[derive(BotCommand, Debug, PartialEq)] #[derive(BotCommands, Debug, PartialEq)]
#[command(rename = "lowercase")] #[command(rename = "lowercase")]
enum DefaultCommands { enum DefaultCommands {
#[command(prefix = "!", description = "desc")] #[command(prefix = "!", description = "desc")]
@ -74,7 +74,7 @@ fn many_attributes() {
#[test] #[test]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
fn global_attributes() { fn global_attributes() {
#[derive(BotCommand, Debug, PartialEq)] #[derive(BotCommands, Debug, PartialEq)]
#[command(prefix = "!", rename = "lowercase", description = "Bot commands")] #[command(prefix = "!", rename = "lowercase", description = "Bot commands")]
enum DefaultCommands { enum DefaultCommands {
#[command(prefix = "/")] #[command(prefix = "/")]
@ -90,7 +90,7 @@ fn global_attributes() {
#[test] #[test]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
fn parse_command_with_bot_name() { fn parse_command_with_bot_name() {
#[derive(BotCommand, Debug, PartialEq)] #[derive(BotCommands, Debug, PartialEq)]
#[command(rename = "lowercase")] #[command(rename = "lowercase")]
enum DefaultCommands { enum DefaultCommands {
#[command(prefix = "/")] #[command(prefix = "/")]
@ -107,7 +107,7 @@ fn parse_command_with_bot_name() {
#[test] #[test]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
fn parse_with_split() { fn parse_with_split() {
#[derive(BotCommand, Debug, PartialEq)] #[derive(BotCommands, Debug, PartialEq)]
#[command(rename = "lowercase")] #[command(rename = "lowercase")]
#[command(parse_with = "split")] #[command(parse_with = "split")]
enum DefaultCommands { enum DefaultCommands {
@ -124,7 +124,7 @@ fn parse_with_split() {
#[test] #[test]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
fn parse_with_split2() { fn parse_with_split2() {
#[derive(BotCommand, Debug, PartialEq)] #[derive(BotCommands, Debug, PartialEq)]
#[command(rename = "lowercase")] #[command(rename = "lowercase")]
#[command(parse_with = "split", separator = "|")] #[command(parse_with = "split", separator = "|")]
enum DefaultCommands { enum DefaultCommands {
@ -152,7 +152,7 @@ fn parse_custom_parser() {
.map_err(|_| ParseError::Custom("First argument must be a integer!".to_owned().into())) .map_err(|_| ParseError::Custom("First argument must be a integer!".to_owned().into()))
} }
#[derive(BotCommand, Debug, PartialEq)] #[derive(BotCommands, Debug, PartialEq)]
#[command(rename = "lowercase")] #[command(rename = "lowercase")]
enum DefaultCommands { enum DefaultCommands {
#[command(parse_with = "custom_parse_function")] #[command(parse_with = "custom_parse_function")]
@ -169,7 +169,7 @@ fn parse_custom_parser() {
#[test] #[test]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
fn parse_named_fields() { fn parse_named_fields() {
#[derive(BotCommand, Debug, PartialEq)] #[derive(BotCommands, Debug, PartialEq)]
#[command(rename = "lowercase")] #[command(rename = "lowercase")]
#[command(parse_with = "split")] #[command(parse_with = "split")]
enum DefaultCommands { enum DefaultCommands {
@ -186,7 +186,7 @@ fn parse_named_fields() {
#[test] #[test]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
fn descriptions_off() { fn descriptions_off() {
#[derive(BotCommand, Debug, PartialEq)] #[derive(BotCommands, Debug, PartialEq)]
#[command(rename = "lowercase")] #[command(rename = "lowercase")]
enum DefaultCommands { enum DefaultCommands {
#[command(description = "off")] #[command(description = "off")]