• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

davidcole1340 / ext-php-rs / 15425510964

03 Jun 2025 06:55PM CUT coverage: 20.885% (-0.04%) from 20.927%
15425510964

Pull #436

github

Xenira
chore(macro)!: change rename defaults to match psr

BREAKING CHANGE: Methods and Properties are renamed to camelCase by default. Classes to PascalCase and constants to UPPER_CASE.

Refs: #189
Pull Request #436: chore(macro)!: change rename defaults to match psr

16 of 35 new or added lines in 5 files covered. (45.71%)

2 existing lines in 2 files now uncovered.

821 of 3931 relevant lines covered (20.89%)

2.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.66
/crates/macros/src/parsing.rs
1
use convert_case::{Case, Casing};
2
use darling::FromMeta;
3

4
const MAGIC_METHOD: [&str; 17] = [
5
    "__construct",
6
    "__destruct",
7
    "__call",
8
    "__call_static",
9
    "__get",
10
    "__set",
11
    "__isset",
12
    "__unset",
13
    "__sleep",
14
    "__wakeup",
15
    "__serialize",
16
    "__unserialize",
17
    "__to_string",
18
    "__invoke",
19
    "__set_state",
20
    "__clone",
21
    "__debug_info",
22
];
23

24
#[derive(Debug, FromMeta)]
25
pub enum Visibility {
26
    #[darling(rename = "public")]
27
    Public,
28
    #[darling(rename = "private")]
29
    Private,
30
    #[darling(rename = "protected")]
31
    Protected,
32
}
33

34
pub trait Rename {
35
    fn rename(&self, rule: RenameRule) -> String;
36
}
37

38
pub trait MethodRename: Rename {
39
    fn rename_method(&self, rule: RenameRule) -> String;
40
}
41

42
#[derive(FromMeta, Debug, Default)]
43
#[darling(default)]
44
pub struct PhpRename {
45
    name: Option<String>,
46
    rename: Option<RenameRule>,
47
}
48

49
impl PhpRename {
50
    pub fn rename(&self, name: impl AsRef<str>, default: RenameRule) -> String {
12✔
51
        if let Some(name) = self.name.as_ref() {
18✔
NEW
52
            name.to_string()
×
53
        } else {
54
            name.as_ref().rename(self.rename.unwrap_or(default))
6✔
55
        }
56
    }
57

58
    pub fn rename_method(&self, name: impl AsRef<str>, default: RenameRule) -> String {
97✔
59
        if let Some(name) = self.name.as_ref() {
103✔
NEW
60
            name.to_string()
×
61
        } else {
62
            name.as_ref().rename_method(self.rename.unwrap_or(default))
91✔
63
        }
64
    }
65
}
66

67
#[derive(Debug, Copy, Clone, FromMeta, Default)]
68
pub enum RenameRule {
69
    /// Methods won't be renamed.
70
    #[darling(rename = "none")]
71
    None,
72
    /// Methods will be converted to `camelCase`.
73
    #[darling(rename = "camelCase")]
74
    #[default]
75
    Camel,
76
    /// Methods will be converted to `snake_case`.
77
    #[darling(rename = "snake_case")]
78
    Snake,
79
    /// Methods will be converted to `PascalCase`.
80
    #[darling(rename = "PascalCase")]
81
    Pascal,
82
    /// Renames to `UPPER_SNAKE_CASE`.
83
    #[darling(rename = "UPPER_CASE")]
84
    ScreamingSnake,
85
}
86

87
impl RenameRule {
88
    fn rename(self, value: impl AsRef<str>) -> String {
21✔
89
        match self {
21✔
90
            Self::None => value.as_ref().to_string(),
1✔
91
            Self::Camel => value.as_ref().to_case(Case::Camel),
2✔
92
            Self::Pascal => value.as_ref().to_case(Case::Pascal),
2✔
93
            Self::Snake => value.as_ref().to_case(Case::Snake),
8✔
94
            Self::ScreamingSnake => value.as_ref().to_case(Case::Constant),
8✔
95
        }
96
    }
97
}
98

99
impl<T> Rename for T
100
where
101
    T: ToString,
102
{
103
    fn rename(&self, rule: RenameRule) -> String {
21✔
104
        rule.rename(self.to_string())
21✔
105
    }
106
}
107

