inflector/
lib.rs

1#![deny(warnings, unused_variables, missing_docs, unsafe_code, unused_extern_crates)]
2#![cfg_attr(feature = "unstable", feature(test))]
3
4//! Adds String based inflections for Rust. Snake, kebab, train, camel,
5//! sentence, class, and title cases as well as ordinalize,
6//! deordinalize, demodulize, deconstantize, and foreign key are supported as
7//! both traits and pure functions acting on String types.
8//! ```rust
9//! use inflector::Inflector;
10//! let camel_case_string: String = "some_string".to_camel_case();
11//! let is_camel_cased: bool= camel_case_string.is_camel_case();
12//! assert!(is_camel_cased == true);
13//! ```
14
15#[cfg(feature = "heavyweight")]
16extern crate regex;
17
18#[cfg(feature = "heavyweight")]
19#[macro_use] extern crate lazy_static;
20
21/// Provides case inflections
22/// - Camel case
23/// - Class case
24/// - Kebab case
25/// - Train case
26/// - Screaming snake case
27/// - Table case
28/// - Sentence case
29/// - Snake case
30/// - Pascal case
31pub mod cases;
32/// Provides number inflections
33/// - Ordinalize
34/// - Deordinalize
35pub mod numbers;
36/// Provides suffix inflections
37/// - Foreign key
38pub mod suffix;
39/// Provides string inflections
40/// - Deconstantize
41/// - Demodulize
42/// - Pluralize
43/// - Singularize
44#[cfg(feature = "heavyweight")]
45pub mod string;
46
47
48#[cfg(feature = "heavyweight")]
49use cases::classcase::to_class_case;
50#[cfg(feature = "heavyweight")]
51use cases::classcase::is_class_case;
52
53use cases::camelcase::to_camel_case;
54use cases::camelcase::is_camel_case;
55
56use cases::pascalcase::to_pascal_case;
57use cases::pascalcase::is_pascal_case;
58
59use cases::snakecase::to_snake_case;
60use cases::snakecase::is_snake_case;
61
62use cases::screamingsnakecase::to_screaming_snake_case;
63use cases::screamingsnakecase::is_screaming_snake_case;
64
65use cases::kebabcase::to_kebab_case;
66use cases::kebabcase::is_kebab_case;
67
68use cases::traincase::to_train_case;
69use cases::traincase::is_train_case;
70
71use cases::sentencecase::to_sentence_case;
72use cases::sentencecase::is_sentence_case;
73
74use cases::titlecase::to_title_case;
75use cases::titlecase::is_title_case;
76
77#[cfg(feature = "heavyweight")]
78use cases::tablecase::to_table_case;
79#[cfg(feature = "heavyweight")]
80use cases::tablecase::is_table_case;
81
82use numbers::ordinalize::ordinalize;
83use numbers::deordinalize::deordinalize;
84
85use suffix::foreignkey::to_foreign_key;
86use suffix::foreignkey::is_foreign_key;
87
88#[cfg(feature = "heavyweight")]
89use string::demodulize::demodulize;
90#[cfg(feature = "heavyweight")]
91use string::deconstantize::deconstantize;
92
93#[cfg(feature = "heavyweight")]
94use string::pluralize::to_plural;
95#[cfg(feature = "heavyweight")]
96use string::singularize::to_singular;
97
98#[allow(missing_docs)]
99pub trait Inflector {
100
101    fn to_camel_case(&self) -> String;
102    fn is_camel_case(&self) -> bool;
103
104    fn to_pascal_case(&self) -> String;
105    fn is_pascal_case(&self) -> bool;
106
107    fn to_snake_case(&self) -> String;
108    fn is_snake_case(&self) -> bool;
109
110    fn to_screaming_snake_case(&self) -> String;
111    fn is_screaming_snake_case(&self) -> bool;
112
113    fn to_kebab_case(&self) -> String;
114    fn is_kebab_case(&self) -> bool;
115
116    fn to_train_case(&self) -> String;
117    fn is_train_case(&self) -> bool;
118
119    fn to_sentence_case(&self) -> String;
120    fn is_sentence_case(&self) -> bool;
121
122    fn to_title_case(&self) -> String;
123    fn is_title_case(&self) -> bool;
124
125    fn ordinalize(&self) -> String;
126    fn deordinalize(&self) -> String;
127
128    fn to_foreign_key(&self) -> String;
129    fn is_foreign_key(&self) -> bool;
130
131    #[cfg(feature = "heavyweight")]
132    fn demodulize(&self) -> String;
133    #[cfg(feature = "heavyweight")]
134    fn deconstantize(&self) -> String;
135
136    #[cfg(feature = "heavyweight")]
137    fn to_class_case(&self) -> String;
138    #[cfg(feature = "heavyweight")]
139    fn is_class_case(&self) -> bool;
140
141    #[cfg(feature = "heavyweight")]
142    fn to_table_case(&self) -> String;
143    #[cfg(feature = "heavyweight")]
144    fn is_table_case(&self) -> bool;
145    #[cfg(feature = "heavyweight")]
146    fn to_plural(&self) -> String;
147    #[cfg(feature = "heavyweight")]
148    fn to_singular(&self) -> String;
149}
150
151
152#[allow(missing_docs)]
153pub trait InflectorNumbers {
154    fn ordinalize(&self) -> String;
155}
156
157
158macro_rules! define_implementations {
159    ( $slf:ident; $($imp_trait:ident => $typ:ident), *) => {
160        $(
161            #[inline]
162            fn $imp_trait(&$slf) -> $typ {
163                $imp_trait($slf)
164            }
165        )*
166    }
167}
168
169macro_rules! define_number_implementations {
170    ( $slf:ident; $($imp_trait:ident => $typ:ident), *) => {
171        $(
172            #[inline]
173            fn $imp_trait(&$slf) -> $typ {
174                $imp_trait(&$slf.to_string())
175            }
176        )*
177    }
178}
179
180macro_rules! define_gated_implementations {
181    ( $slf:ident; $($imp_trait:ident => $typ:ident), *) => {
182        $(
183            #[inline]
184            #[cfg(feature = "heavyweight")]
185            fn $imp_trait(&$slf) -> $typ {
186                $imp_trait($slf)
187            }
188        )*
189    }
190}
191
192macro_rules! implement_string_for {
193    ( $trt:ident; $($typ:ident), *) => {
194        $(
195            impl $trt for $typ {
196                define_implementations![self;
197                    to_camel_case => String,
198                    is_camel_case => bool,
199                    to_pascal_case => String,
200                    is_pascal_case => bool,
201                    to_screaming_snake_case => String,
202                    is_screaming_snake_case => bool,
203                    to_snake_case => String,
204                    is_snake_case => bool,
205                    to_kebab_case => String,
206                    is_kebab_case => bool,
207                    to_train_case => String,
208                    is_train_case => bool,
209                    to_sentence_case => String,
210                    is_sentence_case => bool,
211                    to_title_case => String,
212                    is_title_case => bool,
213                    to_foreign_key => String,
214                    is_foreign_key => bool,
215                    ordinalize => String,
216                    deordinalize => String
217                ];
218                define_gated_implementations![self;
219                    to_class_case => String,
220                    is_class_case => bool,
221                    to_table_case => String,
222                    is_table_case => bool,
223                    to_plural => String,
224                    to_singular => String,
225                    demodulize => String,
226                    deconstantize => String
227                ];
228            }
229        )*
230    }
231}
232
233macro_rules! implement_number_for {
234    ( $trt:ident; $($typ:ident), *) => {
235        $(
236            impl $trt for $typ {
237                define_number_implementations![self;
238                    ordinalize => String
239                ];
240            }
241        )*
242    }
243}
244
245implement_string_for![
246    Inflector;
247    String, str
248];
249
250implement_number_for![
251    InflectorNumbers;
252    i8, i16, i32, i64, u8, u16, u32, u64, isize, usize, f32, f64
253];
254
255#[cfg(all(feature = "unstable", test))]
256mod benchmarks {
257    extern crate test;
258    use self::test::Bencher;
259    use ::Inflector;
260
261    macro_rules! benchmarks {
262        ( $($test_name:ident => $imp_trait:ident => $to_cast:expr), *) => {
263            $(
264                #[bench]
265                fn $test_name(b: &mut Bencher) {
266                    b.iter(|| {
267                        $to_cast.$imp_trait()
268                    });
269                }
270            )*
271        }
272    }
273
274    benchmarks![
275        benchmark_str_to_camel => to_camel_case => "foo_bar",
276        benchmark_str_is_camel => is_camel_case => "fooBar",
277        benchmark_str_to_screaming_snake => to_screaming_snake_case => "fooBar",
278        benchmark_str_is_screaming_snake => is_screaming_snake_case => "FOO_BAR",
279        benchmark_str_to_snake => to_snake_case => "fooBar",
280        benchmark_str_is_snake => is_snake_case => "foo_bar",
281        benchmark_str_to_kebab => to_kebab_case => "fooBar",
282        benchmark_str_is_kebab => is_kebab_case => "foo-bar",
283        benchmark_str_to_train => to_train_case => "fooBar",
284        benchmark_str_is_train => is_train_case => "Foo-Bar",
285        benchmark_str_to_sentence => to_sentence_case => "fooBar",
286        benchmark_str_is_sentence => is_sentence_case => "Foo bar",
287        benchmark_str_to_title => to_title_case => "fooBar",
288        benchmark_str_is_title => is_title_case => "Foo Bar",
289        benchmark_str_ordinalize  => ordinalize => "1",
290        benchmark_str_deordinalize  => deordinalize => "1st",
291        benchmark_str_to_foreign_key => to_foreign_key => "Foo::Bar",
292        benchmark_str_is_foreign_key => is_foreign_key => "bar_id",
293        benchmark_string_to_camel => to_camel_case => "foo_bar".to_string(),
294        benchmark_string_is_camel => is_camel_case => "fooBar".to_string(),
295        benchmark_string_to_screaming_snake => to_screaming_snake_case => "fooBar".to_string(),
296        benchmark_string_is_screaming_snake => is_screaming_snake_case => "FOO_BAR".to_string(),
297        benchmark_string_to_snake => to_snake_case => "fooBar".to_string(),
298        benchmark_string_is_snake => is_snake_case => "foo_bar".to_string(),
299        benchmark_string_to_kebab => to_kebab_case => "fooBar".to_string(),
300        benchmark_string_is_kebab => is_kebab_case => "foo-bar".to_string(),
301        benchmark_string_to_train => to_train_case => "fooBar".to_string(),
302        benchmark_string_is_train => is_train_case => "Foo-Bar".to_string(),
303        benchmark_string_to_sentence => to_sentence_case => "fooBar".to_string(),
304        benchmark_string_is_sentence => is_sentence_case => "Foo bar".to_string(),
305        benchmark_string_to_title => to_title_case => "fooBar".to_string(),
306        benchmark_string_is_title => is_title_case => "Foo Bar".to_string(),
307        benchmark_string_ordinalize  => ordinalize => "1".to_string(),
308        benchmark_string_deordinalize  => deordinalize => "1st".to_string(),
309        benchmark_string_to_foreign_key => to_foreign_key => "Foo::Bar".to_string(),
310        benchmark_string_is_foreign_key => is_foreign_key => "bar_id".to_string()
311    ];
312
313    #[cfg(feature = "heavyweight")]
314    benchmarks![
315        benchmark_str_to_class => to_class_case => "foo",
316        benchmark_str_is_class => is_class_case => "Foo",
317        benchmark_str_to_table => to_table_case => "fooBar",
318        benchmark_str_is_table => is_table_case => "foo_bars",
319        benchmark_str_pluralize => to_plural => "crate",
320        benchmark_str_singular => to_singular => "crates",
321        benchmark_string_to_class => to_class_case => "foo".to_string(),
322        benchmark_string_is_class => is_class_case => "Foo".to_string(),
323        benchmark_string_to_table => to_table_case => "fooBar".to_string(),
324        benchmark_string_is_table => is_table_case => "foo_bars".to_string(),
325        benchmark_string_pluralize => to_plural => "crate".to_string(),
326        benchmark_string_singular => to_singular => "crates".to_string(),
327        benchmark_string_demodulize => demodulize => "Foo::Bar".to_string(),
328        benchmark_string_deconstantize => deconstantize => "Foo::Bar".to_string(),
329        benchmark_str_demodulize => demodulize => "Foo::Bar",
330        benchmark_str_deconstantize => deconstantize => "Foo::Bar"
331    ];
332}