mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-03 09:49:07 +01:00
Cleanup renaming
(this technically breaks `#[rename = "actual_name"]` but we wanted to split `rename` VS `rename_rule` anyway, so this is ok)
This commit is contained in:
parent
88449531a6
commit
ddacee966e
4 changed files with 131 additions and 101 deletions
|
@ -2,7 +2,7 @@ use crate::{
|
|||
attr::{Attr, BotCommandAttribute},
|
||||
command_enum::CommandEnum,
|
||||
fields_parse::ParserType,
|
||||
rename_rules::rename_by_rule,
|
||||
rename_rules::RenameRule,
|
||||
Result,
|
||||
};
|
||||
|
||||
|
@ -11,24 +11,22 @@ pub(crate) struct Command {
|
|||
pub description: Option<String>,
|
||||
pub parser: Option<ParserType>,
|
||||
pub name: String,
|
||||
pub renamed: bool,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn try_from(attrs: &[Attr], name: &str) -> Result<Self> {
|
||||
let attrs = parse_attrs(attrs)?;
|
||||
let mut new_name = name.to_string();
|
||||
let mut renamed = false;
|
||||
let CommandAttrs {
|
||||
prefix,
|
||||
description,
|
||||
rename_rule,
|
||||
parser,
|
||||
separator: _,
|
||||
} = attrs;
|
||||
|
||||
let prefix = attrs.prefix;
|
||||
let description = attrs.description;
|
||||
let rename = attrs.rename;
|
||||
let parser = attrs.parser;
|
||||
if let Some(rename_rule) = rename {
|
||||
new_name = rename_by_rule(name, &rename_rule);
|
||||
renamed = true;
|
||||
}
|
||||
Ok(Self { prefix, description, parser, name: new_name, renamed })
|
||||
let name = rename_rule.apply(name);
|
||||
|
||||
Ok(Self { prefix, description, parser, name })
|
||||
}
|
||||
|
||||
pub fn get_matched_value(&self, global_parameters: &CommandEnum) -> String {
|
||||
|
@ -39,11 +37,8 @@ impl Command {
|
|||
} else {
|
||||
"/"
|
||||
};
|
||||
if let Some(rule) = &global_parameters.rename_rule {
|
||||
String::from(prefix) + &rename_by_rule(&self.name, rule.as_str())
|
||||
} else {
|
||||
String::from(prefix) + &self.name
|
||||
}
|
||||
|
||||
String::from(prefix) + &global_parameters.rename_rule.apply(&self.name)
|
||||
}
|
||||
|
||||
pub fn get_matched_value2(
|
||||
|
@ -57,18 +52,15 @@ impl Command {
|
|||
} else {
|
||||
"/"
|
||||
};
|
||||
if let Some(rule) = &global_parameters.rename_rule {
|
||||
(String::from(prefix), rename_by_rule(&self.name, rule.as_str()))
|
||||
} else {
|
||||
(String::from(prefix), self.name.clone())
|
||||
}
|
||||
|
||||
(String::from(prefix), global_parameters.rename_rule.apply(&self.name))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CommandAttrs {
|
||||
pub prefix: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub rename: Option<String>,
|
||||
pub rename_rule: RenameRule,
|
||||
pub parser: Option<ParserType>,
|
||||
pub separator: Option<String>,
|
||||
}
|
||||
|
@ -76,7 +68,7 @@ pub(crate) struct CommandAttrs {
|
|||
pub(crate) fn parse_attrs(attrs: &[Attr]) -> Result<CommandAttrs> {
|
||||
let mut prefix = None;
|
||||
let mut description = None;
|
||||
let mut rename_rule = None;
|
||||
let mut rename_rule = RenameRule::Identity;
|
||||
let mut parser = None;
|
||||
let mut separator = None;
|
||||
|
||||
|
@ -86,7 +78,9 @@ pub(crate) fn parse_attrs(attrs: &[Attr]) -> Result<CommandAttrs> {
|
|||
BotCommandAttribute::Description => {
|
||||
description = Some(attr.value())
|
||||
}
|
||||
BotCommandAttribute::RenameRule => rename_rule = Some(attr.value()),
|
||||
BotCommandAttribute::RenameRule => {
|
||||
rename_rule = RenameRule::parse(&attr.value())?
|
||||
}
|
||||
BotCommandAttribute::CustomParser => {
|
||||
parser = Some(ParserType::parse(&attr.value()))
|
||||
}
|
||||
|
@ -94,11 +88,5 @@ pub(crate) fn parse_attrs(attrs: &[Attr]) -> Result<CommandAttrs> {
|
|||
}
|
||||
}
|
||||
|
||||
Ok(CommandAttrs {
|
||||
prefix,
|
||||
description,
|
||||
rename: rename_rule,
|
||||
parser,
|
||||
separator,
|
||||
})
|
||||
Ok(CommandAttrs { prefix, description, rename_rule, parser, separator })
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use crate::{
|
||||
attr::Attr, command::parse_attrs, error::compile_error,
|
||||
fields_parse::ParserType, Result,
|
||||
attr::Attr, command::parse_attrs, fields_parse::ParserType,
|
||||
rename_rules::RenameRule, Result,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CommandEnum {
|
||||
pub prefix: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub rename_rule: Option<String>,
|
||||
pub rename_rule: RenameRule,
|
||||
pub parser_type: ParserType,
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ impl CommandEnum {
|
|||
|
||||
let prefix = attrs.prefix;
|
||||
let description = attrs.description;
|
||||
let rename = attrs.rename;
|
||||
let rename = attrs.rename_rule;
|
||||
let separator = attrs.separator;
|
||||
let mut parser = attrs.parser.unwrap_or(ParserType::Default);
|
||||
if let (ParserType::Split { separator }, Some(s)) =
|
||||
|
@ -25,19 +25,6 @@ impl CommandEnum {
|
|||
{
|
||||
*separator = Some(s.clone())
|
||||
}
|
||||
if let Some(rename_rule) = &rename {
|
||||
match rename_rule.as_str() {
|
||||
"lowercase"
|
||||
| "UPPERCASE"
|
||||
| "PascalCase"
|
||||
| "camelCase"
|
||||
| "snake_case"
|
||||
| "SCREAMING_SNAKE_CASE"
|
||||
| "kebab-case"
|
||||
| "SCREAMING-KEBAB-CASE" => {}
|
||||
_ => return Err(compile_error("disallowed value")),
|
||||
}
|
||||
}
|
||||
Ok(Self {
|
||||
prefix,
|
||||
description,
|
||||
|
|
|
@ -3,6 +3,7 @@ use quote::{quote, ToTokens};
|
|||
|
||||
pub(crate) type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Error(TokenStream);
|
||||
|
||||
pub(crate) fn compile_error<T>(data: T) -> Error
|
||||
|
|
|
@ -5,23 +5,75 @@ use heck::{
|
|||
ToShoutySnakeCase, ToSnakeCase,
|
||||
};
|
||||
|
||||
/// Apply a renaming rule to an enum variant,
|
||||
/// returning the version expected in the source.
|
||||
///
|
||||
/// The possible `rule` can be: `lowercase`, `UPPERCASE`, `PascalCase`,
|
||||
/// `camelCase`, `snake_case`, `SCREAMING_SNAKE_CASE`, `kebab-case`,
|
||||
/// `SCREAMING-KEBAB-CASE`. See tests for the details how it will work.
|
||||
pub(crate) fn rename_by_rule(input: &str, rule: &str) -> String {
|
||||
match rule {
|
||||
"lowercase" => input.to_lowercase(),
|
||||
"UPPERCASE" => input.to_uppercase(),
|
||||
"PascalCase" => input.to_pascal_case(),
|
||||
"camelCase" => input.to_lower_camel_case(),
|
||||
"snake_case" => input.to_snake_case(),
|
||||
"SCREAMING_SNAKE_CASE" => input.to_shouty_snake_case(),
|
||||
"kebab-case" => input.to_kebab_case(),
|
||||
"SCREAMING-KEBAB-CASE" => input.to_shouty_kebab_case(),
|
||||
_ => rule.to_string(),
|
||||
use crate::error::{compile_error, Result};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) enum RenameRule {
|
||||
/// -> `lowercase`
|
||||
LowerCase,
|
||||
/// -> `UPPERCASE`
|
||||
UpperCase,
|
||||
/// -> `PascalCase`
|
||||
PascalCase,
|
||||
/// -> `camelCase`
|
||||
CamelCase,
|
||||
/// -> `snake_case`
|
||||
SnakeCase,
|
||||
/// -> `SCREAMING_SNAKE_CASE`
|
||||
ScreamingSnakeCase,
|
||||
/// -> `kebab-case`
|
||||
KebabCase,
|
||||
/// -> `SCREAMING-KEBAB-CASE`
|
||||
ScreamingKebabCase,
|
||||
/// Leaves input as-is
|
||||
Identity,
|
||||
}
|
||||
|
||||
impl RenameRule {
|
||||
/// Apply a renaming rule to a string, returning the version expected in the
|
||||
/// source.
|
||||
///
|
||||
/// See tests for the details how it will work.
|
||||
pub fn apply(self, input: &str) -> String {
|
||||
use RenameRule::*;
|
||||
|
||||
match self {
|
||||
LowerCase => input.to_lowercase(),
|
||||
UpperCase => input.to_uppercase(),
|
||||
PascalCase => input.to_pascal_case(),
|
||||
CamelCase => input.to_lower_camel_case(),
|
||||
SnakeCase => input.to_snake_case(),
|
||||
ScreamingSnakeCase => input.to_shouty_snake_case(),
|
||||
KebabCase => input.to_kebab_case(),
|
||||
ScreamingKebabCase => input.to_shouty_kebab_case(),
|
||||
Identity => input.to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(rule: &str) -> Result<Self> {
|
||||
use RenameRule::*;
|
||||
|
||||
let rule = match rule {
|
||||
"lowercase" => LowerCase,
|
||||
"UPPERCASE" => UpperCase,
|
||||
"PascalCase" => PascalCase,
|
||||
"camelCase" => CamelCase,
|
||||
"snake_case" => SnakeCase,
|
||||
"SCREAMING_SNAKE_CASE" => ScreamingSnakeCase,
|
||||
"kebab-case" => KebabCase,
|
||||
"SCREAMING-KEBAB-CASE" => ScreamingKebabCase,
|
||||
"identity" => Identity,
|
||||
invalid => {
|
||||
return Err(compile_error(format!(
|
||||
"invalid rename rule `{invalid}` (supported rules: \
|
||||
`lowercase`, `UPPERCASE`, `PascalCase`, `camelCase`, \
|
||||
`snake_case`, `SCREAMING_SNAKE_CASE`, `kebab-case`, \
|
||||
`SCREAMING-KEBAB-CASE` and `identity`)"
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(rule)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,8 +82,10 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
macro_rules! test_eq {
|
||||
($lval:expr, $rval:expr) => {
|
||||
assert_eq!(rename_by_rule($lval, TYPE), $rval);
|
||||
($lval:expr => $rval:expr) => {
|
||||
let rule = RenameRule::parse(TYPE).unwrap();
|
||||
|
||||
assert_eq!(rule.apply($lval), $rval);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -39,79 +93,79 @@ mod tests {
|
|||
fn test_lowercase() {
|
||||
const TYPE: &str = "lowercase";
|
||||
|
||||
test_eq!("HelloWorld", "helloworld");
|
||||
test_eq!("Hello_World", "hello_world");
|
||||
test_eq!("Hello-World", "hello-world");
|
||||
test_eq!("helloWorld", "helloworld");
|
||||
test_eq!("HelloWorld" => "helloworld");
|
||||
test_eq!("Hello_World" => "hello_world");
|
||||
test_eq!("Hello-World" => "hello-world");
|
||||
test_eq!("helloWorld" => "helloworld");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uppercase() {
|
||||
const TYPE: &str = "UPPERCASE";
|
||||
|
||||
test_eq!("HelloWorld", "HELLOWORLD");
|
||||
test_eq!("Hello_World", "HELLO_WORLD");
|
||||
test_eq!("Hello-World", "HELLO-WORLD");
|
||||
test_eq!("helloWorld", "HELLOWORLD");
|
||||
test_eq!("HelloWorld" => "HELLOWORLD");
|
||||
test_eq!("Hello_World" => "HELLO_WORLD");
|
||||
test_eq!("Hello-World" => "HELLO-WORLD");
|
||||
test_eq!("helloWorld" => "HELLOWORLD");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pascalcase() {
|
||||
const TYPE: &str = "PascalCase";
|
||||
|
||||
test_eq!("HelloWorld", "HelloWorld");
|
||||
test_eq!("Hello_World", "HelloWorld");
|
||||
test_eq!("Hello-World", "HelloWorld");
|
||||
test_eq!("helloWorld", "HelloWorld");
|
||||
test_eq!("HelloWorld" => "HelloWorld");
|
||||
test_eq!("Hello_World" => "HelloWorld");
|
||||
test_eq!("Hello-World" => "HelloWorld");
|
||||
test_eq!("helloWorld" => "HelloWorld");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_camelcase() {
|
||||
const TYPE: &str = "camelCase";
|
||||
|
||||
test_eq!("HelloWorld", "helloWorld");
|
||||
test_eq!("Hello_World", "helloWorld");
|
||||
test_eq!("Hello-World", "helloWorld");
|
||||
test_eq!("helloWorld", "helloWorld");
|
||||
test_eq!("HelloWorld" => "helloWorld");
|
||||
test_eq!("Hello_World" => "helloWorld");
|
||||
test_eq!("Hello-World" => "helloWorld");
|
||||
test_eq!("helloWorld" => "helloWorld");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_snakecase() {
|
||||
const TYPE: &str = "snake_case";
|
||||
|
||||
test_eq!("HelloWorld", "hello_world");
|
||||
test_eq!("Hello_World", "hello_world");
|
||||
test_eq!("Hello-World", "hello_world");
|
||||
test_eq!("helloWorld", "hello_world");
|
||||
test_eq!("HelloWorld" => "hello_world");
|
||||
test_eq!("Hello_World" => "hello_world");
|
||||
test_eq!("Hello-World" => "hello_world");
|
||||
test_eq!("helloWorld" => "hello_world");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_screaming_snakecase() {
|
||||
const TYPE: &str = "SCREAMING_SNAKE_CASE";
|
||||
|
||||
test_eq!("HelloWorld", "HELLO_WORLD");
|
||||
test_eq!("Hello_World", "HELLO_WORLD");
|
||||
test_eq!("Hello-World", "HELLO_WORLD");
|
||||
test_eq!("helloWorld", "HELLO_WORLD");
|
||||
test_eq!("HelloWorld" => "HELLO_WORLD");
|
||||
test_eq!("Hello_World" => "HELLO_WORLD");
|
||||
test_eq!("Hello-World" => "HELLO_WORLD");
|
||||
test_eq!("helloWorld" => "HELLO_WORLD");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kebabcase() {
|
||||
const TYPE: &str = "kebab-case";
|
||||
|
||||
test_eq!("HelloWorld", "hello-world");
|
||||
test_eq!("Hello_World", "hello-world");
|
||||
test_eq!("Hello-World", "hello-world");
|
||||
test_eq!("helloWorld", "hello-world");
|
||||
test_eq!("HelloWorld" => "hello-world");
|
||||
test_eq!("Hello_World" => "hello-world");
|
||||
test_eq!("Hello-World" => "hello-world");
|
||||
test_eq!("helloWorld" => "hello-world");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_screaming_kebabcase() {
|
||||
const TYPE: &str = "SCREAMING-KEBAB-CASE";
|
||||
|
||||
test_eq!("HelloWorld", "HELLO-WORLD");
|
||||
test_eq!("Hello_World", "HELLO-WORLD");
|
||||
test_eq!("Hello-World", "HELLO-WORLD");
|
||||
test_eq!("helloWorld", "HELLO-WORLD");
|
||||
test_eq!("HelloWorld" => "HELLO-WORLD");
|
||||
test_eq!("Hello_World" => "HELLO-WORLD");
|
||||
test_eq!("Hello-World" => "HELLO-WORLD");
|
||||
test_eq!("helloWorld" => "HELLO-WORLD");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue