Skip to content

Commit 201990e

Browse files
NorbytusXenira
andauthored
refactor(macro): trait rename for general and method names
* refactor(macro): Make rename as Trait && separate to common rename, method_rename * test(rename): add explicit tests for rename Refs: #420 * fix(macro): Fix rename some magic methods * test(macro): Add test for magic method call * refactor(macro): Change if condition * test(macro): Fix tests --------- Co-authored-by: Xenira <[email protected]>
1 parent 645ffb8 commit 201990e

File tree

5 files changed

+245
-93
lines changed

5 files changed

+245
-93
lines changed

crates/macros/src/impl_.rs

Lines changed: 3 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use syn::{Ident, ItemImpl, Lit};
88
use crate::constant::PhpConstAttribute;
99
use crate::function::{Args, CallType, Function, MethodReceiver};
1010
use crate::helpers::get_docs;
11-
use crate::parsing::{PhpRename, RenameRule, Visibility};
11+
use crate::parsing::{MethodRename, PhpRename, Rename, RenameRule, Visibility};
1212
use crate::prelude::*;
1313

1414
/// Method types.
@@ -184,7 +184,7 @@ impl<'a> ParsedImpl<'a> {
184184
match items {
185185
syn::ImplItem::Const(c) => {
186186
let attr = PhpConstAttribute::from_attributes(&c.attrs)?;
187-
let name = self.rename_constants.rename(c.ident.to_string());
187+
let name = c.ident.rename(&self.rename_constants);
188188
let name = attr.rename.rename(name);
189189
let docs = get_docs(&attr.attrs)?;
190190
c.attrs.retain(|attr| !attr.path().is_ident("php"));
@@ -197,7 +197,7 @@ impl<'a> ParsedImpl<'a> {
197197
}
198198
syn::ImplItem::Fn(method) => {
199199
let attr = PhpFunctionImplAttribute::from_attributes(&method.attrs)?;
200-
let name = self.rename_methods.rename(method.sig.ident.to_string());
200+
let name = method.sig.ident.rename_method(&self.rename_methods);
201201
let name = attr.rename.rename(name);
202202
let docs = get_docs(&attr.attrs)?;
203203
method.attrs.retain(|attr| !attr.path().is_ident("php"));
@@ -318,43 +318,3 @@ impl quote::ToTokens for FnBuilder {
318318
.to_tokens(tokens);
319319
}
320320
}
321-
322-
#[cfg(test)]
323-
mod tests {
324-
use super::RenameRule;
325-
326-
#[test]
327-
fn test_rename_magic() {
328-
for &(magic, expected) in &[
329-
("__construct", "__construct"),
330-
("__destruct", "__destruct"),
331-
("__call", "__call"),
332-
("__call_static", "__callStatic"),
333-
("__get", "__get"),
334-
("__set", "__set"),
335-
("__isset", "__isset"),
336-
("__unset", "__unset"),
337-
("__sleep", "__sleep"),
338-
("__wakeup", "__wakeup"),
339-
("__serialize", "__serialize"),
340-
("__unserialize", "__unserialize"),
341-
("__to_string", "__toString"),
342-
("__invoke", "__invoke"),
343-
("__set_state", "__set_state"),
344-
("__clone", "__clone"),
345-
("__debug_info", "__debugInfo"),
346-
] {
347-
assert_eq!(magic, RenameRule::None.rename(magic));
348-
assert_eq!(expected, RenameRule::Camel.rename(magic));
349-
assert_eq!(expected, RenameRule::Snake.rename(magic));
350-
}
351-
}
352-
353-
#[test]
354-
fn test_rename_php_methods() {
355-
let &(original, camel, snake) = &("get_name", "getName", "get_name");
356-
assert_eq!(original, RenameRule::None.rename(original));
357-
assert_eq!(camel, RenameRule::Camel.rename(original));
358-
assert_eq!(snake, RenameRule::Snake.rename(original));
359-
}
360-
}

crates/macros/src/parsing.rs

Lines changed: 109 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
use darling::FromMeta;
22

3+
const MAGIC_METHOD: [&str; 17] = [
4+
"__construct",
5+
"__destruct",
6+
"__call",
7+
"__call_static",
8+
"__get",
9+
"__set",
10+
"__isset",
11+
"__unset",
12+
"__sleep",
13+
"__wakeup",
14+
"__serialize",
15+
"__unserialize",
16+
"__to_string",
17+
"__invoke",
18+
"__set_state",
19+
"__clone",
20+
"__debug_info",
21+
];
22+
323
#[derive(Debug, FromMeta)]
424
pub enum Visibility {
525
#[darling(rename = "public")]
@@ -10,6 +30,14 @@ pub enum Visibility {
1030
Protected,
1131
}
1232

33+
pub trait Rename {
34+
fn rename(&self, rule: &RenameRule) -> String;
35+
}
36+
37+
pub trait MethodRename: Rename {
38+
fn rename_method(&self, rule: &RenameRule) -> String;
39+
}
40+
1341
#[derive(FromMeta, Debug, Default)]
1442
#[darling(default)]
1543
pub struct PhpRename {
@@ -24,7 +52,7 @@ impl PhpRename {
2452
let name = name.as_ref();
2553
self.rename
2654
.as_ref()
27-
.map_or_else(|| name.to_string(), |r| r.rename(name))
55+
.map_or_else(|| name.to_string(), |r| name.rename(r))
2856
},
2957
ToString::to_string,
3058
)
@@ -52,52 +80,66 @@ pub enum RenameRule {
5280
}
5381

5482
impl RenameRule {
55-
/// Change case of an identifier.
56-
///
57-
/// Magic methods are handled specially to make sure they're always cased
58-
/// correctly.
59-
pub fn rename(self, name: impl AsRef<str>) -> String {
60-
let name = name.as_ref();
61-
match self {
62-
RenameRule::None => name.to_string(),
63-
rule => match name {
64-
"__construct" => "__construct".to_string(),
65-
"__destruct" => "__destruct".to_string(),
66-
"__call" => "__call".to_string(),
67-
"__call_static" => "__callStatic".to_string(),
68-
"__get" => "__get".to_string(),
69-
"__set" => "__set".to_string(),
70-
"__isset" => "__isset".to_string(),
71-
"__unset" => "__unset".to_string(),
72-
"__sleep" => "__sleep".to_string(),
73-
"__wakeup" => "__wakeup".to_string(),
74-
"__serialize" => "__serialize".to_string(),
75-
"__unserialize" => "__unserialize".to_string(),
76-
"__to_string" => "__toString".to_string(),
77-
"__invoke" => "__invoke".to_string(),
78-
"__set_state" => "__set_state".to_string(),
79-
"__clone" => "__clone".to_string(),
80-
"__debug_info" => "__debugInfo".to_string(),
81-
field => match rule {
82-
Self::Camel => ident_case::RenameRule::CamelCase.apply_to_field(field),
83-
Self::Pascal => ident_case::RenameRule::PascalCase.apply_to_field(field),
84-
Self::Snake => ident_case::RenameRule::SnakeCase.apply_to_field(field),
85-
Self::ScreamingSnakeCase => {
86-
ident_case::RenameRule::ScreamingSnakeCase.apply_to_field(field)
83+
fn rename(&self, value: impl AsRef<str>) -> String {
84+
match *self {
85+
Self::None => value.as_ref().to_string(),
86+
Self::Camel => ident_case::RenameRule::CamelCase.apply_to_field(value.as_ref()),
87+
Self::Pascal => ident_case::RenameRule::PascalCase.apply_to_field(value.as_ref()),
88+
Self::Snake => ident_case::RenameRule::SnakeCase.apply_to_field(value.as_ref()),
89+
Self::ScreamingSnakeCase => {
90+
ident_case::RenameRule::ScreamingSnakeCase.apply_to_field(value.as_ref())
91+
}
92+
}
93+
}
94+
}
95+
96+
impl Rename for &str {
97+
fn rename(&self, rule: &RenameRule) -> String {
98+
rule.rename(self)
99+
}
100+
}
101+
102+
impl Rename for syn::Ident {
103+
fn rename(&self, rule: &RenameRule) -> String {
104+
let s = self.to_string();
105+
rule.rename(s)
106+
}
107+
}
108+
109+
impl MethodRename for syn::Ident {
110+
fn rename_method(&self, rule: &RenameRule) -> String {
111+
self.to_string().as_str().rename_method(rule)
112+
}
113+
}
114+
115+
impl MethodRename for &str {
116+
fn rename_method(&self, rule: &RenameRule) -> String {
117+
match rule {
118+
RenameRule::None => self.to_string(),
119+
_ => {
120+
if MAGIC_METHOD.contains(self) {
121+
match *self {
122+
"__to_string" => "__toString".to_string(),
123+
"__debug_info" => "__debugInfo".to_string(),
124+
"__call_static" => "__callStatic".to_string(),
125+
_ => self.to_string(),
87126
}
88-
Self::None => unreachable!(),
89-
},
90-
},
127+
} else {
128+
self.rename(rule)
129+
}
130+
}
91131
}
92132
}
93133
}
94134

95135
#[cfg(test)]
96136
mod tests {
97-
use super::{PhpRename, RenameRule};
137+
use crate::parsing::{MethodRename, Rename};
138+
139+
use super::{PhpRename, RenameRule, MAGIC_METHOD};
98140

99141
#[test]
100-
fn test_php_rename() {
142+
fn php_rename() {
101143
let rename = PhpRename {
102144
name: Some("test".to_string()),
103145
rename: None,
@@ -132,7 +174,7 @@ mod tests {
132174
}
133175

134176
#[test]
135-
fn test_rename_magic() {
177+
fn rename_magic_method() {
136178
for &(magic, expected) in &[
137179
("__construct", "__construct"),
138180
("__destruct", "__destruct"),
@@ -152,25 +194,42 @@ mod tests {
152194
("__clone", "__clone"),
153195
("__debug_info", "__debugInfo"),
154196
] {
155-
assert_eq!(magic, RenameRule::None.rename(magic));
156-
assert_eq!(expected, RenameRule::Camel.rename(magic));
157-
assert_eq!(expected, RenameRule::Pascal.rename(magic));
158-
assert_eq!(expected, RenameRule::Snake.rename(magic));
159-
assert_eq!(expected, RenameRule::ScreamingSnakeCase.rename(magic));
197+
assert_eq!(magic, magic.rename_method(&RenameRule::None));
198+
assert_eq!(expected, magic.rename_method(&RenameRule::Camel));
199+
assert_eq!(expected, magic.rename_method(&RenameRule::Pascal));
200+
assert_eq!(expected, magic.rename_method(&RenameRule::Snake));
201+
assert_eq!(
202+
expected,
203+
magic.rename_method(&RenameRule::ScreamingSnakeCase)
204+
);
160205
}
161206
}
162207

163208
#[test]
164-
fn test_rename_php_methods() {
209+
fn rename_method() {
210+
let &(original, camel, snake, pascal, screaming_snake) =
211+
&("get_name", "getName", "get_name", "GetName", "GET_NAME");
212+
assert_eq!(original, original.rename_method(&RenameRule::None));
213+
assert_eq!(camel, original.rename_method(&RenameRule::Camel));
214+
assert_eq!(pascal, original.rename_method(&RenameRule::Pascal));
215+
assert_eq!(snake, original.rename_method(&RenameRule::Snake));
216+
assert_eq!(
217+
screaming_snake,
218+
original.rename_method(&RenameRule::ScreamingSnakeCase)
219+
);
220+
}
221+
222+
#[test]
223+
fn rename() {
165224
let &(original, camel, snake, pascal, screaming_snake) =
166225
&("get_name", "getName", "get_name", "GetName", "GET_NAME");
167-
assert_eq!(original, RenameRule::None.rename(original));
168-
assert_eq!(camel, RenameRule::Camel.rename(original));
169-
assert_eq!(pascal, RenameRule::Pascal.rename(original));
170-
assert_eq!(snake, RenameRule::Snake.rename(original));
226+
assert_eq!(original, original.rename(&RenameRule::None));
227+
assert_eq!(camel, original.rename(&RenameRule::Camel));
228+
assert_eq!(pascal, original.rename(&RenameRule::Pascal));
229+
assert_eq!(snake, original.rename(&RenameRule::Snake));
171230
assert_eq!(
172231
screaming_snake,
173-
RenameRule::ScreamingSnakeCase.rename(original)
232+
original.rename(&RenameRule::ScreamingSnakeCase)
174233
);
175234
}
176235
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
$magicMethod = new MagicMethod();
4+
5+
// __set
6+
$magicMethod->count = 10;
7+
// __get
8+
assert(10 === $magicMethod->count);
9+
assert(null === $magicMethod->test);
10+
11+
//__isset
12+
assert(true === isset($magicMethod->count));
13+
assert(false === isset($magicMethod->noCount));
14+
15+
// __unset
16+
unset($magicMethod->count);
17+
assert(0 === $magicMethod->count);
18+
19+
// __toString
20+
assert("0" === $magicMethod->__toString());
21+
assert("0" === (string) $magicMethod);
22+
23+
// __invoke
24+
assert(34 === $magicMethod(34));
25+
26+
// __debugInfo
27+
$debug = print_r($magicMethod, true);
28+
$expectedDebug = "MagicMethod Object\n(\n [count] => 0\n)\n";
29+
assert($expectedDebug === $debug);
30+
31+
// __call
32+
assert("Hello" === $magicMethod->callMagicMethod(1, 2, 3));
33+
assert(null === $magicMethod->callUndefinedMagicMethod());
34+
35+
// __call_static
36+
assert("Hello from static call 6" === MagicMethod::callStaticSomeMagic(1, 2, 3));
37+
assert(null === MagicMethod::callUndefinedStaticSomeMagic());

tests/src/integration/magic_method.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#[test]
2+
fn magic_method() {
3+
assert!(crate::integration::run_php("magic_method.php"));
4+
}

0 commit comments

Comments
 (0)