108
impl<T> MethodRename for T
109
where
110
    T: ToString + Rename,
111
{
112
    fn rename_method(&self, rule: RenameRule) -> String {
181✔
113
        let original = self.to_string();
181✔
114
        match rule {
181✔
115
            RenameRule::None => original,
35✔
UNCOV
116
            _ => {
×
117
                if MAGIC_METHOD.contains(&original.as_str()) {
146✔
118
                    match original.as_str() {
136✔
119
                        "__to_string" => "__toString".to_string(),
144✔
120
                        "__debug_info" => "__debugInfo".to_string(),
136✔
121
                        "__call_static" => "__callStatic".to_string(),
128✔
122
                        _ => original,
112✔
123
                    }
124
                } else {
125
                    self.rename(rule)
10✔
126
                }
127
            }
128
        }
129
    }
130
}
131

132
#[cfg(test)]
133
mod tests {
134
    use crate::parsing::{MethodRename, Rename};
135

136
    use super::{PhpRename, RenameRule};
137

138
    #[test]
139
    fn php_rename() {
140
        let rename = PhpRename {
141
            name: Some("test".to_string()),
142
            rename: None,
143
        };
144
        assert_eq!(rename.rename("testCase", RenameRule::Snake), "test");
145
        assert_eq!(rename.rename("TestCase", RenameRule::Snake), "test");
146
        assert_eq!(rename.rename("TEST_CASE", RenameRule::Snake), "test");
147

148
        let rename = PhpRename {
149
            name: None,
150
            rename: Some(RenameRule::ScreamingSnake),
151
        };
152
        assert_eq!(rename.rename("testCase", RenameRule::Snake), "TEST_CASE");
153
        assert_eq!(rename.rename("TestCase", RenameRule::Snake), "TEST_CASE");
154
        assert_eq!(rename.rename("TEST_CASE", RenameRule::Snake), "TEST_CASE");
155

156
        let rename = PhpRename {
157
            name: Some("test".to_string()),
158
            rename: Some(RenameRule::ScreamingSnake),
159
        };
160
        assert_eq!(rename.rename("testCase", RenameRule::Snake), "test");
161
        assert_eq!(rename.rename("TestCase", RenameRule::Snake), "test");
162
        assert_eq!(rename.rename("TEST_CASE", RenameRule::Snake), "test");
163

164
        let rename = PhpRename {
165
            name: None,
166
            rename: None,
167
        };
168
        assert_eq!(rename.rename("testCase", RenameRule::Snake), "test_case");
169
        assert_eq!(rename.rename("TestCase", RenameRule::Snake), "test_case");
170
        assert_eq!(rename.rename("TEST_CASE", RenameRule::Snake), "test_case");
171
    }
172

173
    #[test]
174
    fn php_rename_method() {
175
        let rename = PhpRename {
176
            name: Some("test".to_string()),
177
            rename: None,
178
        };
179
        assert_eq!(rename.rename_method("testCase", RenameRule::Snake), "test");
180
        assert_eq!(rename.rename_method("TestCase", RenameRule::Snake), "test");
181
        assert_eq!(rename.rename_method("TEST_CASE", RenameRule::Snake), "test");
182

183
        let rename = PhpRename {
184
            name: None,
185
            rename: Some(RenameRule::ScreamingSnake),
186
        };
187
        assert_eq!(
188
            rename.rename_method("testCase", RenameRule::Snake),
189
            "TEST_CASE"
190
        );
191
        assert_eq!(
192
            rename.rename_method("TestCase", RenameRule::Snake),
193
            "TEST_CASE"
194
        );
195
        assert_eq!(
196
            rename.rename_method("TEST_CASE", RenameRule::Snake),
197
            "TEST_CASE"
198
        );
199

200
        let rename = PhpRename {
201
            name: Some("test".to_string()),
202
            rename: Some(RenameRule::ScreamingSnake),
203
        };
204
        assert_eq!(rename.rename_method("testCase", RenameRule::Snake), "test");
205
        assert_eq!(rename.rename_method("TestCase", RenameRule::Snake), "test");
206
        assert_eq!(rename.rename_method("TEST_CASE", RenameRule::Snake), "test");
207

208
        let rename = PhpRename {
209
            name: None,
210
            rename: None,
211
        };
212
        assert_eq!(
213
            rename.rename_method("testCase", RenameRule::Snake),
214
            "test_case"
215
        );
216
        assert_eq!(
217
            rename.rename_method("TestCase", RenameRule::Snake),
218
            "test_case"
219
        );
220
        assert_eq!(
221
            rename.rename_method("TEST_CASE", RenameRule::Snake),
222
            "test_case"
223
        );
224
    }
225

226
    #[test]
227
    fn rename_magic_method() {
228
        for &(magic, expected) in &[
229
            ("__construct", "__construct"),
230
            ("__destruct", "__destruct"),
231
            ("__call", "__call"),
232
            ("__call_static", "__callStatic"),
233
            ("__get", "__get"),
234
            ("__set", "__set"),
235
            ("__isset", "__isset"),
236
            ("__unset", "__unset"),
237
            ("__sleep", "__sleep"),
238
            ("__wakeup", "__wakeup"),
239
            ("__serialize", "__serialize"),
240
            ("__unserialize", "__unserialize"),
241
            ("__to_string", "__toString"),
242
            ("__invoke", "__invoke"),
243
            ("__set_state", "__set_state"),
244
            ("__clone", "__clone"),
245
            ("__debug_info", "__debugInfo"),
246
        ] {
247
            assert_eq!(magic, magic.rename_method(RenameRule::None));
248
            assert_eq!(
249
                magic,
250
                PhpRename {
251
                    name: None,
252
                    rename: Some(RenameRule::None)
253
                }
254
                .rename_method(magic, RenameRule::ScreamingSnake)
255
            );
256

257
            assert_eq!(expected, magic.rename_method(RenameRule::Camel));
258
            assert_eq!(
259
                expected,
260
                PhpRename {
261
                    name: None,
262
                    rename: Some(RenameRule::Camel)
263
                }
264
                .rename_method(magic, RenameRule::ScreamingSnake)
265
            );
266

267
            assert_eq!(expected, magic.rename_method(RenameRule::Pascal));
268
            assert_eq!(
269
                expected,
270
                PhpRename {
271
                    name: None,
272
                    rename: Some(RenameRule::Pascal)
273
                }
274
                .rename_method(magic, RenameRule::ScreamingSnake)
275
            );
276

277
            assert_eq!(expected, magic.rename_method(RenameRule::Snake));
278
            assert_eq!(
279
                expected,
280
                PhpRename {
281
                    name: None,
282
                    rename: Some(RenameRule::Snake)
283
                }
284
                .rename_method(magic, RenameRule::ScreamingSnake)
285
            );
286

287
            assert_eq!(expected, magic.rename_method(RenameRule::ScreamingSnake));
288
            assert_eq!(
289
                expected,
290
                PhpRename {
291
                    name: None,
292
                    rename: Some(RenameRule::ScreamingSnake)
293
                }
294
                .rename_method(magic, RenameRule::Camel)
295
            );
296
        }
297
    }
298

299
    #[test]
300
    fn rename_method() {
301
        let &(original, camel, snake, pascal, screaming_snake) =
302
            &("get_name", "getName", "get_name", "GetName", "GET_NAME");
303
        assert_eq!(original, original.rename_method(RenameRule::None));
304
        assert_eq!(camel, original.rename_method(RenameRule::Camel));
305
        assert_eq!(pascal, original.rename_method(RenameRule::Pascal));
306
        assert_eq!(snake, original.rename_method(RenameRule::Snake));
307
        assert_eq!(
308
            screaming_snake,
309
            original.rename_method(RenameRule::ScreamingSnake)
310
        );
311
    }
312

313
    #[test]
314
    fn rename() {
315
        let &(original, camel, snake, pascal, screaming_snake) =
316
            &("get_name", "getName", "get_name", "GetName", "GET_NAME");
317
        assert_eq!(original, original.rename(RenameRule::None));
318
        assert_eq!(camel, original.rename(RenameRule::Camel));
319
        assert_eq!(pascal, original.rename(RenameRule::Pascal));
320
        assert_eq!(snake, original.rename(RenameRule::Snake));
321
        assert_eq!(screaming_snake, original.rename(RenameRule::ScreamingSnake));
322
    }
323
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc