├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE.md ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── src ├── cases │ ├── camelcase │ │ └── mod.rs │ ├── case │ │ └── mod.rs │ ├── classcase │ │ └── mod.rs │ ├── kebabcase │ │ └── mod.rs │ ├── mod.rs │ ├── pascalcase │ │ └── mod.rs │ ├── screamingsnakecase │ │ └── mod.rs │ ├── sentencecase │ │ └── mod.rs │ ├── snakecase │ │ └── mod.rs │ ├── tablecase │ │ └── mod.rs │ ├── titlecase │ │ └── mod.rs │ └── traincase │ │ └── mod.rs ├── lib.rs ├── numbers │ ├── deordinalize │ │ └── mod.rs │ ├── mod.rs │ └── ordinalize │ │ └── mod.rs ├── string │ ├── constants │ │ └── mod.rs │ ├── deconstantize │ │ └── mod.rs │ ├── demodulize │ │ └── mod.rs │ ├── mod.rs │ ├── pluralize │ │ └── mod.rs │ └── singularize │ │ └── mod.rs └── suffix │ ├── foreignkey │ └── mod.rs │ └── mod.rs └── tests └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | *.rs.bk 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | matrix: 7 | fast_finish: true 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.11.4 2 | 3 | ## Non-breaking changes: 4 | - Resolved usage of deprecated method 5 | - Updated `regex` and `lazy_static` to current latest 6 | 7 | # 0.11.3 8 | 9 | ## Non-breaking changes: 10 | - Updated regex to 1.0.0 -- Thanks @Eijebong 11 | 12 | # 0.11.2 13 | 14 | ## Non-breaking changes: 15 | - Added class_cases and removed -- Thanks @Yoric 16 | - Use pascal case 17 | - Updated lazy_static to 1.0.0 18 | 19 | # 0.11.1 20 | 21 | ## Non-breaking changes: 22 | - Fixed an issue where words ending in e.g. "-ches", such as "witches"; that 23 | would be singularized as "wit" instead of the expected "witch". -- Thanks nbaksalyar 24 | - Will be removing ascii import when current nightly goes stable. 25 | 26 | # 0.11.0 27 | 28 | ## Breaking changes: 29 | - Made snake case deal correctly with special characters. Behaviour now follows 30 | rails infector 31 | - Made camel case deal correctly with special characters. Behaviour now follows 32 | rails infector 33 | 34 | ## Non-breaking changes: 35 | - Removed magic macros for testing. 36 | - Added explicit tests for all cases. 37 | 38 | # 0.10.1 39 | 40 | ## Non-breaking changes: 41 | - Added flags for unused macros. Any current macros with this flag with either 42 | be moved or removed. 43 | 44 | # 0.10.0 45 | 46 | ## Non-breaking changes: 47 | - Changed from `fold` to `for in` which resulted in a average 10-20% boost in 48 | performance for all castings using the case module. 49 | 50 | ## Fixes: 51 | - Fixed issue with snake case like strings where numbers were incorrectly 52 | permitted to be next to a string e.g. `string1` was considered valid when it 53 | should have been `string_1`. This has been corrected as part of the above 54 | change. 55 | 56 | ## Why is this not 0.9.1? 57 | - The change in this case are all on private API. This normally wouldn't cause a 58 | breaking change as there are extensive tests wrapping all methods. This 59 | however doesn't preclude an edge case that hasn't been considered. I've 60 | deemed it safer to call this a 0.x.0 release for that reason. 61 | 62 | # 0.9.0 63 | 64 | ## Breaking changes: 65 | - Changed type signature for all casting methods to use `&str`. This gives the 66 | crate a >10% increase in performance in a majority of conversions. Although 67 | most users only use: 68 | `"my_string".to_camel_case()` 69 | or 70 | `"myString".to_string().to_snake_case()` 71 | For those using the `to_camel_case("something".to_string())` this will be a 72 | breaking change as the new syntax demands `to_camel_case("something")`. 73 | 74 | 75 | # 0.8.1 76 | 77 | ## Fixes: 78 | 79 | - Fixed singularize issues with `/ies/`. Thanks @mthjones 80 | - Fixed issue with feature gates which may have caused downstream api 81 | incompatibilities. 82 | 83 | # 0.8.0 84 | 85 | ## New features: 86 | 87 | - Feature gated pluralize, singularize, class_case, table_case, demodulize, and 88 | deconstantize. This can be activated by passing --features=lightweight. See 89 | README 90 | 91 | 92 | ## Possible breaking change: 93 | 94 | - Feature gated items are on by default, meaning that you'll get the full 95 | version of the crate if you install as normal. See README if you want to use 96 | the lightweight version. 97 | - Although the application still passes all tests, substantial portions of the 98 | core of the conversion code have been method extracted and may have caused a 99 | change for some people. Please file an issue if this is a problem for you. 100 | 101 | # 0.7.0 102 | 103 | ## New features: 104 | 105 | - Added traits for various number types on ordinalize. 106 | 107 | ## Possible breaking change: 108 | 109 | - Fixed issue with Boxes to Box which may cause breakages for some people 110 | 111 | ## Non-breaking change: 112 | 113 | - Updated dependencies on `regex` and `lazy_static` to be the current latest 114 | - Changed the way that traits are implemented to use macros. Thus reducing 115 | duplication issues seen previously for each type that wanted to implement 116 | Inflector 117 | - More tests for conversion between different string formats 118 | - Better documentation for new users 119 | - Cleaned up documentation 120 | 121 | ## Notes: 122 | - This is a pre-release for 1.0.0 123 | 124 | # 0.6.0 125 | 126 | ## Breaking changes: 127 | 128 | - Removed lower and upper case. -- Use the built in [Rust implementations](https://doc.rust-lang.org/std/string/struct.String.html#method.to_uppercase) 129 | 130 | ## Non-breaking change: 131 | 132 | - Removed lib definitions. -- Thanks @kanerogers 133 | 134 | # 0.5.1 135 | 136 | ## Non-breaking change: 137 | 138 | - Refactored Title, Pascal, Train and Camel cases to be unified. 139 | 140 | # 0.5.0 141 | 142 | ## New features: 143 | 144 | - Adds Train-Case thanks to @stpettersens 145 | 146 | ## Fixes: 147 | 148 | - Fixes performance issues with Title Case 149 | 150 | # 0.4.0 151 | 152 | ## Fixes: 153 | 154 | - Fixes issue where strings like `HTTPParty` becomes `h_t_t_p_party` instead of `http_party` as it should -- Thanks @cmsd2 155 | 156 | ## New features: 157 | 158 | - Adds PascalCase 159 | 160 | ## Benchmarks: 161 | ```shell 162 | test cases::camelcase::tests::bench_camel0 ... bench: 142 ns/iter (+/- 28) 163 | test cases::camelcase::tests::bench_camel1 ... bench: 143 ns/iter (+/- 30) 164 | test cases::camelcase::tests::bench_camel2 ... bench: 138 ns/iter (+/- 80) 165 | test cases::camelcase::tests::bench_is_camel ... bench: 171 ns/iter (+/- 103) 166 | test cases::classcase::tests::bench_class_case ... bench: 2,369 ns/iter (+/- 658) 167 | test cases::classcase::tests::bench_class_from_snake ... bench: 2,378 ns/iter (+/- 914) 168 | test cases::classcase::tests::bench_is_class ... bench: 2,541 ns/iter (+/- 294) 169 | test cases::kebabcase::tests::bench_is_kebab ... bench: 180 ns/iter (+/- 35) 170 | test cases::kebabcase::tests::bench_kebab ... bench: 156 ns/iter (+/- 91) 171 | test cases::kebabcase::tests::bench_kebab_from_snake ... bench: 248 ns/iter (+/- 143) 172 | test cases::lowercase::tests::bench_is_lower ... bench: 340 ns/iter (+/- 91) 173 | test cases::lowercase::tests::bench_lower ... bench: 301 ns/iter (+/- 124) 174 | test cases::pascalcase::tests::bench_is_pascal ... bench: 163 ns/iter (+/- 65) 175 | test cases::pascalcase::tests::bench_pascal0 ... bench: 140 ns/iter (+/- 78) 176 | test cases::pascalcase::tests::bench_pascal1 ... bench: 140 ns/iter (+/- 40) 177 | test cases::pascalcase::tests::bench_pascal2 ... bench: 138 ns/iter (+/- 105) 178 | test cases::screamingsnakecase::tests::bench_is_screaming_snake ... bench: 193 ns/iter (+/- 27) 179 | test cases::screamingsnakecase::tests::bench_screaming_snake ... bench: 161 ns/iter (+/- 84) 180 | test cases::sentencecase::tests::bench_is_sentence ... bench: 394 ns/iter (+/- 85) 181 | test cases::sentencecase::tests::bench_sentence ... bench: 365 ns/iter (+/- 186) 182 | test cases::sentencecase::tests::bench_sentence_from_snake ... bench: 333 ns/iter (+/- 178) 183 | test cases::snakecase::tests::bench_is_snake ... bench: 190 ns/iter (+/- 74) 184 | test cases::snakecase::tests::bench_snake_from_camel ... bench: 155 ns/iter (+/- 44) 185 | test cases::snakecase::tests::bench_snake_from_snake ... bench: 280 ns/iter (+/- 161) 186 | test cases::snakecase::tests::bench_snake_from_title ... bench: 156 ns/iter (+/- 31) 187 | test cases::tablecase::tests::bench_is_table_case ... bench: 2,388 ns/iter (+/- 431) 188 | test cases::tablecase::tests::bench_table_case ... bench: 2,240 ns/iter (+/- 446) 189 | test cases::titlecase::tests::bench_is_title ... bench: 786 ns/iter (+/- 135) 190 | test cases::titlecase::tests::bench_title ... bench: 826 ns/iter (+/- 278) 191 | test cases::titlecase::tests::bench_title_from_snake ... bench: 723 ns/iter (+/- 256) 192 | test cases::uppercase::tests::bench_is_upper ... bench: 351 ns/iter (+/- 85) 193 | test cases::uppercase::tests::bench_upper ... bench: 332 ns/iter (+/- 48) 194 | ``` 195 | 196 | # 0.3.3 197 | 198 | ## Fixes: 199 | 200 | - Fixes issue where camel case tests were not run 201 | - Fixes issue with camel case with numbers 202 | 203 | # 0.3.2 204 | 205 | ## Fixes: 206 | 207 | - Fixes issue https://github.com/whatisinternet/inflector/issues/18 208 | - Fixes performance issues overall 209 | 210 | ## Benchmarks: 211 | ```shell 212 | test cases::camelcase::tests::bench_camel0 ... bench: 139 ns/iter (+/- 40) 213 | test cases::camelcase::tests::bench_camel1 ... bench: 138 ns/iter (+/- 31) 214 | test cases::camelcase::tests::bench_camel2 ... bench: 138 ns/iter (+/- 41) 215 | test cases::camelcase::tests::bench_is_camel ... bench: 184 ns/iter (+/- 90) 216 | test cases::classcase::tests::bench_class_case ... bench: 2,383 ns/iter (+/- 557) 217 | test cases::classcase::tests::bench_class_from_snake ... bench: 2,393 ns/iter (+/- 1,120) 218 | test cases::classcase::tests::bench_is_class ... bench: 2,443 ns/iter (+/- 1,060) 219 | test cases::kebabcase::tests::bench_is_kebab ... bench: 182 ns/iter (+/- 60) 220 | test cases::kebabcase::tests::bench_kebab ... bench: 161 ns/iter (+/- 98) 221 | test cases::kebabcase::tests::bench_kebab_from_snake ... bench: 264 ns/iter (+/- 144) 222 | test cases::lowercase::tests::bench_is_lower ... bench: 358 ns/iter (+/- 154) 223 | test cases::lowercase::tests::bench_lower ... bench: 347 ns/iter (+/- 220) 224 | test cases::screamingsnakecase::tests::bench_is_screaming_snake ... bench: 194 ns/iter (+/- 35) 225 | test cases::screamingsnakecase::tests::bench_screaming_snake ... bench: 173 ns/iter (+/- 97) 226 | test cases::sentencecase::tests::bench_is_sentence ... bench: 377 ns/iter (+/- 83) 227 | test cases::sentencecase::tests::bench_sentence ... bench: 337 ns/iter (+/- 155) 228 | test cases::sentencecase::tests::bench_sentence_from_snake ... bench: 370 ns/iter (+/- 176) 229 | test cases::snakecase::tests::bench_is_snake ... bench: 191 ns/iter (+/- 98) 230 | test cases::snakecase::tests::bench_snake_from_camel ... bench: 156 ns/iter (+/- 25) 231 | test cases::snakecase::tests::bench_snake_from_snake ... bench: 289 ns/iter (+/- 136) 232 | test cases::snakecase::tests::bench_snake_from_title ... bench: 157 ns/iter (+/- 68) 233 | test cases::tablecase::tests::bench_is_table_case ... bench: 2,253 ns/iter (+/- 978) 234 | test cases::tablecase::tests::bench_table_case ... bench: 2,227 ns/iter (+/- 704) 235 | test cases::titlecase::tests::bench_is_title ... bench: 787 ns/iter (+/- 362) 236 | test cases::titlecase::tests::bench_title ... bench: 826 ns/iter (+/- 317) 237 | test cases::titlecase::tests::bench_title_from_snake ... bench: 747 ns/iter (+/- 230) 238 | test cases::uppercase::tests::bench_is_upper ... bench: 347 ns/iter (+/- 111) 239 | test cases::uppercase::tests::bench_upper ... bench: 328 ns/iter (+/- 42) 240 | ``` 241 | 242 | ## OLD Benchmarks: 243 | ```shell 244 | test cases::camelcase::tests::bench_camel ... bench: 1,825 ns/iter (+/- 346) 245 | test cases::camelcase::tests::bench_camel_from_sname ... bench: 1,223 ns/iter (+/- 289) 246 | test cases::camelcase::tests::bench_is_camel ... bench: 49,416 ns/iter (+/- 593) 247 | test cases::classcase::tests::bench_class_case ... bench: 160,985,376 ns/iter (+/- 5,173,751) 248 | test cases::classcase::tests::bench_class_from_snake ... bench: 161,533,425 ns/iter (+/- 4,167,305) 249 | test cases::classcase::tests::bench_is_class ... bench: 161,352,118 ns/iter (+/- 3,793,478) 250 | test cases::kebabcase::tests::bench_is_kebab ... bench: 793 ns/iter (+/- 400) 251 | test cases::kebabcase::tests::bench_kebab ... bench: 752 ns/iter (+/- 310) 252 | test cases::kebabcase::tests::bench_kebab_from_snake ... bench: 210 ns/iter (+/- 32) 253 | test cases::lowercase::tests::bench_is_lower ... bench: 340 ns/iter (+/- 86) 254 | test cases::lowercase::tests::bench_lower ... bench: 306 ns/iter (+/- 173) 255 | test cases::screamingsnakecase::tests::bench_is_screaming_snake ... bench: 635 ns/iter (+/- 210) 256 | test cases::screamingsnakecase::tests::bench_screaming_snake ... bench: 610 ns/iter (+/- 87) 257 | test cases::screamingsnakecase::tests::bench_screaming_snake_from_camel ... bench: 961 ns/iter (+/- 579) 258 | test cases::screamingsnakecase::tests::bench_screaming_snake_from_class ... bench: 894 ns/iter (+/- 352) 259 | test cases::screamingsnakecase::tests::bench_screaming_snake_from_kebab ... bench: 877 ns/iter (+/- 571) 260 | test cases::screamingsnakecase::tests::bench_screaming_snake_from_screaming_snake ... bench: 584 ns/iter (+/- 304) 261 | test cases::screamingsnakecase::tests::bench_screaming_snake_from_sentence ... bench: 1,123 ns/iter (+/- 630) 262 | test cases::screamingsnakecase::tests::bench_screaming_snake_from_upper_kebab ... bench: 914 ns/iter (+/- 435) 263 | test cases::sentencecase::tests::bench_is_sentence ... bench: 2,714 ns/iter (+/- 796) 264 | test cases::sentencecase::tests::bench_sentence ... bench: 2,678 ns/iter (+/- 1,357) 265 | test cases::sentencecase::tests::bench_sentence_from_snake ... bench: 2,100 ns/iter (+/- 1,046) 266 | test cases::snakecase::tests::bench_is_snake ... bench: 626 ns/iter (+/- 191) 267 | test cases::snakecase::tests::bench_snake ... bench: 581 ns/iter (+/- 298) 268 | test cases::snakecase::tests::bench_snake_from_camel ... bench: 882 ns/iter (+/- 328) 269 | test cases::snakecase::tests::bench_snake_from_class ... bench: 883 ns/iter (+/- 193) 270 | test cases::snakecase::tests::bench_snake_from_kebab ... bench: 922 ns/iter (+/- 360) 271 | test cases::snakecase::tests::bench_snake_from_sentence ... bench: 1,209 ns/iter (+/- 539) 272 | test cases::snakecase::tests::bench_snake_from_snake ... bench: 637 ns/iter (+/- 386) 273 | test cases::snakecase::tests::bench_snake_from_upper_kebab ... bench: 876 ns/iter (+/- 488) 274 | test cases::tablecase::tests::bench_is_table_case ... bench: 5,784 ns/iter (+/- 1,129) 275 | test cases::tablecase::tests::bench_table_case ... bench: 5,754 ns/iter (+/- 1,460) 276 | test cases::titlecase::tests::bench_is_title ... bench: 2,847 ns/iter (+/- 1,553) 277 | test cases::titlecase::tests::bench_title ... bench: 2,799 ns/iter (+/- 1,309) 278 | test cases::titlecase::tests::bench_title_from_snake ... bench: 2,202 ns/iter (+/- 697) 279 | test cases::uppercase::tests::bench_is_upper ... bench: 357 ns/iter (+/- 55) 280 | test cases::uppercase::tests::bench_upper ... bench: 311 ns/iter (+/- 135) 281 | ``` 282 | 283 | # 0.3.1 284 | 285 | ## Fixes: 286 | 287 | - Fixes issue https://github.com/rust-lang/rust/pull/34660 288 | - Updates Regex to 0.1.73 for latest fixes 289 | 290 | # 0.3.0 291 | 292 | ## Fixes: 293 | 294 | - Resolves issues with pluralize not always correctly pluralizing strings. 295 | Thanks, @weiznich! 296 | - Resolves issues with silently failing test on table case 297 | - Replaces complex code used for is_*_case checks with simple conversion and 298 | check equality. 299 | 300 | ## Breaking changes: 301 | 302 | - Dropping support for Rust versions below stable 303 | 304 | # 0.2.1 305 | 306 | ## Features: 307 | 308 | - Replaced custom implementation of lower and uppercase with Rust default 309 | 310 | ## Breaking changes: 311 | 312 | - Rust 1.2 or greater required 313 | 314 | # 0.2.0 315 | 316 | ## Features: 317 | 318 | - Added Pluralize 319 | - Added Singularize 320 | - Added Table case 321 | 322 | ## Fixes: 323 | 324 | - Fixed doc tests to properly run as rust auto wraps doc tests in a function and 325 | never ran the inner function that was defined. 326 | - Fixed documentation for kebab case 327 | - Fixed several failed tests for various cases which were mainly typos 328 | 329 | ## Breaking changes: 330 | 331 | - Class case now singularizes strings and verifies that strings are 332 | singularized. Those wishing for the old behaviour should remain on the 0.1.6 333 | release. 334 | 335 | 336 | # 0.1.6 337 | 338 | ## Features: 339 | 340 | - Added screaming snake case 341 | 342 | # 0.1.5 343 | 344 | ## Fixes: 345 | 346 | - Refactored tests into doc tests. 347 | 348 | 349 | # 0.1.4 350 | 351 | ## Features: 352 | 353 | - Significant performance improvement for casting strings between different case 354 | types see #13. 355 | 356 | ## Fixes: 357 | 358 | - Fixed performance issues with string casting. 359 | - Removed heavy reliance on Regex 360 | 361 | 362 | # 0.1.3 363 | 364 | ## Fixes: 365 | 366 | - Refactored code to mostly pass through snake case then be converted to lower 367 | the number of moving parts and reduce the complexity for adding a new casting 368 | as only snake case would need to be modified to convert to most other cases. 369 | 370 | ## Breaking changes: 371 | 372 | - This release is slow in contrast to other crates 373 | 374 | 375 | # 0.1.2 376 | 377 | ## Fixes: 378 | 379 | - Documentation fixes 380 | - Added uppercase 381 | - Added lowercase 382 | - Added foreign key 383 | - Added sentence case 384 | - Added title case 385 | 386 | 387 | # 0.1.1 388 | 389 | ## Features: 390 | - Adds support for foreign key 391 | - Adds demodulize 392 | - Adds deconstantize 393 | - Adds trait based usage 394 | 395 | 396 | # 0.1.0 397 | 398 | ## Features: 399 | 400 | - Added support for camel case 401 | - Added support for class case 402 | - Added support for kebab case 403 | - Added support for snake case 404 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Thank you! :heart: 2 | 3 | This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. 4 | 5 | ## Getting started 6 | - If you don't have rust installed: Install [rustup](https://www.rustup.rs/) 7 | - For normal development on `master` run on stable 8 | - `rustup toolchain install stable` 9 | - `rustup default stable` 10 | 11 | - For development with benchmarks run nightly 12 | - `rustup toolchain install nightly` 13 | - `rustup default nightly` 14 | 15 | ## Git/GitHub steps 16 | 1. Fork it ( https://github.com/whatisinternet/inflector/fork ) 17 | 2. Create your feature branch (`git checkout -b my-new-feature`) 18 | 3. Add test for the new feature (conversions to all different casts MUST also 19 | pass) 20 | 4. Write some code to pass the tests 21 | 5. Commit your changes (`git commit -am 'Add some feature'`) 22 | 6. Push to the branch (`git push origin my-new-feature`) 23 | 7. Create a new Pull Request 24 | 25 | ### Running the tests 26 | - `cargo test` 27 | 28 | ### Running the benchmarks 29 | - `cargo bench --features=unstable` 30 | 31 | ## Is this an issues? 32 | 33 | - Please ensure you fill out an [issue](https://github.com/whatisinternet/inflector/issues) 34 | - Be available for questions. 35 | 36 | ## Are you submitting documentation? 37 | 38 | - Awesome! 39 | - Has everything been run through spell check? 40 | 41 | ## Are you submitting code? 42 | 43 | - Have you added doc tests and do they pass? 44 | - Do all other tests pass? 45 | - Have you added trait tests? (If applicable) 46 | - Have you filled out the pull request template? 47 | 48 | 49 | ## Adding a trait 50 | Traits are now both easy to add and easy to test. Just follow the next steps: 51 | 52 | ### Adding the trait 53 | - `src/lib.rs` 54 | - Add the function signature to the Inflector trait 55 | ```rust 56 | //... 57 | use string::singularize::to_singular; 58 | //... 59 | pub trait Inflector { // Or InflectorNumbers 60 | //... 61 | fn your_trait(&self) -> [return_type]; 62 | //... 63 | } 64 | ``` 65 | - Add the function name an return type to either `implement_string_for` or 66 | `implement_number_for` 67 | ```rust 68 | your_trait => [return_type] 69 | ``` 70 | - Add a benchmark following the current convention 71 | 72 | ### Add the trait tests 73 | - `tests/lib.rs` 74 | - Add your trait following the current convention and the test will be 75 | automatically generated 76 | 77 | Thank you for your help! :heart: 78 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "Inflector" 3 | version = "0.11.4" 4 | authors = ["Josh Teeter"] 5 | include = [ 6 | "**/*.rs", 7 | "Cargo.toml", 8 | "README.md" 9 | ] 10 | readme = "README.md" 11 | repository = "https://github.com/whatisinternet/inflector" 12 | documentation = "https://docs.rs/Inflector" 13 | homepage = "https://github.com/whatisinternet/inflector" 14 | license="BSD-2-Clause" 15 | description = """ 16 | Adds String based inflections for Rust. Snake, kebab, camel, sentence, class, title and table cases as well as ordinalize, deordinalize, demodulize, foreign key, and pluralize/singularize are supported as both traits and pure functions acting on String types. 17 | """ 18 | keywords = ["pluralize", "Inflector", "camel", "snake", "inflection"] 19 | categories = ["text-processing", "value-formatting"] 20 | 21 | [badges] 22 | travis-ci = { repository = "whatisinternet/Inflector" } 23 | 24 | [features] 25 | default = ['heavyweight'] 26 | unstable = [] 27 | heavyweight = ['regex', 'lazy_static'] 28 | 29 | [lib] 30 | name = "inflector" 31 | 32 | [dependencies] 33 | regex = {version = "1.1", optional = true} 34 | lazy_static = {version = "1.2.0", optional = true} 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2017 Josh Teeter 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # What it does: 2 | 3 | 4 | # Why it does it: 5 | 6 | 7 | # Related issues: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust Inflector 2 | 3 | 4 | [![Build Status](https://travis-ci.org/whatisinternet/Inflector.svg?branch=master)](https://travis-ci.org/whatisinternet/Inflector) [![Crates.io](https://img.shields.io/crates/v/Inflector.svg)](https://crates.io/crates/inflector)[![Crate downloads](https://img.shields.io/crates/d/Inflector.svg)](https://crates.io/crates/inflector) 5 | 6 | 7 | Adds String based inflections for Rust. Snake, kebab, train, camel, 8 | sentence, class, and title cases as well as ordinalize, 9 | deordinalize, demodulize, deconstantize, foreign key, table case, and pluralize/singularize are supported as both traits and pure functions 10 | acting on &str and String types. 11 | 12 | ----- 13 | ## Documentation: 14 | 15 | Documentation can be found here at the README or via rust docs below. 16 | 17 | [Rust docs with examples](https://docs.rs/Inflector) 18 | 19 | ----- 20 | 21 | ## Installation: 22 | 23 | ### As a [crate](http://crates.io) 24 | 25 | ```toml 26 | [dependencies] 27 | Inflector = "*" 28 | ``` 29 | 30 | ### Compile yourself: 31 | 32 | 1. Install [Rust and cargo](http://doc.crates.io/) 33 | 2. git clone https://github.com/whatisinternet/Inflector 34 | 3. Library: cd inflector && cargo build --release --lib 35 | 4. You can find the library in target/release 36 | 37 | ## Usage / Example: 38 | 39 | ```rust 40 | ... 41 | // to use methods like String.to_lower_case(); 42 | extern crate inflector; 43 | use inflector::Inflector; 44 | ... 45 | fn main() { 46 | ... 47 | let camel_case_string: String = "some_string".to_camel_case(); 48 | ... 49 | } 50 | 51 | ``` 52 | 53 | Or 54 | 55 | ```rust 56 | ... 57 | // to use methods like to_snake_case(&str); 58 | extern crate inflector; 59 | 60 | // use inflector::cases::classcase::to_class_case; 61 | // use inflector::cases::classcase::is_class_case; 62 | 63 | // use inflector::cases::camelcase::to_camel_case; 64 | // use inflector::cases::camelcase::is_camel_case; 65 | 66 | // use inflector::cases::pascalcase::to_pascal_case; 67 | // use inflector::cases::pascalcase::is_pascal_case; 68 | 69 | // use inflector::cases::screamingsnakecase::to_screamingsnake_case; 70 | // use inflector::cases::screamingsnakecase::is_screamingsnake_case; 71 | 72 | // use inflector::cases::snakecase::to_snake_case; 73 | // use inflector::cases::snakecase::is_snake_case; 74 | 75 | // use inflector::cases::kebabcase::to_kebab_case; 76 | // use inflector::cases::kebabcase::is_kebab_case; 77 | 78 | // use inflector::cases::traincase::to_train_case; 79 | // use inflector::cases::traincase::is_train_case; 80 | 81 | // use inflector::cases::sentencecase::to_sentence_case; 82 | // use inflector::cases::sentencecase::is_sentence_case; 83 | 84 | // use inflector::cases::titlecase::to_title_case; 85 | // use inflector::cases::titlecase::is_title_case; 86 | 87 | // use inflector::cases::tablecase::to_table_case; 88 | // use inflector::cases::tablecase::is_table_case; 89 | 90 | // use inflector::numbers::ordinalize::ordinalize; 91 | // use inflector::numbers::deordinalize::deordinalize; 92 | 93 | // use inflector::suffix::foreignkey::to_foreign_key; 94 | // use inflector::suffix::foreignkey::is_foreign_key; 95 | 96 | // use inflector::string::demodulize::demodulize; 97 | // use inflector::string::deconstantize::deconstantize; 98 | 99 | // use inflector::string::pluralize::to_plural; 100 | // use inflector::string::singularize::to_singular; 101 | ... 102 | fn main() { 103 | ... 104 | let camel_case_string: String = to_camel_case("some_string"); 105 | ... 106 | } 107 | 108 | ``` 109 | 110 | ## Advanced installation and usage: 111 | 112 | If the project doesn't require singularize, pluralize, class, table, demodulize, 113 | deconstantize. Then in your `cargo.toml` you may wish to specify: 114 | 115 | ```toml 116 | [dependencies.Inflector] 117 | version = "*" 118 | default-features = false 119 | ``` 120 | 121 | Or 122 | 123 | ```toml 124 | Inflector = {version="*", default-features=false} 125 | 126 | ``` 127 | 128 | To test this crate locally with features off try: 129 | 130 | ```shell 131 | cargo test --no-default-features 132 | ``` 133 | 134 | ## [Contributing](CONTRIBUTING.md) 135 | 136 | This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. 137 | -------------------------------------------------------------------------------- /src/cases/camelcase/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | use cases::case::*; 3 | 4 | /// Converts a `&str` to camelCase `String` 5 | /// 6 | /// ``` 7 | /// use inflector::cases::camelcase::to_camel_case; 8 | /// let mock_string: &str = "fooBar"; 9 | /// let expected_string: String = "fooBar".to_string(); 10 | /// let asserted_string: String = to_camel_case(mock_string); 11 | /// assert!(asserted_string == expected_string); 12 | /// 13 | /// ``` 14 | /// ``` 15 | /// use inflector::cases::camelcase::to_camel_case; 16 | /// let mock_string: &str = "FOO_BAR"; 17 | /// let expected_string: String = "fooBar".to_string(); 18 | /// let asserted_string: String = to_camel_case(mock_string); 19 | /// assert!(asserted_string == expected_string); 20 | /// 21 | /// ``` 22 | /// ``` 23 | /// use inflector::cases::camelcase::to_camel_case; 24 | /// let mock_string: &str = "Foo Bar"; 25 | /// let expected_string: String = "fooBar".to_string(); 26 | /// let asserted_string: String = to_camel_case(mock_string); 27 | /// assert!(asserted_string == expected_string); 28 | /// 29 | /// ``` 30 | /// ``` 31 | /// use inflector::cases::camelcase::to_camel_case; 32 | /// let mock_string: &str = "foo_bar"; 33 | /// let expected_string: String = "fooBar".to_string(); 34 | /// let asserted_string: String = to_camel_case(mock_string); 35 | /// assert!(asserted_string == expected_string); 36 | /// 37 | /// ``` 38 | /// ``` 39 | /// use inflector::cases::camelcase::to_camel_case; 40 | /// let mock_string: &str = "Foo bar"; 41 | /// let expected_string: String = "fooBar".to_string(); 42 | /// let asserted_string: String = to_camel_case(mock_string); 43 | /// assert!(asserted_string == expected_string); 44 | /// 45 | /// ``` 46 | /// ``` 47 | /// use inflector::cases::camelcase::to_camel_case; 48 | /// let mock_string: &str = "foo-bar"; 49 | /// let expected_string: String = "fooBar".to_string(); 50 | /// let asserted_string: String = to_camel_case(mock_string); 51 | /// assert!(asserted_string == expected_string); 52 | /// 53 | /// ``` 54 | /// ``` 55 | /// use inflector::cases::camelcase::to_camel_case; 56 | /// let mock_string: &str = "FooBar"; 57 | /// let expected_string: String = "fooBar".to_string(); 58 | /// let asserted_string: String = to_camel_case(mock_string); 59 | /// assert!(asserted_string == expected_string); 60 | /// 61 | /// ``` 62 | /// ``` 63 | /// use inflector::cases::camelcase::to_camel_case; 64 | /// let mock_string: &str = "FooBar3"; 65 | /// let expected_string: String = "fooBar3".to_string(); 66 | /// let asserted_string: String = to_camel_case(mock_string); 67 | /// assert!(asserted_string == expected_string); 68 | /// 69 | /// ``` 70 | /// ``` 71 | /// use inflector::cases::camelcase::to_camel_case; 72 | /// let mock_string: &str = "Foo-Bar"; 73 | /// let expected_string: String = "fooBar".to_string(); 74 | /// let asserted_string: String = to_camel_case(mock_string); 75 | /// assert!(asserted_string == expected_string); 76 | /// 77 | /// ``` 78 | pub fn to_camel_case(non_camelized_string: &str) -> String { 79 | let options = CamelOptions { 80 | new_word: false, 81 | last_char: ' ', 82 | first_word: false, 83 | injectable_char: ' ', 84 | has_seperator: false, 85 | inverted: false, 86 | }; 87 | to_case_camel_like(&non_camelized_string, options) 88 | } 89 | 90 | /// Determines if a `&str` is camelCase bool`` 91 | /// 92 | /// ``` 93 | /// use inflector::cases::camelcase::is_camel_case; 94 | /// let mock_string: &str = "Foo"; 95 | /// let asserted_bool: bool = is_camel_case(mock_string); 96 | /// assert!(asserted_bool == false); 97 | /// 98 | /// 99 | /// ``` 100 | /// ``` 101 | /// use inflector::cases::camelcase::is_camel_case; 102 | /// let mock_string: &str = "foo"; 103 | /// let asserted_bool: bool = is_camel_case(mock_string); 104 | /// assert!(asserted_bool == true); 105 | /// 106 | /// 107 | /// ``` 108 | /// ``` 109 | /// use inflector::cases::camelcase::is_camel_case; 110 | /// let mock_string: &str = "foo-bar-string-that-is-really-really-long"; 111 | /// let asserted_bool: bool = is_camel_case(mock_string); 112 | /// assert!(asserted_bool == false); 113 | /// 114 | /// 115 | /// ``` 116 | /// ``` 117 | /// use inflector::cases::camelcase::is_camel_case; 118 | /// let mock_string: &str = "FooBarIsAReallyReallyLongString"; 119 | /// let asserted_bool: bool = is_camel_case(mock_string); 120 | /// assert!(asserted_bool == false); 121 | /// 122 | /// 123 | /// ``` 124 | /// ``` 125 | /// use inflector::cases::camelcase::is_camel_case; 126 | /// let mock_string: &str = "fooBarIsAReallyReally3LongString"; 127 | /// let asserted_bool: bool = is_camel_case(mock_string); 128 | /// assert!(asserted_bool == true); 129 | /// 130 | /// 131 | /// ``` 132 | /// ``` 133 | /// use inflector::cases::camelcase::is_camel_case; 134 | /// let mock_string: &str = "fooBarIsAReallyReallyLongString"; 135 | /// let asserted_bool: bool = is_camel_case(mock_string); 136 | /// assert!(asserted_bool == true); 137 | /// 138 | /// 139 | /// ``` 140 | /// ``` 141 | /// use inflector::cases::camelcase::is_camel_case; 142 | /// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG"; 143 | /// let asserted_bool: bool = is_camel_case(mock_string); 144 | /// assert!(asserted_bool == false); 145 | /// 146 | /// 147 | /// ``` 148 | /// ``` 149 | /// use inflector::cases::camelcase::is_camel_case; 150 | /// let mock_string: &str = "foo_bar_string_that_is_really_really_long"; 151 | /// let asserted_bool: bool = is_camel_case(mock_string); 152 | /// assert!(asserted_bool == false); 153 | /// 154 | /// 155 | /// ``` 156 | /// ``` 157 | /// use inflector::cases::camelcase::is_camel_case; 158 | /// let mock_string: &str = "Foo bar string that is really really long"; 159 | /// let asserted_bool: bool = is_camel_case(mock_string); 160 | /// assert!(asserted_bool == false); 161 | /// 162 | /// 163 | /// ``` 164 | /// ``` 165 | /// use inflector::cases::camelcase::is_camel_case; 166 | /// let mock_string: &str = "Foo Bar Is A Really Really Long String"; 167 | /// let asserted_bool: bool = is_camel_case(mock_string); 168 | /// assert!(asserted_bool == false); 169 | /// ``` 170 | pub fn is_camel_case(test_string: &str) -> bool { 171 | to_camel_case(&test_string.clone()) == test_string 172 | } 173 | 174 | #[cfg(all(feature = "unstable", test))] 175 | mod benchmarks { 176 | extern crate test; 177 | use self::test::Bencher; 178 | 179 | #[bench] 180 | fn bench_camel0(b: &mut Bencher) { 181 | b.iter(|| { 182 | let test_string = "Foo bar"; 183 | super::to_camel_case(test_string) 184 | }); 185 | } 186 | 187 | #[bench] 188 | fn bench_camel1(b: &mut Bencher) { 189 | b.iter(|| { 190 | let test_string = "foo_bar"; 191 | super::to_camel_case(test_string) 192 | }); 193 | } 194 | 195 | #[bench] 196 | fn bench_camel2(b: &mut Bencher) { 197 | b.iter(|| { 198 | let test_string = "fooBar"; 199 | super::to_camel_case(test_string) 200 | }); 201 | } 202 | 203 | #[bench] 204 | fn bench_is_camel(b: &mut Bencher) { 205 | b.iter(|| { 206 | let test_string: &str = "Foo bar"; 207 | super::is_camel_case(test_string) 208 | }); 209 | } 210 | } 211 | 212 | #[cfg(test)] 213 | mod tests { 214 | use ::to_camel_case; 215 | use ::is_camel_case; 216 | 217 | #[test] 218 | fn from_camel_case() { 219 | let convertable_string: String = "fooBar".to_owned(); 220 | let expected: String = "fooBar".to_owned(); 221 | assert_eq!(to_camel_case(&convertable_string), expected) 222 | } 223 | 224 | #[test] 225 | fn from_pascal_case() { 226 | let convertable_string: String = "FooBar".to_owned(); 227 | let expected: String = "fooBar".to_owned(); 228 | assert_eq!(to_camel_case(&convertable_string), expected) 229 | } 230 | 231 | #[test] 232 | fn from_kebab_case() { 233 | let convertable_string: String = "foo-bar".to_owned(); 234 | let expected: String = "fooBar".to_owned(); 235 | assert_eq!(to_camel_case(&convertable_string), expected) 236 | } 237 | 238 | #[test] 239 | fn from_sentence_case() { 240 | let convertable_string: String = "Foo bar".to_owned(); 241 | let expected: String = "fooBar".to_owned(); 242 | assert_eq!(to_camel_case(&convertable_string), expected) 243 | } 244 | 245 | #[test] 246 | fn from_title_case() { 247 | let convertable_string: String = "Foo Bar".to_owned(); 248 | let expected: String = "fooBar".to_owned(); 249 | assert_eq!(to_camel_case(&convertable_string), expected) 250 | } 251 | 252 | #[test] 253 | fn from_train_case() { 254 | let convertable_string: String = "Foo-Bar".to_owned(); 255 | let expected: String = "fooBar".to_owned(); 256 | assert_eq!(to_camel_case(&convertable_string), expected) 257 | } 258 | 259 | #[test] 260 | fn from_screaming_snake_case() { 261 | let convertable_string: String = "FOO_BAR".to_owned(); 262 | let expected: String = "fooBar".to_owned(); 263 | assert_eq!(to_camel_case(&convertable_string), expected) 264 | } 265 | 266 | #[test] 267 | fn from_snake_case() { 268 | let convertable_string: String = "foo_bar".to_owned(); 269 | let expected: String = "fooBar".to_owned(); 270 | assert_eq!(to_camel_case(&convertable_string), expected) 271 | } 272 | 273 | #[test] 274 | fn from_case_with_loads_of_space() { 275 | let convertable_string: String = "foo bar".to_owned(); 276 | let expected: String = "fooBar".to_owned(); 277 | assert_eq!(to_camel_case(&convertable_string), expected) 278 | } 279 | 280 | #[test] 281 | fn a_name_with_a_dot() { 282 | let convertable_string: String = "Robert C. Martin".to_owned(); 283 | let expected: String = "robertCMartin".to_owned(); 284 | assert_eq!(to_camel_case(&convertable_string), expected) 285 | } 286 | 287 | #[test] 288 | fn random_text_with_bad_chars() { 289 | let convertable_string: String = "Random text with *(bad) chars".to_owned(); 290 | let expected: String = "randomTextWithBadChars".to_owned(); 291 | assert_eq!(to_camel_case(&convertable_string), expected) 292 | } 293 | 294 | #[test] 295 | fn trailing_bad_chars() { 296 | let convertable_string: String = "trailing bad_chars*(()())".to_owned(); 297 | let expected: String = "trailingBadChars".to_owned(); 298 | assert_eq!(to_camel_case(&convertable_string), expected) 299 | } 300 | 301 | #[test] 302 | fn leading_bad_chars() { 303 | let convertable_string: String = "-!#$%leading bad chars".to_owned(); 304 | let expected: String = "leadingBadChars".to_owned(); 305 | assert_eq!(to_camel_case(&convertable_string), expected) 306 | } 307 | 308 | #[test] 309 | fn wrapped_in_bad_chars() { 310 | let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<>><>))".to_owned(); 311 | let expected: String = "wrappedInBadChars".to_owned(); 312 | assert_eq!(to_camel_case(&convertable_string), expected) 313 | } 314 | 315 | #[test] 316 | fn has_a_sign() { 317 | let convertable_string: String = "has a + sign".to_owned(); 318 | let expected: String = "hasASign".to_owned(); 319 | assert_eq!(to_camel_case(&convertable_string), expected) 320 | } 321 | 322 | #[test] 323 | fn is_correct_from_camel_case() { 324 | let convertable_string: String = "fooBar".to_owned(); 325 | assert_eq!(is_camel_case(&convertable_string), true) 326 | } 327 | 328 | #[test] 329 | fn is_correct_from_pascal_case() { 330 | let convertable_string: String = "FooBar".to_owned(); 331 | assert_eq!(is_camel_case(&convertable_string), false) 332 | } 333 | 334 | #[test] 335 | fn is_correct_from_kebab_case() { 336 | let convertable_string: String = "foo-bar".to_owned(); 337 | assert_eq!(is_camel_case(&convertable_string), false) 338 | } 339 | 340 | #[test] 341 | fn is_correct_from_sentence_case() { 342 | let convertable_string: String = "Foo bar".to_owned(); 343 | assert_eq!(is_camel_case(&convertable_string), false) 344 | } 345 | 346 | #[test] 347 | fn is_correct_from_title_case() { 348 | let convertable_string: String = "Foo Bar".to_owned(); 349 | assert_eq!(is_camel_case(&convertable_string), false) 350 | } 351 | 352 | #[test] 353 | fn is_correct_from_train_case() { 354 | let convertable_string: String = "Foo-Bar".to_owned(); 355 | assert_eq!(is_camel_case(&convertable_string), false) 356 | } 357 | 358 | #[test] 359 | fn is_correct_from_screaming_snake_case() { 360 | let convertable_string: String = "FOO_BAR".to_owned(); 361 | assert_eq!(is_camel_case(&convertable_string), false) 362 | } 363 | 364 | #[test] 365 | fn is_correct_from_snake_case() { 366 | let convertable_string: String = "foo_bar".to_owned(); 367 | assert_eq!(is_camel_case(&convertable_string), false) 368 | } 369 | } 370 | 371 | -------------------------------------------------------------------------------- /src/cases/case/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | #[allow(unknown_lints)] 3 | #[allow(unused_imports)] 4 | use std::ascii::*; 5 | 6 | pub struct CamelOptions { 7 | pub new_word: bool, 8 | pub last_char: char, 9 | pub first_word: bool, 10 | pub injectable_char: char, 11 | pub has_seperator: bool, 12 | pub inverted: bool, 13 | } 14 | 15 | pub fn to_case_snake_like(convertable_string: &str, replace_with: &str, case: &str) -> String { 16 | let mut first_character: bool = true; 17 | let mut result: String = String::with_capacity(convertable_string.len() * 2); 18 | for char_with_index in trim_right(convertable_string).char_indices() { 19 | if char_is_seperator(&char_with_index.1) { 20 | if !first_character { 21 | first_character = true; 22 | result.push(replace_with.chars().nth(0).unwrap_or('_')); 23 | } 24 | } else if requires_seperator(char_with_index, first_character, &convertable_string) { 25 | first_character = false; 26 | result = snake_like_with_seperator(result, replace_with, &char_with_index.1, case) 27 | } else { 28 | first_character = false; 29 | result = snake_like_no_seperator(result, &char_with_index.1, case) 30 | } 31 | } 32 | result 33 | } 34 | 35 | pub fn to_case_camel_like(convertable_string: &str, camel_options: CamelOptions) -> String { 36 | let mut new_word: bool = camel_options.new_word; 37 | let mut first_word: bool = camel_options.first_word; 38 | let mut last_char: char = camel_options.last_char; 39 | let mut found_real_char: bool = false; 40 | let mut result: String = String::with_capacity(convertable_string.len() * 2); 41 | for character in trim_right(convertable_string).chars() { 42 | if char_is_seperator(&character) && found_real_char { 43 | new_word = true; 44 | } else if !found_real_char && is_not_alphanumeric(character) { 45 | continue; 46 | } else if character.is_numeric() { 47 | found_real_char = true; 48 | new_word = true; 49 | result.push(character); 50 | } else if last_char_lower_current_is_upper_or_new_word(new_word, last_char, character) { 51 | found_real_char = true; 52 | new_word = false; 53 | result = append_on_new_word(result, first_word, character, &camel_options); 54 | first_word = false; 55 | } else { 56 | found_real_char = true; 57 | last_char = character; 58 | result.push(character.to_ascii_lowercase()); 59 | } 60 | } 61 | result 62 | } 63 | 64 | #[inline] 65 | fn append_on_new_word(mut result: String, first_word: bool, character: char, camel_options: &CamelOptions) -> String { 66 | if not_first_word_and_has_seperator(first_word, camel_options.has_seperator) { 67 | result.push(camel_options.injectable_char); 68 | } 69 | if first_word_or_not_inverted(first_word, camel_options.inverted) { 70 | result.push(character.to_ascii_uppercase()); 71 | } else { 72 | result.push(character.to_ascii_lowercase()); 73 | } 74 | result 75 | } 76 | 77 | fn not_first_word_and_has_seperator(first_word: bool, has_seperator: bool) -> bool { 78 | has_seperator && !first_word 79 | } 80 | 81 | fn first_word_or_not_inverted(first_word: bool, inverted: bool) -> bool { 82 | !inverted || first_word 83 | } 84 | 85 | 86 | fn last_char_lower_current_is_upper_or_new_word(new_word: bool, last_char: char, character: char) -> bool{ 87 | new_word || 88 | ((last_char.is_lowercase() && character.is_uppercase()) && 89 | (last_char != ' ')) 90 | } 91 | 92 | fn char_is_seperator(character: &char) -> bool { 93 | is_not_alphanumeric(*character) 94 | } 95 | 96 | fn trim_right(convertable_string: &str) -> &str { 97 | convertable_string.trim_end_matches(is_not_alphanumeric) 98 | } 99 | 100 | fn is_not_alphanumeric(character: char) -> bool { 101 | !character.is_alphanumeric() 102 | } 103 | 104 | #[inline] 105 | fn requires_seperator(char_with_index: (usize, char), first_character: bool, convertable_string: &str) -> bool { 106 | !first_character && 107 | char_is_uppercase(char_with_index.1) && 108 | next_or_previous_char_is_lowercase(convertable_string, char_with_index.0) 109 | } 110 | 111 | #[inline] 112 | fn snake_like_no_seperator(mut accumlator: String, current_char: &char, case: &str) -> String { 113 | if case == "lower" { 114 | accumlator.push(current_char.to_ascii_lowercase()); 115 | accumlator 116 | } else { 117 | accumlator.push(current_char.to_ascii_uppercase()); 118 | accumlator 119 | } 120 | } 121 | 122 | #[inline] 123 | fn snake_like_with_seperator(mut accumlator: String, replace_with: &str, current_char: &char, case: &str) -> String { 124 | if case == "lower" { 125 | accumlator.push(replace_with.chars().nth(0).unwrap_or('_')); 126 | accumlator.push(current_char.to_ascii_lowercase()); 127 | accumlator 128 | } else { 129 | accumlator.push(replace_with.chars().nth(0).unwrap_or('_')); 130 | accumlator.push(current_char.to_ascii_uppercase()); 131 | accumlator 132 | } 133 | } 134 | 135 | fn next_or_previous_char_is_lowercase(convertable_string: &str, char_with_index: usize) -> bool { 136 | convertable_string.chars().nth(char_with_index + 1).unwrap_or('A').is_lowercase() || 137 | convertable_string.chars().nth(char_with_index - 1).unwrap_or('A').is_lowercase() 138 | } 139 | 140 | fn char_is_uppercase(test_char: char) -> bool { 141 | test_char == test_char.to_ascii_uppercase() 142 | } 143 | 144 | #[test] 145 | fn test_trim_bad_chars() { 146 | assert_eq!("abc", trim_right("abc----^")) 147 | } 148 | 149 | #[test] 150 | fn test_trim_bad_chars_when_none_are_bad() { 151 | assert_eq!("abc", trim_right("abc")) 152 | } 153 | 154 | #[test] 155 | fn test_is_not_alphanumeric_on_is_alphanumeric() { 156 | assert!(!is_not_alphanumeric('a')) 157 | } 158 | 159 | #[test] 160 | fn test_is_not_alphanumeric_on_is_not_alphanumeric() { 161 | assert!(is_not_alphanumeric('_')) 162 | } 163 | 164 | 165 | #[test] 166 | fn test_char_is_uppercase_when_it_is() { 167 | assert_eq!(char_is_uppercase('A'), true) 168 | } 169 | 170 | #[test] 171 | fn test_char_is_uppercase_when_it_is_not() { 172 | assert_eq!(char_is_uppercase('a'), false) 173 | } 174 | 175 | #[test] 176 | fn test_next_or_previous_char_is_lowercase_true() { 177 | assert_eq!(next_or_previous_char_is_lowercase("TestWWW", 3), true) 178 | } 179 | 180 | #[test] 181 | fn test_next_or_previous_char_is_lowercase_false() { 182 | assert_eq!(next_or_previous_char_is_lowercase("TestWWW", 5), false) 183 | } 184 | 185 | #[test] 186 | fn snake_like_with_seperator_lowers() { 187 | assert_eq!(snake_like_with_seperator("".to_owned(), "^", &'c', "lower"), "^c".to_string()) 188 | } 189 | 190 | #[test] 191 | fn snake_like_with_seperator_upper() { 192 | assert_eq!(snake_like_with_seperator("".to_owned(), "^", &'c', "upper"), "^C".to_string()) 193 | } 194 | 195 | #[test] 196 | fn snake_like_no_seperator_lower() { 197 | assert_eq!(snake_like_no_seperator("".to_owned(), &'C', "lower"), "c".to_string()) 198 | } 199 | 200 | #[test] 201 | fn snake_like_no_seperator_upper() { 202 | assert_eq!(snake_like_no_seperator("".to_owned(), &'c', "upper"), "C".to_string()) 203 | } 204 | 205 | #[test] 206 | fn requires_seperator_upper_not_first_wrap_is_safe_current_upper() { 207 | assert_eq!(requires_seperator((2, 'C'), false, "test"), true) 208 | } 209 | 210 | #[test] 211 | fn requires_seperator_upper_not_first_wrap_is_safe_current_lower() { 212 | assert_eq!(requires_seperator((2, 'c'), false, "test"), false) 213 | } 214 | 215 | #[test] 216 | fn requires_seperator_upper_first_wrap_is_safe_current_upper() { 217 | assert_eq!(requires_seperator((0, 'T'), true, "Test"), false) 218 | } 219 | 220 | #[test] 221 | fn requires_seperator_upper_first_wrap_is_safe_current_lower() { 222 | assert_eq!(requires_seperator((0, 't'), true, "Test"), false) 223 | } 224 | 225 | #[test] 226 | fn requires_seperator_upper_first_wrap_is_safe_current_lower_next_is_too() { 227 | assert_eq!(requires_seperator((0, 't'), true, "test"), false) 228 | } 229 | 230 | #[test] 231 | fn test_char_is_seperator_dash() { 232 | assert_eq!(char_is_seperator(&'-'), true) 233 | } 234 | 235 | #[test] 236 | fn test_char_is_seperator_underscore() { 237 | assert_eq!(char_is_seperator(&'_'), true) 238 | } 239 | 240 | #[test] 241 | fn test_char_is_seperator_space() { 242 | assert_eq!(char_is_seperator(&' '), true) 243 | } 244 | 245 | #[test] 246 | fn test_char_is_seperator_when_not() { 247 | assert_eq!(char_is_seperator(&'A'), false) 248 | } 249 | 250 | #[test] 251 | fn test_last_char_lower_current_is_upper_or_new_word_with_new_word() { 252 | assert_eq!(last_char_lower_current_is_upper_or_new_word(true, ' ', '-'), true) 253 | } 254 | 255 | #[test] 256 | fn test_last_char_lower_current_is_upper_or_new_word_last_char_space() { 257 | assert_eq!(last_char_lower_current_is_upper_or_new_word(false, ' ', '-'), false) 258 | } 259 | 260 | #[test] 261 | fn test_last_char_lower_current_is_upper_or_new_word_last_char_lower_current_upper() { 262 | assert_eq!(last_char_lower_current_is_upper_or_new_word(false, 'a', 'A'), true) 263 | } 264 | 265 | #[test] 266 | fn test_last_char_lower_current_is_upper_or_new_word_last_char_upper_current_upper() { 267 | assert_eq!(last_char_lower_current_is_upper_or_new_word(false, 'A', 'A'), false) 268 | } 269 | 270 | #[test] 271 | fn test_last_char_lower_current_is_upper_or_new_word_last_char_upper_current_lower() { 272 | assert_eq!(last_char_lower_current_is_upper_or_new_word(false, 'A', 'a'), false) 273 | } 274 | 275 | #[test] 276 | fn test_first_word_or_not_inverted_with_first_word() { 277 | assert_eq!(first_word_or_not_inverted(true, false), true) 278 | } 279 | 280 | #[test] 281 | fn test_first_word_or_not_inverted_not_first_word_not_inverted() { 282 | assert_eq!(first_word_or_not_inverted(false, false), true) 283 | } 284 | 285 | #[test] 286 | fn test_first_word_or_not_inverted_not_first_word_is_inverted() { 287 | assert_eq!(first_word_or_not_inverted(false, true), false) 288 | } 289 | 290 | #[test] 291 | fn test_not_first_word_and_has_seperator_is_first_and_not_seperator() { 292 | assert_eq!(not_first_word_and_has_seperator(true, false), false) 293 | } 294 | 295 | #[test] 296 | fn test_not_first_word_and_has_seperator_not_first_and_not_seperator() { 297 | assert_eq!(not_first_word_and_has_seperator(false, false), false) 298 | } 299 | 300 | #[test] 301 | fn test_not_first_word_and_has_seperator_not_first_and_has_seperator() { 302 | assert_eq!(not_first_word_and_has_seperator(false, true), true) 303 | } 304 | -------------------------------------------------------------------------------- /src/cases/classcase/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | use cases::case::*; 3 | #[cfg(feature = "heavyweight")] 4 | use string::singularize::to_singular; 5 | #[cfg(feature = "heavyweight")] 6 | /// Converts a `&str` to `ClassCase` `String` 7 | /// 8 | /// ``` 9 | /// use inflector::cases::classcase::to_class_case; 10 | /// let mock_string: &str = "FooBar"; 11 | /// let expected_string: String = "FooBar".to_string(); 12 | /// let asserted_string: String = to_class_case(mock_string); 13 | /// assert!(asserted_string == expected_string); 14 | /// 15 | /// ``` 16 | /// 17 | /// ``` 18 | /// use inflector::cases::classcase::to_class_case; 19 | /// let mock_string: &str = "FooBars"; 20 | /// let expected_string: String = "FooBar".to_string(); 21 | /// let asserted_string: String = to_class_case(mock_string); 22 | /// assert!(asserted_string == expected_string); 23 | /// 24 | /// ``` 25 | /// 26 | /// ``` 27 | /// use inflector::cases::classcase::to_class_case; 28 | /// let mock_string: &str = "Foo Bar"; 29 | /// let expected_string: String = "FooBar".to_string(); 30 | /// let asserted_string: String = to_class_case(mock_string); 31 | /// assert!(asserted_string == expected_string); 32 | /// 33 | /// ``` 34 | /// 35 | /// ``` 36 | /// use inflector::cases::classcase::to_class_case; 37 | /// let mock_string: &str = "foo-bar"; 38 | /// let expected_string: String = "FooBar".to_string(); 39 | /// let asserted_string: String = to_class_case(mock_string); 40 | /// assert!(asserted_string == expected_string); 41 | /// 42 | /// ``` 43 | /// 44 | /// ``` 45 | /// use inflector::cases::classcase::to_class_case; 46 | /// let mock_string: &str = "fooBar"; 47 | /// let expected_string: String = "FooBar".to_string(); 48 | /// let asserted_string: String = to_class_case(mock_string); 49 | /// assert!(asserted_string == expected_string); 50 | /// 51 | /// ``` 52 | /// 53 | /// ``` 54 | /// use inflector::cases::classcase::to_class_case; 55 | /// let mock_string: &str = "FOO_BAR"; 56 | /// let expected_string: String = "FooBar".to_string(); 57 | /// let asserted_string: String = to_class_case(mock_string); 58 | /// assert!(asserted_string == expected_string); 59 | /// 60 | /// ``` 61 | /// 62 | /// ``` 63 | /// use inflector::cases::classcase::to_class_case; 64 | /// let mock_string: &str = "foo_bar"; 65 | /// let expected_string: String = "FooBar".to_string(); 66 | /// let asserted_string: String = to_class_case(mock_string); 67 | /// assert!(asserted_string == expected_string); 68 | /// 69 | /// ``` 70 | /// 71 | /// ``` 72 | /// use inflector::cases::classcase::to_class_case; 73 | /// let mock_string: &str = "foo_bars"; 74 | /// let expected_string: String = "FooBar".to_string(); 75 | /// let asserted_string: String = to_class_case(mock_string); 76 | /// assert!(asserted_string == expected_string); 77 | /// 78 | /// ``` 79 | /// 80 | /// ``` 81 | /// use inflector::cases::classcase::to_class_case; 82 | /// let mock_string: &str = "Foo bar"; 83 | /// let expected_string: String = "FooBar".to_string(); 84 | /// let asserted_string: String = to_class_case(mock_string); 85 | /// assert!(asserted_string == expected_string); 86 | /// 87 | /// ``` 88 | pub fn to_class_case(non_class_case_string: &str) -> String { 89 | let options = CamelOptions { 90 | new_word: true, 91 | last_char: ' ', 92 | first_word: false, 93 | injectable_char: ' ', 94 | has_seperator: false, 95 | inverted: false, 96 | }; 97 | let class_plural = to_case_camel_like(non_class_case_string, options); 98 | let split: (&str, &str) = 99 | class_plural.split_at(class_plural.rfind(char::is_uppercase).unwrap_or(0)); 100 | format!("{}{}", split.0, to_singular(split.1)) 101 | } 102 | 103 | #[cfg(feature = "heavyweight")] 104 | /// Determines if a `&str` is `ClassCase` `bool` 105 | /// 106 | /// ``` 107 | /// use inflector::cases::classcase::is_class_case; 108 | /// let mock_string: &str = "Foo"; 109 | /// let asserted_bool: bool = is_class_case(mock_string); 110 | /// assert!(asserted_bool == true); 111 | /// 112 | /// ``` 113 | /// 114 | /// ``` 115 | /// use inflector::cases::classcase::is_class_case; 116 | /// let mock_string: &str = "foo"; 117 | /// let asserted_bool: bool = is_class_case(mock_string); 118 | /// assert!(asserted_bool == false); 119 | /// 120 | /// ``` 121 | /// 122 | /// ``` 123 | /// use inflector::cases::classcase::is_class_case; 124 | /// let mock_string: &str = "FooBarIsAReallyReallyLongStrings"; 125 | /// let asserted_bool: bool = is_class_case(mock_string); 126 | /// assert!(asserted_bool == false); 127 | /// 128 | /// ``` 129 | /// 130 | /// 131 | /// ``` 132 | /// use inflector::cases::classcase::is_class_case; 133 | /// let mock_string: &str = "FooBarIsAReallyReallyLongString"; 134 | /// let asserted_bool: bool = is_class_case(mock_string); 135 | /// assert!(asserted_bool == true); 136 | /// 137 | /// ``` 138 | /// 139 | /// ``` 140 | /// use inflector::cases::classcase::is_class_case; 141 | /// let mock_string: &str = "foo-bar-string-that-is-really-really-long"; 142 | /// let asserted_bool: bool = is_class_case(mock_string); 143 | /// assert!(asserted_bool == false); 144 | /// 145 | /// ``` 146 | /// 147 | /// ``` 148 | /// use inflector::cases::classcase::is_class_case; 149 | /// let mock_string: &str = "foo_bar_is_a_really_really_long_strings"; 150 | /// let asserted_bool: bool = is_class_case(mock_string); 151 | /// assert!(asserted_bool == false); 152 | /// 153 | /// ``` 154 | /// 155 | /// 156 | /// ``` 157 | /// use inflector::cases::classcase::is_class_case; 158 | /// let mock_string: &str = "fooBarIsAReallyReallyLongString"; 159 | /// let asserted_bool: bool = is_class_case(mock_string); 160 | /// assert!(asserted_bool == false); 161 | /// 162 | /// ``` 163 | /// 164 | /// ``` 165 | /// use inflector::cases::classcase::is_class_case; 166 | /// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG"; 167 | /// let asserted_bool: bool = is_class_case(mock_string); 168 | /// assert!(asserted_bool == false); 169 | /// 170 | /// ``` 171 | /// 172 | /// ``` 173 | /// use inflector::cases::classcase::is_class_case; 174 | /// let mock_string: &str = "foo_bar_string_that_is_really_really_long"; 175 | /// let asserted_bool: bool = is_class_case(mock_string); 176 | /// assert!(asserted_bool == false); 177 | /// 178 | /// ``` 179 | /// 180 | /// ``` 181 | /// use inflector::cases::classcase::is_class_case; 182 | /// let mock_string: &str = "Foo bar string that is really really long"; 183 | /// let asserted_bool: bool = is_class_case(mock_string); 184 | /// assert!(asserted_bool == false); 185 | /// 186 | /// ``` 187 | /// 188 | /// ``` 189 | /// use inflector::cases::classcase::is_class_case; 190 | /// let mock_string: &str = "Foo Bar Is A Really Really Long String"; 191 | /// let asserted_bool: bool = is_class_case(mock_string); 192 | /// assert!(asserted_bool == false); 193 | /// 194 | /// ``` 195 | pub fn is_class_case(test_string: &str) -> bool { 196 | to_class_case(&test_string.clone()) == test_string 197 | } 198 | 199 | #[cfg(all(feature = "unstable", test))] 200 | #[cfg(feature = "heavyweight")] 201 | mod benchmarks { 202 | extern crate test; 203 | use self::test::Bencher; 204 | 205 | #[bench] 206 | fn bench_class_case(b: &mut Bencher) { 207 | b.iter(|| super::to_class_case("Foo bar")); 208 | } 209 | 210 | #[bench] 211 | fn bench_is_class(b: &mut Bencher) { 212 | b.iter(|| super::is_class_case("Foo bar")); 213 | } 214 | 215 | #[bench] 216 | fn bench_class_from_snake(b: &mut Bencher) { 217 | b.iter(|| super::to_class_case("foo_bar")); 218 | } 219 | } 220 | 221 | #[cfg(test)] 222 | #[cfg(feature = "heavyweight")] 223 | mod tests { 224 | use ::to_class_case; 225 | use ::is_class_case; 226 | 227 | #[test] 228 | fn from_camel_case() { 229 | let convertable_string: String = "fooBar".to_owned(); 230 | let expected: String = "FooBar".to_owned(); 231 | assert_eq!(to_class_case(&convertable_string), expected) 232 | } 233 | 234 | #[test] 235 | fn from_pascal_case() { 236 | let convertable_string: String = "FooBar".to_owned(); 237 | let expected: String = "FooBar".to_owned(); 238 | assert_eq!(to_class_case(&convertable_string), expected) 239 | } 240 | 241 | #[test] 242 | fn from_kebab_case() { 243 | let convertable_string: String = "foo-bar".to_owned(); 244 | let expected: String = "FooBar".to_owned(); 245 | assert_eq!(to_class_case(&convertable_string), expected) 246 | } 247 | 248 | #[test] 249 | fn from_sentence_case() { 250 | let convertable_string: String = "Foo bar".to_owned(); 251 | let expected: String = "FooBar".to_owned(); 252 | assert_eq!(to_class_case(&convertable_string), expected) 253 | } 254 | 255 | #[test] 256 | fn from_title_case() { 257 | let convertable_string: String = "Foo Bar".to_owned(); 258 | let expected: String = "FooBar".to_owned(); 259 | assert_eq!(to_class_case(&convertable_string), expected) 260 | } 261 | 262 | #[test] 263 | fn from_train_case() { 264 | let convertable_string: String = "Foo-Bar".to_owned(); 265 | let expected: String = "FooBar".to_owned(); 266 | assert_eq!(to_class_case(&convertable_string), expected) 267 | } 268 | 269 | #[test] 270 | fn from_screaming_class_case() { 271 | let convertable_string: String = "FOO_BAR".to_owned(); 272 | let expected: String = "FooBar".to_owned(); 273 | assert_eq!(to_class_case(&convertable_string), expected) 274 | } 275 | 276 | #[test] 277 | fn from_snake_case() { 278 | let convertable_string: String = "foo_bar".to_owned(); 279 | let expected: String = "FooBar".to_owned(); 280 | assert_eq!(to_class_case(&convertable_string), expected) 281 | } 282 | 283 | #[test] 284 | fn from_table_case() { 285 | let convertable_string: String = "foo_bars".to_owned(); 286 | let expected: String = "FooBar".to_owned(); 287 | assert_eq!(to_class_case(&convertable_string), expected) 288 | } 289 | 290 | #[test] 291 | fn from_case_with_loads_of_space() { 292 | let convertable_string: String = "foo bar".to_owned(); 293 | let expected: String = "FooBar".to_owned(); 294 | assert_eq!(to_class_case(&convertable_string), expected) 295 | } 296 | 297 | #[test] 298 | fn a_name_with_a_dot() { 299 | let convertable_string: String = "Robert C. Martin".to_owned(); 300 | let expected: String = "RobertCMartin".to_owned(); 301 | assert_eq!(to_class_case(&convertable_string), expected) 302 | } 303 | 304 | #[test] 305 | fn random_text_with_bad_chars() { 306 | let convertable_string: String = "Random text with *(bad) chars".to_owned(); 307 | let expected: String = "RandomTextWithBadChar".to_owned(); 308 | assert_eq!(to_class_case(&convertable_string), expected) 309 | } 310 | 311 | #[test] 312 | fn trailing_bad_chars() { 313 | let convertable_string: String = "trailing bad_chars*(()())".to_owned(); 314 | let expected: String = "TrailingBadChar".to_owned(); 315 | assert_eq!(to_class_case(&convertable_string), expected) 316 | } 317 | 318 | #[test] 319 | fn leading_bad_chars() { 320 | let convertable_string: String = "-!#$%leading bad chars".to_owned(); 321 | let expected: String = "LeadingBadChar".to_owned(); 322 | assert_eq!(to_class_case(&convertable_string), expected) 323 | } 324 | 325 | #[test] 326 | fn wrapped_in_bad_chars() { 327 | let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<>><>))".to_owned(); 328 | let expected: String = "WrappedInBadChar".to_owned(); 329 | assert_eq!(to_class_case(&convertable_string), expected) 330 | } 331 | 332 | #[test] 333 | fn has_a_sign() { 334 | let convertable_string: String = "has a + sign".to_owned(); 335 | let expected: String = "HasASign".to_owned(); 336 | assert_eq!(to_class_case(&convertable_string), expected) 337 | } 338 | 339 | #[test] 340 | fn is_correct_from_class_case() { 341 | let convertable_string: String = "fooBar".to_owned(); 342 | assert_eq!(is_class_case(&convertable_string), false) 343 | } 344 | 345 | #[test] 346 | fn is_correct_from_pascal_case() { 347 | let convertable_string: String = "FooBar".to_owned(); 348 | assert_eq!(is_class_case(&convertable_string), true) 349 | } 350 | 351 | #[test] 352 | fn is_correct_from_kebab_case() { 353 | let convertable_string: String = "foo-bar".to_owned(); 354 | assert_eq!(is_class_case(&convertable_string), false) 355 | } 356 | 357 | #[test] 358 | fn is_correct_from_sentence_case() { 359 | let convertable_string: String = "Foo bar".to_owned(); 360 | assert_eq!(is_class_case(&convertable_string), false) 361 | } 362 | 363 | #[test] 364 | fn is_correct_from_title_case() { 365 | let convertable_string: String = "Foo Bar".to_owned(); 366 | assert_eq!(is_class_case(&convertable_string), false) 367 | } 368 | 369 | #[test] 370 | fn is_correct_from_train_case() { 371 | let convertable_string: String = "Foo-Bar".to_owned(); 372 | assert_eq!(is_class_case(&convertable_string), false) 373 | } 374 | 375 | #[test] 376 | fn is_correct_from_screaming_snake_case() { 377 | let convertable_string: String = "FOO_BAR".to_owned(); 378 | assert_eq!(is_class_case(&convertable_string), false) 379 | } 380 | 381 | #[test] 382 | fn is_correct_from_snake_case() { 383 | let convertable_string: String = "foo_bar".to_owned(); 384 | assert_eq!(is_class_case(&convertable_string), false) 385 | } 386 | 387 | #[test] 388 | fn is_correct_from_table_case() { 389 | let convertable_string: String = "FooBar".to_owned(); 390 | assert_eq!(is_class_case(&convertable_string), true) 391 | } 392 | } 393 | 394 | -------------------------------------------------------------------------------- /src/cases/kebabcase/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | use cases::case::*; 3 | /// Determines if a `&str` is `kebab-case` 4 | /// 5 | /// ``` 6 | /// use inflector::cases::kebabcase::is_kebab_case; 7 | /// let mock_string: &str = "foo-bar-string-that-is-really-really-long"; 8 | /// let asserted_bool: bool = is_kebab_case(mock_string); 9 | /// assert!(asserted_bool == true); 10 | /// 11 | /// ``` 12 | /// 13 | /// ``` 14 | /// use inflector::cases::kebabcase::is_kebab_case; 15 | /// let mock_string: &str = "FooBarIsAReallyReallyLongString"; 16 | /// let asserted_bool: bool = is_kebab_case(mock_string); 17 | /// assert!(asserted_bool == false); 18 | /// 19 | /// ``` 20 | /// 21 | /// ``` 22 | /// use inflector::cases::kebabcase::is_kebab_case; 23 | /// let mock_string: &str = "fooBarIsAReallyReallyLongString"; 24 | /// let asserted_bool: bool = is_kebab_case(mock_string); 25 | /// assert!(asserted_bool == false); 26 | /// 27 | /// ``` 28 | /// 29 | /// ``` 30 | /// use inflector::cases::kebabcase::is_kebab_case; 31 | /// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG"; 32 | /// let asserted_bool: bool = is_kebab_case(mock_string); 33 | /// assert!(asserted_bool == false); 34 | /// 35 | /// ``` 36 | /// 37 | /// ``` 38 | /// use inflector::cases::kebabcase::is_kebab_case; 39 | /// let mock_string: &str = "foo_bar_string_that_is_really_really_long"; 40 | /// let asserted_bool: bool = is_kebab_case(mock_string); 41 | /// assert!(asserted_bool == false); 42 | /// 43 | /// ``` 44 | /// 45 | /// ``` 46 | /// use inflector::cases::kebabcase::is_kebab_case; 47 | /// let mock_string: &str = "Foo bar string that is really really long"; 48 | /// let asserted_bool: bool = is_kebab_case(mock_string); 49 | /// assert!(asserted_bool == false); 50 | /// 51 | /// ``` 52 | /// 53 | /// ``` 54 | /// use inflector::cases::kebabcase::is_kebab_case; 55 | /// let mock_string: &str = "Foo Bar Is A Really Really Long String"; 56 | /// let asserted_bool: bool = is_kebab_case(mock_string); 57 | /// assert!(asserted_bool == false); 58 | /// 59 | /// ``` 60 | pub fn is_kebab_case(test_string: &str) -> bool { 61 | test_string == to_kebab_case(test_string.clone()) 62 | } 63 | 64 | /// Converts a `&str` to `kebab-case` `String` 65 | /// 66 | /// ``` 67 | /// use inflector::cases::kebabcase::to_kebab_case; 68 | /// let mock_string: &str = "foo-bar"; 69 | /// let expected_string: String = "foo-bar".to_string(); 70 | /// let asserted_string: String = to_kebab_case(mock_string); 71 | /// assert!(asserted_string == expected_string); 72 | /// 73 | /// ``` 74 | /// 75 | /// ``` 76 | /// use inflector::cases::kebabcase::to_kebab_case; 77 | /// let mock_string: &str = "FOO_BAR"; 78 | /// let expected_string: String = "foo-bar".to_string(); 79 | /// let asserted_string: String = to_kebab_case(mock_string); 80 | /// assert!(asserted_string == expected_string); 81 | /// 82 | /// ``` 83 | /// 84 | /// ``` 85 | /// use inflector::cases::kebabcase::to_kebab_case; 86 | /// let mock_string: &str = "foo_bar"; 87 | /// let expected_string: String = "foo-bar".to_string(); 88 | /// let asserted_string: String = to_kebab_case(mock_string); 89 | /// assert!(asserted_string == expected_string); 90 | /// 91 | /// ``` 92 | /// 93 | /// ``` 94 | /// use inflector::cases::kebabcase::to_kebab_case; 95 | /// let mock_string: &str = "Foo Bar"; 96 | /// let expected_string: String = "foo-bar".to_string(); 97 | /// let asserted_string: String = to_kebab_case(mock_string); 98 | /// assert!(asserted_string == expected_string); 99 | /// 100 | /// ``` 101 | /// 102 | /// ``` 103 | /// use inflector::cases::kebabcase::to_kebab_case; 104 | /// let mock_string: &str = "Foo bar"; 105 | /// let expected_string: String = "foo-bar".to_string(); 106 | /// let asserted_string: String = to_kebab_case(mock_string); 107 | /// assert!(asserted_string == expected_string); 108 | /// 109 | /// ``` 110 | /// 111 | /// ``` 112 | /// use inflector::cases::kebabcase::to_kebab_case; 113 | /// let mock_string: &str = "FooBar"; 114 | /// let expected_string: String = "foo-bar".to_string(); 115 | /// let asserted_string: String = to_kebab_case(mock_string); 116 | /// assert!(asserted_string == expected_string); 117 | /// 118 | /// ``` 119 | /// 120 | /// ``` 121 | /// use inflector::cases::kebabcase::to_kebab_case; 122 | /// let mock_string: &str = "fooBar"; 123 | /// let expected_string: String = "foo-bar".to_string(); 124 | /// let asserted_string: String = to_kebab_case(mock_string); 125 | /// assert!(asserted_string == expected_string); 126 | /// 127 | /// ``` 128 | pub fn to_kebab_case(non_kebab_case_string: &str) -> String { 129 | to_case_snake_like(non_kebab_case_string, "-", "lower") 130 | } 131 | 132 | #[cfg(all(feature = "unstable", test))] 133 | mod benchmarks { 134 | extern crate test; 135 | use self::test::Bencher; 136 | 137 | #[bench] 138 | fn bench_kebab(b: &mut Bencher) { 139 | b.iter(|| super::to_kebab_case("Foo bar")); 140 | } 141 | 142 | #[bench] 143 | fn bench_is_kebab(b: &mut Bencher) { 144 | b.iter(|| super::is_kebab_case("Foo bar")); 145 | } 146 | 147 | #[bench] 148 | fn bench_kebab_from_snake(b: &mut Bencher) { 149 | b.iter(|| super::to_kebab_case("test_test_test")); 150 | } 151 | } 152 | 153 | #[cfg(test)] 154 | mod tests { 155 | use ::to_kebab_case; 156 | use ::is_kebab_case; 157 | 158 | #[test] 159 | fn from_camel_case() { 160 | let convertable_string: String = "fooBar".to_owned(); 161 | let expected: String = "foo-bar".to_owned(); 162 | assert_eq!(to_kebab_case(&convertable_string), expected) 163 | } 164 | 165 | #[test] 166 | fn from_pascal_case() { 167 | let convertable_string: String = "FooBar".to_owned(); 168 | let expected: String = "foo-bar".to_owned(); 169 | assert_eq!(to_kebab_case(&convertable_string), expected) 170 | } 171 | 172 | #[test] 173 | fn from_kebab_case() { 174 | let convertable_string: String = "foo-bar".to_owned(); 175 | let expected: String = "foo-bar".to_owned(); 176 | assert_eq!(to_kebab_case(&convertable_string), expected) 177 | } 178 | 179 | #[test] 180 | fn from_sentence_case() { 181 | let convertable_string: String = "Foo bar".to_owned(); 182 | let expected: String = "foo-bar".to_owned(); 183 | assert_eq!(to_kebab_case(&convertable_string), expected) 184 | } 185 | 186 | #[test] 187 | fn from_title_case() { 188 | let convertable_string: String = "Foo Bar".to_owned(); 189 | let expected: String = "foo-bar".to_owned(); 190 | assert_eq!(to_kebab_case(&convertable_string), expected) 191 | } 192 | 193 | #[test] 194 | fn from_train_case() { 195 | let convertable_string: String = "Foo-Bar".to_owned(); 196 | let expected: String = "foo-bar".to_owned(); 197 | assert_eq!(to_kebab_case(&convertable_string), expected) 198 | } 199 | 200 | #[test] 201 | fn from_screaming_snake_case() { 202 | let convertable_string: String = "FOO_BAR".to_owned(); 203 | let expected: String = "foo-bar".to_owned(); 204 | assert_eq!(to_kebab_case(&convertable_string), expected) 205 | } 206 | 207 | #[test] 208 | fn from_snake_case() { 209 | let convertable_string: String = "foo_bar".to_owned(); 210 | let expected: String = "foo-bar".to_owned(); 211 | assert_eq!(to_kebab_case(&convertable_string), expected) 212 | } 213 | 214 | #[test] 215 | fn is_correct_from_camel_case() { 216 | let convertable_string: String = "fooBar".to_owned(); 217 | assert_eq!(is_kebab_case(&convertable_string), false) 218 | } 219 | 220 | #[test] 221 | fn is_correct_from_pascal_case() { 222 | let convertable_string: String = "FooBar".to_owned(); 223 | assert_eq!(is_kebab_case(&convertable_string), false) 224 | } 225 | 226 | #[test] 227 | fn is_correct_from_kebab_case() { 228 | let convertable_string: String = "foo-bar".to_owned(); 229 | assert_eq!(is_kebab_case(&convertable_string), true) 230 | } 231 | 232 | #[test] 233 | fn is_correct_from_sentence_case() { 234 | let convertable_string: String = "Foo bar".to_owned(); 235 | assert_eq!(is_kebab_case(&convertable_string), false) 236 | } 237 | 238 | #[test] 239 | fn is_correct_from_title_case() { 240 | let convertable_string: String = "Foo Bar".to_owned(); 241 | assert_eq!(is_kebab_case(&convertable_string), false) 242 | } 243 | 244 | #[test] 245 | fn is_correct_from_train_case() { 246 | let convertable_string: String = "Foo-Bar".to_owned(); 247 | assert_eq!(is_kebab_case(&convertable_string), false) 248 | } 249 | 250 | #[test] 251 | fn is_correct_from_screaming_snake_case() { 252 | let convertable_string: String = "FOO_BAR".to_owned(); 253 | assert_eq!(is_kebab_case(&convertable_string), false) 254 | } 255 | 256 | #[test] 257 | fn is_correct_from_snake_case() { 258 | let convertable_string: String = "foo_bar".to_owned(); 259 | assert_eq!(is_kebab_case(&convertable_string), false) 260 | } 261 | } 262 | 263 | -------------------------------------------------------------------------------- /src/cases/mod.rs: -------------------------------------------------------------------------------- 1 | mod case; 2 | /// Provides conversion to and detection of class case strings. 3 | /// 4 | /// This version singularizes strings. 5 | /// 6 | /// Example string `ClassCase` 7 | pub mod classcase; 8 | 9 | /// Provides conversion to and detection of camel case strings. 10 | /// 11 | /// Example string `camelCase` 12 | pub mod camelcase; 13 | 14 | /// Provides conversion to and detection of snake case strings. 15 | /// 16 | /// Example string `snake_case` 17 | pub mod snakecase; 18 | 19 | /// Provides conversion to and detection of screaming snake case strings. 20 | /// 21 | /// Example string `SCREAMING_SNAKE_CASE` 22 | pub mod screamingsnakecase; 23 | 24 | /// Provides conversion to and detection of kebab case strings. 25 | /// 26 | /// Example string `kebab-case` 27 | pub mod kebabcase; 28 | 29 | /// Provides conversion to and detection of train case strings. 30 | /// 31 | /// Example string `Train-Case` 32 | pub mod traincase; 33 | 34 | /// Provides conversion to and detection of sentence case strings. 35 | /// 36 | /// Example string `Sentence case` 37 | pub mod sentencecase; 38 | 39 | /// Provides conversion to and detection of title case strings. 40 | /// 41 | /// Example string `Title Case` 42 | pub mod titlecase; 43 | 44 | /// Provides conversion to and detection of table case strings. 45 | /// 46 | /// Example string `table_cases` 47 | pub mod tablecase; 48 | 49 | /// Provides conversion to pascal case strings. 50 | /// 51 | /// Example string `PascalCase` 52 | pub mod pascalcase; 53 | -------------------------------------------------------------------------------- /src/cases/pascalcase/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | use cases::case::*; 3 | /// Converts a `&str` to pascalCase `String` 4 | /// 5 | /// ``` 6 | /// use inflector::cases::pascalcase::to_pascal_case; 7 | /// let mock_string: &str = "fooBar"; 8 | /// let expected_string: String = "FooBar".to_string(); 9 | /// let asserted_string: String = to_pascal_case(mock_string); 10 | /// assert!(asserted_string == expected_string); 11 | /// 12 | /// ``` 13 | /// ``` 14 | /// use inflector::cases::pascalcase::to_pascal_case; 15 | /// let mock_string: &str = "FOO_BAR"; 16 | /// let expected_string: String = "FooBar".to_string(); 17 | /// let asserted_string: String = to_pascal_case(mock_string); 18 | /// assert!(asserted_string == expected_string); 19 | /// 20 | /// ``` 21 | /// ``` 22 | /// use inflector::cases::pascalcase::to_pascal_case; 23 | /// let mock_string: &str = "Foo Bar"; 24 | /// let expected_string: String = "FooBar".to_string(); 25 | /// let asserted_string: String = to_pascal_case(mock_string); 26 | /// assert!(asserted_string == expected_string); 27 | /// 28 | /// ``` 29 | /// ``` 30 | /// use inflector::cases::pascalcase::to_pascal_case; 31 | /// let mock_string: &str = "foo_bar"; 32 | /// let expected_string: String = "FooBar".to_string(); 33 | /// let asserted_string: String = to_pascal_case(mock_string); 34 | /// assert!(asserted_string == expected_string); 35 | /// 36 | /// ``` 37 | /// ``` 38 | /// use inflector::cases::pascalcase::to_pascal_case; 39 | /// let mock_string: &str = "Foo bar"; 40 | /// let expected_string: String = "FooBar".to_string(); 41 | /// let asserted_string: String = to_pascal_case(mock_string); 42 | /// assert!(asserted_string == expected_string); 43 | /// 44 | /// ``` 45 | /// ``` 46 | /// use inflector::cases::pascalcase::to_pascal_case; 47 | /// let mock_string: &str = "foo-bar"; 48 | /// let expected_string: String = "FooBar".to_string(); 49 | /// let asserted_string: String = to_pascal_case(mock_string); 50 | /// assert!(asserted_string == expected_string); 51 | /// 52 | /// ``` 53 | /// ``` 54 | /// use inflector::cases::pascalcase::to_pascal_case; 55 | /// let mock_string: &str = "FooBar"; 56 | /// let expected_string: String = "FooBar".to_string(); 57 | /// let asserted_string: String = to_pascal_case(mock_string); 58 | /// assert!(asserted_string == expected_string); 59 | /// 60 | /// ``` 61 | /// ``` 62 | /// use inflector::cases::pascalcase::to_pascal_case; 63 | /// let mock_string: &str = "FooBar3"; 64 | /// let expected_string: String = "FooBar3".to_string(); 65 | /// let asserted_string: String = to_pascal_case(mock_string); 66 | /// assert!(asserted_string == expected_string); 67 | /// 68 | /// ``` 69 | pub fn to_pascal_case(non_pascalized_string: &str) -> String { 70 | let options = CamelOptions { 71 | new_word: true, 72 | last_char: ' ', 73 | first_word: false, 74 | injectable_char: ' ', 75 | has_seperator: false, 76 | inverted: false, 77 | }; 78 | to_case_camel_like(non_pascalized_string, options) 79 | } 80 | 81 | /// Determines if a `&str` is pascalCase bool`` 82 | /// 83 | /// ``` 84 | /// use inflector::cases::pascalcase::is_pascal_case; 85 | /// let mock_string: &str = "Foo"; 86 | /// let asserted_bool: bool = is_pascal_case(mock_string); 87 | /// assert!(asserted_bool == true); 88 | /// 89 | /// 90 | /// ``` 91 | /// ``` 92 | /// use inflector::cases::pascalcase::is_pascal_case; 93 | /// let mock_string: &str = "foo"; 94 | /// let asserted_bool: bool = is_pascal_case(mock_string); 95 | /// assert!(asserted_bool == false); 96 | /// 97 | /// 98 | /// ``` 99 | /// ``` 100 | /// use inflector::cases::pascalcase::is_pascal_case; 101 | /// let mock_string: &str = "foo-bar-string-that-is-really-really-long"; 102 | /// let asserted_bool: bool = is_pascal_case(mock_string); 103 | /// assert!(asserted_bool == false); 104 | /// 105 | /// 106 | /// ``` 107 | /// ``` 108 | /// use inflector::cases::pascalcase::is_pascal_case; 109 | /// let mock_string: &str = "FooBarIsAReallyReallyLongString"; 110 | /// let asserted_bool: bool = is_pascal_case(mock_string); 111 | /// assert!(asserted_bool == true); 112 | /// 113 | /// 114 | /// ``` 115 | /// ``` 116 | /// use inflector::cases::pascalcase::is_pascal_case; 117 | /// let mock_string: &str = "FooBarIsAReallyReally3LongString"; 118 | /// let asserted_bool: bool = is_pascal_case(mock_string); 119 | /// assert!(asserted_bool == true); 120 | /// 121 | /// 122 | /// ``` 123 | /// ``` 124 | /// use inflector::cases::pascalcase::is_pascal_case; 125 | /// let mock_string: &str = "FooBarIsAReallyReallyLongString"; 126 | /// let asserted_bool: bool = is_pascal_case(mock_string); 127 | /// assert!(asserted_bool == true); 128 | /// 129 | /// 130 | /// ``` 131 | /// ``` 132 | /// use inflector::cases::pascalcase::is_pascal_case; 133 | /// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG"; 134 | /// let asserted_bool: bool = is_pascal_case(mock_string); 135 | /// assert!(asserted_bool == false); 136 | /// 137 | /// 138 | /// ``` 139 | /// ``` 140 | /// use inflector::cases::pascalcase::is_pascal_case; 141 | /// let mock_string: &str = "foo_bar_string_that_is_really_really_long"; 142 | /// let asserted_bool: bool = is_pascal_case(mock_string); 143 | /// assert!(asserted_bool == false); 144 | /// 145 | /// 146 | /// ``` 147 | /// ``` 148 | /// use inflector::cases::pascalcase::is_pascal_case; 149 | /// let mock_string: &str = "Foo bar string that is really really long"; 150 | /// let asserted_bool: bool = is_pascal_case(mock_string); 151 | /// assert!(asserted_bool == false); 152 | /// 153 | /// 154 | /// ``` 155 | /// ``` 156 | /// use inflector::cases::pascalcase::is_pascal_case; 157 | /// let mock_string: &str = "Foo Bar Is A Really Really Long String"; 158 | /// let asserted_bool: bool = is_pascal_case(mock_string); 159 | /// assert!(asserted_bool == false); 160 | /// ``` 161 | pub fn is_pascal_case(test_string: &str) -> bool { 162 | to_pascal_case(test_string.clone()) == test_string 163 | } 164 | 165 | #[cfg(all(feature = "unstable", test))] 166 | mod benchmarks { 167 | extern crate test; 168 | use self::test::Bencher; 169 | 170 | #[bench] 171 | fn bench_pascal0(b: &mut Bencher) { 172 | b.iter(|| { 173 | let test_string = "Foo bar"; 174 | super::to_pascal_case(test_string) 175 | }); 176 | } 177 | 178 | #[bench] 179 | fn bench_pascal1(b: &mut Bencher) { 180 | b.iter(|| { 181 | let test_string = "foo_bar"; 182 | super::to_pascal_case(test_string) 183 | }); 184 | } 185 | 186 | #[bench] 187 | fn bench_pascal2(b: &mut Bencher) { 188 | b.iter(|| { 189 | let test_string = "fooBar"; 190 | super::to_pascal_case(test_string) 191 | }); 192 | } 193 | 194 | #[bench] 195 | fn bench_is_pascal(b: &mut Bencher) { 196 | b.iter(|| { 197 | let test_string: &str = "Foo bar"; 198 | super::is_pascal_case(test_string) 199 | }); 200 | } 201 | } 202 | 203 | #[cfg(test)] 204 | mod tests { 205 | use ::to_pascal_case; 206 | use ::is_pascal_case; 207 | 208 | #[test] 209 | fn from_camel_case() { 210 | let convertable_string: String = "fooBar".to_owned(); 211 | let expected: String = "FooBar".to_owned(); 212 | assert_eq!(to_pascal_case(&convertable_string), expected) 213 | } 214 | 215 | #[test] 216 | fn from_pascal_case() { 217 | let convertable_string: String = "FooBar".to_owned(); 218 | let expected: String = "FooBar".to_owned(); 219 | assert_eq!(to_pascal_case(&convertable_string), expected) 220 | } 221 | 222 | #[test] 223 | fn from_kebab_case() { 224 | let convertable_string: String = "foo-bar".to_owned(); 225 | let expected: String = "FooBar".to_owned(); 226 | assert_eq!(to_pascal_case(&convertable_string), expected) 227 | } 228 | 229 | #[test] 230 | fn from_sentence_case() { 231 | let convertable_string: String = "Foo bar".to_owned(); 232 | let expected: String = "FooBar".to_owned(); 233 | assert_eq!(to_pascal_case(&convertable_string), expected) 234 | } 235 | 236 | #[test] 237 | fn from_title_case() { 238 | let convertable_string: String = "Foo Bar".to_owned(); 239 | let expected: String = "FooBar".to_owned(); 240 | assert_eq!(to_pascal_case(&convertable_string), expected) 241 | } 242 | 243 | #[test] 244 | fn from_train_case() { 245 | let convertable_string: String = "Foo-Bar".to_owned(); 246 | let expected: String = "FooBar".to_owned(); 247 | assert_eq!(to_pascal_case(&convertable_string), expected) 248 | } 249 | 250 | #[test] 251 | fn from_screaming_snake_case() { 252 | let convertable_string: String = "FOO_BAR".to_owned(); 253 | let expected: String = "FooBar".to_owned(); 254 | assert_eq!(to_pascal_case(&convertable_string), expected) 255 | } 256 | 257 | #[test] 258 | fn from_snake_case() { 259 | let convertable_string: String = "foo_bar".to_owned(); 260 | let expected: String = "FooBar".to_owned(); 261 | assert_eq!(to_pascal_case(&convertable_string), expected) 262 | } 263 | 264 | #[test] 265 | fn from_case_with_loads_of_space() { 266 | let convertable_string: String = "foo bar".to_owned(); 267 | let expected: String = "FooBar".to_owned(); 268 | assert_eq!(to_pascal_case(&convertable_string), expected) 269 | } 270 | 271 | #[test] 272 | fn a_name_with_a_dot() { 273 | let convertable_string: String = "Robert C. Martin".to_owned(); 274 | let expected: String = "RobertCMartin".to_owned(); 275 | assert_eq!(to_pascal_case(&convertable_string), expected) 276 | } 277 | 278 | #[test] 279 | fn random_text_with_bad_chars() { 280 | let convertable_string: String = "Random text with *(bad) chars".to_owned(); 281 | let expected: String = "RandomTextWithBadChars".to_owned(); 282 | assert_eq!(to_pascal_case(&convertable_string), expected) 283 | } 284 | 285 | #[test] 286 | fn trailing_bad_chars() { 287 | let convertable_string: String = "trailing bad_chars*(()())".to_owned(); 288 | let expected: String = "TrailingBadChars".to_owned(); 289 | assert_eq!(to_pascal_case(&convertable_string), expected) 290 | } 291 | 292 | #[test] 293 | fn leading_bad_chars() { 294 | let convertable_string: String = "-!#$%leading bad chars".to_owned(); 295 | let expected: String = "LeadingBadChars".to_owned(); 296 | assert_eq!(to_pascal_case(&convertable_string), expected) 297 | } 298 | 299 | #[test] 300 | fn wrapped_in_bad_chars() { 301 | let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<>><>))".to_owned(); 302 | let expected: String = "WrappedInBadChars".to_owned(); 303 | assert_eq!(to_pascal_case(&convertable_string), expected) 304 | } 305 | 306 | #[test] 307 | fn has_a_sign() { 308 | let convertable_string: String = "has a + sign".to_owned(); 309 | let expected: String = "HasASign".to_owned(); 310 | assert_eq!(to_pascal_case(&convertable_string), expected) 311 | } 312 | 313 | #[test] 314 | fn is_correct_from_camel_case() { 315 | let convertable_string: String = "fooBar".to_owned(); 316 | assert_eq!(is_pascal_case(&convertable_string), false) 317 | } 318 | 319 | #[test] 320 | fn is_correct_from_pascal_case() { 321 | let convertable_string: String = "FooBar".to_owned(); 322 | assert_eq!(is_pascal_case(&convertable_string), true) 323 | } 324 | 325 | #[test] 326 | fn is_correct_from_kebab_case() { 327 | let convertable_string: String = "foo-bar".to_owned(); 328 | assert_eq!(is_pascal_case(&convertable_string), false) 329 | } 330 | 331 | #[test] 332 | fn is_correct_from_sentence_case() { 333 | let convertable_string: String = "Foo bar".to_owned(); 334 | assert_eq!(is_pascal_case(&convertable_string), false) 335 | } 336 | 337 | #[test] 338 | fn is_correct_from_title_case() { 339 | let convertable_string: String = "Foo Bar".to_owned(); 340 | assert_eq!(is_pascal_case(&convertable_string), false) 341 | } 342 | 343 | #[test] 344 | fn is_correct_from_train_case() { 345 | let convertable_string: String = "Foo-Bar".to_owned(); 346 | assert_eq!(is_pascal_case(&convertable_string), false) 347 | } 348 | 349 | #[test] 350 | fn is_correct_from_screaming_snake_case() { 351 | let convertable_string: String = "FOO_BAR".to_owned(); 352 | assert_eq!(is_pascal_case(&convertable_string), false) 353 | } 354 | 355 | #[test] 356 | fn is_correct_from_snake_case() { 357 | let convertable_string: String = "foo_bar".to_owned(); 358 | assert_eq!(is_pascal_case(&convertable_string), false) 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /src/cases/screamingsnakecase/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | use cases::case::*; 3 | /// Converts a `&str` to `SCREAMING_SNAKE_CASE` `String` 4 | /// 5 | /// ``` 6 | /// use inflector::cases::screamingsnakecase::to_screaming_snake_case; 7 | /// let mock_string: &str = "foo_bar"; 8 | /// let expected_string: String = "FOO_BAR".to_string(); 9 | /// let asserted_string: String = to_screaming_snake_case(mock_string); 10 | /// assert!(asserted_string == expected_string); 11 | /// 12 | /// ``` 13 | /// ``` 14 | /// use inflector::cases::screamingsnakecase::to_screaming_snake_case; 15 | /// let mock_string: &str = "HTTP Foo bar"; 16 | /// let expected_string: String = "HTTP_FOO_BAR".to_string(); 17 | /// let asserted_string: String = to_screaming_snake_case(mock_string); 18 | /// assert!(asserted_string == expected_string); 19 | /// 20 | /// ``` 21 | /// ``` 22 | /// use inflector::cases::screamingsnakecase::to_screaming_snake_case; 23 | /// let mock_string: &str = "Foo bar"; 24 | /// let expected_string: String = "FOO_BAR".to_string(); 25 | /// let asserted_string: String = to_screaming_snake_case(mock_string); 26 | /// assert!(asserted_string == expected_string); 27 | /// 28 | /// ``` 29 | /// ``` 30 | /// use inflector::cases::screamingsnakecase::to_screaming_snake_case; 31 | /// let mock_string: &str = "Foo Bar"; 32 | /// let expected_string: String = "FOO_BAR".to_string(); 33 | /// let asserted_string: String = to_screaming_snake_case(mock_string); 34 | /// assert!(asserted_string == expected_string); 35 | /// 36 | /// ``` 37 | /// ``` 38 | /// use inflector::cases::screamingsnakecase::to_screaming_snake_case; 39 | /// let mock_string: &str = "FooBar"; 40 | /// let expected_string: String = "FOO_BAR".to_string(); 41 | /// let asserted_string: String = to_screaming_snake_case(mock_string); 42 | /// assert!(asserted_string == expected_string); 43 | /// 44 | /// ``` 45 | /// ``` 46 | /// use inflector::cases::screamingsnakecase::to_screaming_snake_case; 47 | /// let mock_string: &str = "fooBar"; 48 | /// let expected_string: String = "FOO_BAR".to_string(); 49 | /// let asserted_string: String = to_screaming_snake_case(mock_string); 50 | /// assert!(asserted_string == expected_string); 51 | /// 52 | /// ``` 53 | /// ``` 54 | /// use inflector::cases::screamingsnakecase::to_screaming_snake_case; 55 | /// let mock_string: &str = "fooBar3"; 56 | /// let expected_string: String = "FOO_BAR_3".to_string(); 57 | /// let asserted_string: String = to_screaming_snake_case(mock_string); 58 | /// assert!(asserted_string == expected_string); 59 | /// 60 | /// ``` 61 | pub fn to_screaming_snake_case(non_snake_case_string: &str) -> String { 62 | to_case_snake_like(non_snake_case_string, "_", "upper") 63 | } 64 | 65 | /// Determines of a `&str` is `SCREAMING_SNAKE_CASE` 66 | /// 67 | /// ``` 68 | /// use inflector::cases::screamingsnakecase::is_screaming_snake_case; 69 | /// let mock_string: &str = "Foo bar string that is really really long"; 70 | /// let asserted_bool: bool = is_screaming_snake_case(mock_string); 71 | /// assert!(asserted_bool == false); 72 | /// 73 | /// ``` 74 | /// ``` 75 | /// use inflector::cases::screamingsnakecase::is_screaming_snake_case; 76 | /// let mock_string: &str = "foo-bar-string-that-is-really-really-long"; 77 | /// let asserted_bool: bool = is_screaming_snake_case(mock_string); 78 | /// assert!(asserted_bool == false); 79 | /// 80 | /// ``` 81 | /// ``` 82 | /// use inflector::cases::screamingsnakecase::is_screaming_snake_case; 83 | /// let mock_string: &str = "FooBarIsAReallyReallyLongString"; 84 | /// let asserted_bool: bool = is_screaming_snake_case(mock_string); 85 | /// assert!(asserted_bool == false); 86 | /// 87 | /// ``` 88 | /// ``` 89 | /// use inflector::cases::screamingsnakecase::is_screaming_snake_case; 90 | /// let mock_string: &str = "Foo Bar Is A Really Really Long String"; 91 | /// let asserted_bool: bool = is_screaming_snake_case(mock_string); 92 | /// assert!(asserted_bool == false); 93 | /// 94 | /// ``` 95 | /// ``` 96 | /// use inflector::cases::screamingsnakecase::is_screaming_snake_case; 97 | /// let mock_string: &str = "fooBarIsAReallyReallyLongString"; 98 | /// let asserted_bool: bool = is_screaming_snake_case(mock_string); 99 | /// assert!(asserted_bool == false); 100 | /// 101 | /// ``` 102 | /// ``` 103 | /// use inflector::cases::screamingsnakecase::is_screaming_snake_case; 104 | /// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG"; 105 | /// let asserted_bool: bool = is_screaming_snake_case(mock_string); 106 | /// assert!(asserted_bool == true); 107 | /// 108 | /// ``` 109 | /// ``` 110 | /// use inflector::cases::screamingsnakecase::is_screaming_snake_case; 111 | /// let mock_string: &str = "FOO_BAR1_STRING_THAT_IS_REALLY_REALLY_LONG"; 112 | /// let asserted_bool: bool = is_screaming_snake_case(mock_string); 113 | /// assert!(asserted_bool == true); 114 | /// 115 | /// ``` 116 | /// ``` 117 | /// use inflector::cases::screamingsnakecase::is_screaming_snake_case; 118 | /// let mock_string: &str = "FOO_BAR_1_STRING_THAT_IS_REALLY_REALLY_LONG"; 119 | /// let asserted_bool: bool = is_screaming_snake_case(mock_string); 120 | /// assert!(asserted_bool == true); 121 | /// 122 | /// ``` 123 | pub fn is_screaming_snake_case(test_string: &str) -> bool { 124 | test_string == to_screaming_snake_case(test_string.clone()) 125 | } 126 | 127 | 128 | #[cfg(all(feature = "unstable", test))] 129 | mod benchmarks { 130 | extern crate test; 131 | use self::test::Bencher; 132 | 133 | #[bench] 134 | fn bench_screaming_snake(b: &mut Bencher) { 135 | b.iter(|| super::to_screaming_snake_case("Foo bar")); 136 | } 137 | 138 | #[bench] 139 | fn bench_is_screaming_snake(b: &mut Bencher) { 140 | b.iter(|| super::is_screaming_snake_case("Foo bar")); 141 | } 142 | 143 | } 144 | 145 | #[cfg(test)] 146 | mod tests { 147 | use ::to_screaming_snake_case; 148 | use ::is_screaming_snake_case; 149 | 150 | #[test] 151 | fn from_camel_case() { 152 | let convertable_string: String = "fooBar".to_owned(); 153 | let expected: String = "FOO_BAR".to_owned(); 154 | assert_eq!(to_screaming_snake_case(&convertable_string), expected) 155 | } 156 | 157 | #[test] 158 | fn from_pascal_case() { 159 | let convertable_string: String = "FooBar".to_owned(); 160 | let expected: String = "FOO_BAR".to_owned(); 161 | assert_eq!(to_screaming_snake_case(&convertable_string), expected) 162 | } 163 | 164 | #[test] 165 | fn from_kebab_case() { 166 | let convertable_string: String = "foo-bar".to_owned(); 167 | let expected: String = "FOO_BAR".to_owned(); 168 | assert_eq!(to_screaming_snake_case(&convertable_string), expected) 169 | } 170 | 171 | #[test] 172 | fn from_sentence_case() { 173 | let convertable_string: String = "Foo bar".to_owned(); 174 | let expected: String = "FOO_BAR".to_owned(); 175 | assert_eq!(to_screaming_snake_case(&convertable_string), expected) 176 | } 177 | 178 | #[test] 179 | fn from_title_case() { 180 | let convertable_string: String = "Foo Bar".to_owned(); 181 | let expected: String = "FOO_BAR".to_owned(); 182 | assert_eq!(to_screaming_snake_case(&convertable_string), expected) 183 | } 184 | 185 | #[test] 186 | fn from_train_case() { 187 | let convertable_string: String = "Foo-Bar".to_owned(); 188 | let expected: String = "FOO_BAR".to_owned(); 189 | assert_eq!(to_screaming_snake_case(&convertable_string), expected) 190 | } 191 | 192 | #[test] 193 | fn from_screaming_screaming_snake_case() { 194 | let convertable_string: String = "FOO_BAR".to_owned(); 195 | let expected: String = "FOO_BAR".to_owned(); 196 | assert_eq!(to_screaming_snake_case(&convertable_string), expected) 197 | } 198 | 199 | #[test] 200 | fn from_snake_case() { 201 | let convertable_string: String = "foo_bar".to_owned(); 202 | let expected: String = "FOO_BAR".to_owned(); 203 | assert_eq!(to_screaming_snake_case(&convertable_string), expected) 204 | } 205 | 206 | #[test] 207 | fn is_correct_from_camel_case() { 208 | let convertable_string: String = "fooBar".to_owned(); 209 | assert_eq!(is_screaming_snake_case(&convertable_string), false) 210 | } 211 | 212 | #[test] 213 | fn is_correct_from_pascal_case() { 214 | let convertable_string: String = "FooBar".to_owned(); 215 | assert_eq!(is_screaming_snake_case(&convertable_string), false) 216 | } 217 | 218 | #[test] 219 | fn is_correct_from_kebab_case() { 220 | let convertable_string: String = "foo-bar".to_owned(); 221 | assert_eq!(is_screaming_snake_case(&convertable_string), false) 222 | } 223 | 224 | #[test] 225 | fn is_correct_from_sentence_case() { 226 | let convertable_string: String = "Foo bar".to_owned(); 227 | assert_eq!(is_screaming_snake_case(&convertable_string), false) 228 | } 229 | 230 | #[test] 231 | fn is_correct_from_title_case() { 232 | let convertable_string: String = "Foo Bar".to_owned(); 233 | assert_eq!(is_screaming_snake_case(&convertable_string), false) 234 | } 235 | 236 | #[test] 237 | fn is_correct_from_train_case() { 238 | let convertable_string: String = "Foo-Bar".to_owned(); 239 | assert_eq!(is_screaming_snake_case(&convertable_string), false) 240 | } 241 | 242 | #[test] 243 | fn is_correct_from_screaming_screaming_snake_case() { 244 | let convertable_string: String = "FOO_BAR".to_owned(); 245 | assert_eq!(is_screaming_snake_case(&convertable_string), true) 246 | } 247 | 248 | #[test] 249 | fn is_correct_from_snake_case() { 250 | let convertable_string: String = "foo_bar".to_owned(); 251 | assert_eq!(is_screaming_snake_case(&convertable_string), false) 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /src/cases/sentencecase/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | use cases::case::*; 3 | /// Converts a `&str` to `Sentence case` `String` 4 | /// 5 | /// ``` 6 | /// use inflector::cases::sentencecase::to_sentence_case; 7 | /// let mock_string: &str = "Foo bar"; 8 | /// let expected_string: String = "Foo bar".to_string(); 9 | /// let asserted_string: String = to_sentence_case(mock_string); 10 | /// assert!(asserted_string == expected_string); 11 | /// 12 | /// ``` 13 | /// ``` 14 | /// use inflector::cases::sentencecase::to_sentence_case; 15 | /// let mock_string: &str = "FooBar"; 16 | /// let expected_string: String = "Foo bar".to_string(); 17 | /// let asserted_string: String = to_sentence_case(mock_string); 18 | /// assert!(asserted_string == expected_string); 19 | /// 20 | /// ``` 21 | /// ``` 22 | /// use inflector::cases::sentencecase::to_sentence_case; 23 | /// let mock_string: &str = "fooBar"; 24 | /// let expected_string: String = "Foo bar".to_string(); 25 | /// let asserted_string: String = to_sentence_case(mock_string); 26 | /// assert!(asserted_string == expected_string); 27 | /// 28 | /// ``` 29 | /// ``` 30 | /// use inflector::cases::sentencecase::to_sentence_case; 31 | /// let mock_string: &str = "FOO_BAR"; 32 | /// let expected_string: String = "Foo bar".to_string(); 33 | /// let asserted_string: String = to_sentence_case(mock_string); 34 | /// assert!(asserted_string == expected_string); 35 | /// 36 | /// ``` 37 | /// ``` 38 | /// use inflector::cases::sentencecase::to_sentence_case; 39 | /// let mock_string: &str = "foo_bar"; 40 | /// let expected_string: String = "Foo bar".to_string(); 41 | /// let asserted_string: String = to_sentence_case(mock_string); 42 | /// assert!(asserted_string == expected_string); 43 | /// 44 | /// ``` 45 | /// ``` 46 | /// use inflector::cases::sentencecase::to_sentence_case; 47 | /// let mock_string: &str = "foo-bar"; 48 | /// let expected_string: String = "Foo bar".to_string(); 49 | /// let asserted_string: String = to_sentence_case(mock_string); 50 | /// assert!(asserted_string == expected_string); 51 | /// 52 | /// ``` 53 | pub fn to_sentence_case(non_sentence_case_string: &str) -> String { 54 | let options = CamelOptions { 55 | new_word: true, 56 | last_char: ' ', 57 | first_word: true, 58 | injectable_char: ' ', 59 | has_seperator: true, 60 | inverted: true, 61 | }; 62 | to_case_camel_like(non_sentence_case_string, options) 63 | } 64 | /// Determines of a `&str` is `Sentence case` 65 | /// 66 | /// ``` 67 | /// use inflector::cases::sentencecase::is_sentence_case; 68 | /// let mock_string: &str = "foo-bar-string-that-is-really-really-long"; 69 | /// let asserted_bool: bool = is_sentence_case(mock_string); 70 | /// assert!(asserted_bool == false); 71 | /// 72 | /// ``` 73 | /// ``` 74 | /// use inflector::cases::sentencecase::is_sentence_case; 75 | /// let mock_string: &str = "FooBarIsAReallyReallyLongString"; 76 | /// let asserted_bool: bool = is_sentence_case(mock_string); 77 | /// assert!(asserted_bool == false); 78 | /// 79 | /// ``` 80 | /// ``` 81 | /// use inflector::cases::sentencecase::is_sentence_case; 82 | /// let mock_string: &str = "fooBarIsAReallyReallyLongString"; 83 | /// let asserted_bool: bool = is_sentence_case(mock_string); 84 | /// assert!(asserted_bool == false); 85 | /// 86 | /// ``` 87 | /// ``` 88 | /// use inflector::cases::sentencecase::is_sentence_case; 89 | /// let mock_string: &str = "Foo Bar Is A Really Really Long String"; 90 | /// let asserted_bool: bool = is_sentence_case(mock_string); 91 | /// assert!(asserted_bool == false); 92 | /// 93 | /// ``` 94 | /// ``` 95 | /// use inflector::cases::sentencecase::is_sentence_case; 96 | /// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG"; 97 | /// let asserted_bool: bool = is_sentence_case(mock_string); 98 | /// assert!(asserted_bool == false); 99 | /// 100 | /// ``` 101 | /// ``` 102 | /// use inflector::cases::sentencecase::is_sentence_case; 103 | /// let mock_string: &str = "foo_bar_string_that_is_really_really_long"; 104 | /// let asserted_bool: bool = is_sentence_case(mock_string); 105 | /// assert!(asserted_bool == false); 106 | /// 107 | /// ``` 108 | /// ``` 109 | /// use inflector::cases::sentencecase::is_sentence_case; 110 | /// let mock_string: &str = "Foo"; 111 | /// let asserted_bool: bool = is_sentence_case(mock_string); 112 | /// assert!(asserted_bool == true); 113 | /// 114 | /// ``` 115 | /// ``` 116 | /// use inflector::cases::sentencecase::is_sentence_case; 117 | /// let mock_string: &str = "foo"; 118 | /// let asserted_bool: bool = is_sentence_case(mock_string); 119 | /// assert!(asserted_bool == false); 120 | /// 121 | /// ``` 122 | /// ``` 123 | /// use inflector::cases::sentencecase::is_sentence_case; 124 | /// let mock_string: &str = "Foo bar string that is really really long"; 125 | /// let asserted_bool: bool = is_sentence_case(mock_string); 126 | /// assert!(asserted_bool == true); 127 | /// 128 | /// ``` 129 | pub fn is_sentence_case(test_string: &str) -> bool { 130 | test_string == to_sentence_case(test_string.clone()) 131 | } 132 | 133 | #[cfg(all(feature = "unstable", test))] 134 | mod benchmarks { 135 | extern crate test; 136 | use self::test::Bencher; 137 | 138 | #[bench] 139 | fn bench_sentence(b: &mut Bencher) { 140 | b.iter(|| super::to_sentence_case("Foo BAR")); 141 | } 142 | 143 | #[bench] 144 | fn bench_is_sentence(b: &mut Bencher) { 145 | b.iter(|| super::is_sentence_case("Foo bar")); 146 | } 147 | 148 | #[bench] 149 | fn bench_sentence_from_snake(b: &mut Bencher) { 150 | b.iter(|| super::to_sentence_case("foo_bar")); 151 | } 152 | 153 | } 154 | 155 | #[cfg(test)] 156 | mod tests { 157 | use ::to_sentence_case; 158 | use ::is_sentence_case; 159 | 160 | #[test] 161 | fn from_camel_case() { 162 | let convertable_string: String = "fooBar".to_owned(); 163 | let expected: String = "Foo bar".to_owned(); 164 | assert_eq!(to_sentence_case(&convertable_string), expected) 165 | } 166 | 167 | #[test] 168 | fn from_pascal_case() { 169 | let convertable_string: String = "FooBar".to_owned(); 170 | let expected: String = "Foo bar".to_owned(); 171 | assert_eq!(to_sentence_case(&convertable_string), expected) 172 | } 173 | 174 | #[test] 175 | fn from_kebab_case() { 176 | let convertable_string: String = "foo-bar".to_owned(); 177 | let expected: String = "Foo bar".to_owned(); 178 | assert_eq!(to_sentence_case(&convertable_string), expected) 179 | } 180 | 181 | #[test] 182 | fn from_sentence_case() { 183 | let convertable_string: String = "Foo bar".to_owned(); 184 | let expected: String = "Foo bar".to_owned(); 185 | assert_eq!(to_sentence_case(&convertable_string), expected) 186 | } 187 | 188 | #[test] 189 | fn from_title_case() { 190 | let convertable_string: String = "Foo Bar".to_owned(); 191 | let expected: String = "Foo bar".to_owned(); 192 | assert_eq!(to_sentence_case(&convertable_string), expected) 193 | } 194 | 195 | #[test] 196 | fn from_train_case() { 197 | let convertable_string: String = "Foo-Bar".to_owned(); 198 | let expected: String = "Foo bar".to_owned(); 199 | assert_eq!(to_sentence_case(&convertable_string), expected) 200 | } 201 | 202 | #[test] 203 | fn from_screaming_snake_case() { 204 | let convertable_string: String = "FOO_BAR".to_owned(); 205 | let expected: String = "Foo bar".to_owned(); 206 | assert_eq!(to_sentence_case(&convertable_string), expected) 207 | } 208 | 209 | #[test] 210 | fn from_snake_case() { 211 | let convertable_string: String = "foo_bar".to_owned(); 212 | let expected: String = "Foo bar".to_owned(); 213 | assert_eq!(to_sentence_case(&convertable_string), expected) 214 | } 215 | 216 | #[test] 217 | fn from_case_with_loads_of_space() { 218 | let convertable_string: String = "foo bar".to_owned(); 219 | let expected: String = "Foo bar".to_owned(); 220 | assert_eq!(to_sentence_case(&convertable_string), expected) 221 | } 222 | 223 | #[test] 224 | fn a_name_with_a_dot() { 225 | let convertable_string: String = "Robert C. Martin".to_owned(); 226 | let expected: String = "Robert c martin".to_owned(); 227 | assert_eq!(to_sentence_case(&convertable_string), expected) 228 | } 229 | 230 | #[test] 231 | fn random_text_with_bad_chars() { 232 | let convertable_string: String = "Random text with *(bad) chars".to_owned(); 233 | let expected: String = "Random text with bad chars".to_owned(); 234 | assert_eq!(to_sentence_case(&convertable_string), expected) 235 | } 236 | 237 | #[test] 238 | fn trailing_bad_chars() { 239 | let convertable_string: String = "trailing bad_chars*(()())".to_owned(); 240 | let expected: String = "Trailing bad chars".to_owned(); 241 | assert_eq!(to_sentence_case(&convertable_string), expected) 242 | } 243 | 244 | #[test] 245 | fn leading_bad_chars() { 246 | let convertable_string: String = "-!#$%leading bad chars".to_owned(); 247 | let expected: String = "Leading bad chars".to_owned(); 248 | assert_eq!(to_sentence_case(&convertable_string), expected) 249 | } 250 | 251 | #[test] 252 | fn wrapped_in_bad_chars() { 253 | let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<>><>))".to_owned(); 254 | let expected: String = "Wrapped in bad chars".to_owned(); 255 | assert_eq!(to_sentence_case(&convertable_string), expected) 256 | } 257 | 258 | #[test] 259 | fn has_a_sign() { 260 | let convertable_string: String = "has a + sign".to_owned(); 261 | let expected: String = "Has a sign".to_owned(); 262 | assert_eq!(to_sentence_case(&convertable_string), expected) 263 | } 264 | 265 | 266 | #[test] 267 | fn is_correct_from_camel_case() { 268 | let convertable_string: String = "fooBar".to_owned(); 269 | assert_eq!(is_sentence_case(&convertable_string), false) 270 | } 271 | 272 | #[test] 273 | fn is_correct_from_pascal_case() { 274 | let convertable_string: String = "FooBar".to_owned(); 275 | assert_eq!(is_sentence_case(&convertable_string), false) 276 | } 277 | 278 | #[test] 279 | fn is_correct_from_kebab_case() { 280 | let convertable_string: String = "foo-bar".to_owned(); 281 | assert_eq!(is_sentence_case(&convertable_string), false) 282 | } 283 | 284 | #[test] 285 | fn is_correct_from_sentence_case() { 286 | let convertable_string: String = "Foo bar".to_owned(); 287 | assert_eq!(is_sentence_case(&convertable_string), true) 288 | } 289 | 290 | #[test] 291 | fn is_correct_from_title_case() { 292 | let convertable_string: String = "Foo Bar".to_owned(); 293 | assert_eq!(is_sentence_case(&convertable_string), false) 294 | } 295 | 296 | #[test] 297 | fn is_correct_from_train_case() { 298 | let convertable_string: String = "Foo-Bar".to_owned(); 299 | assert_eq!(is_sentence_case(&convertable_string), false) 300 | } 301 | 302 | #[test] 303 | fn is_correct_from_screaming_snake_case() { 304 | let convertable_string: String = "FOO_BAR".to_owned(); 305 | assert_eq!(is_sentence_case(&convertable_string), false) 306 | } 307 | 308 | #[test] 309 | fn is_correct_from_snake_case() { 310 | let convertable_string: String = "foo_bar".to_owned(); 311 | assert_eq!(is_sentence_case(&convertable_string), false) 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /src/cases/snakecase/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | use cases::case::*; 3 | /// Converts a `&str` to `snake_case` `String` 4 | /// 5 | /// ``` 6 | /// use inflector::cases::snakecase::to_snake_case; 7 | /// let mock_string: &str = "foo_bar"; 8 | /// let expected_string: String = "foo_bar".to_string(); 9 | /// let asserted_string: String = to_snake_case(mock_string); 10 | /// assert!(asserted_string == expected_string); 11 | /// 12 | /// ``` 13 | /// ``` 14 | /// use inflector::cases::snakecase::to_snake_case; 15 | /// let mock_string: &str = "HTTP Foo bar"; 16 | /// let expected_string: String = "http_foo_bar".to_string(); 17 | /// let asserted_string: String = to_snake_case(mock_string); 18 | /// assert!(asserted_string == expected_string); 19 | /// 20 | /// ``` 21 | /// ``` 22 | /// use inflector::cases::snakecase::to_snake_case; 23 | /// let mock_string: &str = "HTTPFooBar"; 24 | /// let expected_string: String = "http_foo_bar".to_string(); 25 | /// let asserted_string: String = to_snake_case(mock_string); 26 | /// assert!(asserted_string == expected_string); 27 | /// 28 | /// ``` 29 | /// ``` 30 | /// use inflector::cases::snakecase::to_snake_case; 31 | /// let mock_string: &str = "Foo bar"; 32 | /// let expected_string: String = "foo_bar".to_string(); 33 | /// let asserted_string: String = to_snake_case(mock_string); 34 | /// assert!(asserted_string == expected_string); 35 | /// 36 | /// ``` 37 | /// ``` 38 | /// use inflector::cases::snakecase::to_snake_case; 39 | /// let mock_string: &str = "Foo Bar"; 40 | /// let expected_string: String = "foo_bar".to_string(); 41 | /// let asserted_string: String = to_snake_case(mock_string); 42 | /// assert!(asserted_string == expected_string); 43 | /// 44 | /// ``` 45 | /// ``` 46 | /// use inflector::cases::snakecase::to_snake_case; 47 | /// let mock_string: &str = "FooBar"; 48 | /// let expected_string: String = "foo_bar".to_string(); 49 | /// let asserted_string: String = to_snake_case(mock_string); 50 | /// assert!(asserted_string == expected_string); 51 | /// 52 | /// ``` 53 | /// ``` 54 | /// use inflector::cases::snakecase::to_snake_case; 55 | /// let mock_string: &str = "FOO_BAR"; 56 | /// let expected_string: String = "foo_bar".to_string(); 57 | /// let asserted_string: String = to_snake_case(mock_string); 58 | /// assert!(asserted_string == expected_string); 59 | /// 60 | /// ``` 61 | /// ``` 62 | /// use inflector::cases::snakecase::to_snake_case; 63 | /// let mock_string: &str = "fooBar"; 64 | /// let expected_string: String = "foo_bar".to_string(); 65 | /// let asserted_string: String = to_snake_case(mock_string); 66 | /// assert!(asserted_string == expected_string); 67 | /// 68 | /// ``` 69 | /// ``` 70 | /// use inflector::cases::snakecase::to_snake_case; 71 | /// let mock_string: &str = "fooBar3"; 72 | /// let expected_string: String = "foo_bar_3".to_string(); 73 | /// let asserted_string: String = to_snake_case(mock_string); 74 | /// assert!(asserted_string == expected_string); 75 | /// 76 | /// ``` 77 | pub fn to_snake_case(non_snake_case_string: &str) -> String { 78 | to_case_snake_like(non_snake_case_string, "_", "lower") 79 | } 80 | 81 | /// Determines of a `&str` is `snake_case` 82 | /// 83 | /// ``` 84 | /// use inflector::cases::snakecase::is_snake_case; 85 | /// let mock_string: &str = "Foo bar string that is really really long"; 86 | /// let asserted_bool: bool = is_snake_case(mock_string); 87 | /// assert!(asserted_bool == false); 88 | /// 89 | /// ``` 90 | /// ``` 91 | /// use inflector::cases::snakecase::is_snake_case; 92 | /// let mock_string: &str = "foo-bar-string-that-is-really-really-long"; 93 | /// let asserted_bool: bool = is_snake_case(mock_string); 94 | /// assert!(asserted_bool == false); 95 | /// 96 | /// ``` 97 | /// ``` 98 | /// use inflector::cases::snakecase::is_snake_case; 99 | /// let mock_string: &str = "FooBarIsAReallyReallyLongString"; 100 | /// let asserted_bool: bool = is_snake_case(mock_string); 101 | /// assert!(asserted_bool == false); 102 | /// 103 | /// ``` 104 | /// ``` 105 | /// use inflector::cases::snakecase::is_snake_case; 106 | /// let mock_string: &str = "Foo Bar Is A Really Really Long String"; 107 | /// let asserted_bool: bool = is_snake_case(mock_string); 108 | /// assert!(asserted_bool == false); 109 | /// 110 | /// ``` 111 | /// ``` 112 | /// use inflector::cases::snakecase::is_snake_case; 113 | /// let mock_string: &str = "FOO_BAR_IS_A_REALLY_REALLY_LONG_STRING"; 114 | /// let asserted_bool: bool = is_snake_case(mock_string); 115 | /// assert!(asserted_bool == false); 116 | /// 117 | /// ``` 118 | /// ``` 119 | /// use inflector::cases::snakecase::is_snake_case; 120 | /// let mock_string: &str = "fooBarIsAReallyReallyLongString"; 121 | /// let asserted_bool: bool = is_snake_case(mock_string); 122 | /// assert!(asserted_bool == false); 123 | /// 124 | /// ``` 125 | /// ``` 126 | /// use inflector::cases::snakecase::is_snake_case; 127 | /// let mock_string: &str = "foo_bar_string_that_is_really_really_long"; 128 | /// let asserted_bool: bool = is_snake_case(mock_string); 129 | /// assert!(asserted_bool == true); 130 | /// 131 | /// ``` 132 | /// ``` 133 | /// use inflector::cases::snakecase::is_snake_case; 134 | /// let mock_string: &str = "foo_bar1_string_that_is_really_really_long"; 135 | /// let asserted_bool: bool = is_snake_case(mock_string); 136 | /// assert!(asserted_bool == false); 137 | /// 138 | /// ``` 139 | /// ``` 140 | /// use inflector::cases::snakecase::is_snake_case; 141 | /// let mock_string: &str = "foo_bar_1_string_that_is_really_really_long"; 142 | /// let asserted_bool: bool = is_snake_case(mock_string); 143 | /// assert!(asserted_bool == true); 144 | /// 145 | /// ``` 146 | pub fn is_snake_case(test_string: &str) -> bool { 147 | test_string == to_snake_case(test_string.clone()) 148 | } 149 | 150 | #[cfg(all(feature = "unstable", test))] 151 | mod benchmarks { 152 | extern crate test; 153 | use self::test::Bencher; 154 | 155 | #[bench] 156 | fn bench_snake_from_title(b: &mut Bencher) { 157 | b.iter(|| super::to_snake_case("Foo bar")); 158 | } 159 | 160 | #[bench] 161 | fn bench_snake_from_camel(b: &mut Bencher) { 162 | b.iter(|| super::to_snake_case("fooBar")); 163 | } 164 | 165 | #[bench] 166 | fn bench_snake_from_snake(b: &mut Bencher) { 167 | b.iter(|| super::to_snake_case("foo_bar_bar_bar")); 168 | } 169 | 170 | #[bench] 171 | fn bench_is_snake(b: &mut Bencher) { 172 | b.iter(|| super::is_snake_case("Foo bar")); 173 | } 174 | 175 | } 176 | 177 | #[cfg(test)] 178 | mod tests { 179 | use ::to_snake_case; 180 | use ::is_snake_case; 181 | 182 | #[test] 183 | fn from_camel_case() { 184 | let convertable_string: String = "fooBar".to_owned(); 185 | let expected: String = "foo_bar".to_owned(); 186 | assert_eq!(to_snake_case(&convertable_string), expected) 187 | } 188 | 189 | #[test] 190 | fn from_pascal_case() { 191 | let convertable_string: String = "FooBar".to_owned(); 192 | let expected: String = "foo_bar".to_owned(); 193 | assert_eq!(to_snake_case(&convertable_string), expected) 194 | } 195 | 196 | #[test] 197 | fn from_kebab_case() { 198 | let convertable_string: String = "foo-bar".to_owned(); 199 | let expected: String = "foo_bar".to_owned(); 200 | assert_eq!(to_snake_case(&convertable_string), expected) 201 | } 202 | 203 | #[test] 204 | fn from_sentence_case() { 205 | let convertable_string: String = "Foo bar".to_owned(); 206 | let expected: String = "foo_bar".to_owned(); 207 | assert_eq!(to_snake_case(&convertable_string), expected) 208 | } 209 | 210 | #[test] 211 | fn from_title_case() { 212 | let convertable_string: String = "Foo Bar".to_owned(); 213 | let expected: String = "foo_bar".to_owned(); 214 | assert_eq!(to_snake_case(&convertable_string), expected) 215 | } 216 | 217 | #[test] 218 | fn from_train_case() { 219 | let convertable_string: String = "Foo-Bar".to_owned(); 220 | let expected: String = "foo_bar".to_owned(); 221 | assert_eq!(to_snake_case(&convertable_string), expected) 222 | } 223 | 224 | #[test] 225 | fn from_screaming_snake_case() { 226 | let convertable_string: String = "FOO_BAR".to_owned(); 227 | let expected: String = "foo_bar".to_owned(); 228 | assert_eq!(to_snake_case(&convertable_string), expected) 229 | } 230 | 231 | #[test] 232 | fn from_snake_case() { 233 | let convertable_string: String = "foo_bar".to_owned(); 234 | let expected: String = "foo_bar".to_owned(); 235 | assert_eq!(to_snake_case(&convertable_string), expected) 236 | } 237 | 238 | #[test] 239 | fn from_case_with_loads_of_space() { 240 | let convertable_string: String = "foo bar".to_owned(); 241 | let expected: String = "foo_bar".to_owned(); 242 | assert_eq!(to_snake_case(&convertable_string), expected) 243 | } 244 | 245 | #[test] 246 | fn a_name_with_a_dot() { 247 | let convertable_string: String = "Robert C. Martin".to_owned(); 248 | let expected: String = "robert_c_martin".to_owned(); 249 | assert_eq!(to_snake_case(&convertable_string), expected) 250 | } 251 | 252 | #[test] 253 | fn random_text_with_bad_chars() { 254 | let convertable_string: String = "Random text with *(bad) chars".to_owned(); 255 | let expected: String = "random_text_with_bad_chars".to_owned(); 256 | assert_eq!(to_snake_case(&convertable_string), expected) 257 | } 258 | 259 | #[test] 260 | fn trailing_bad_chars() { 261 | let convertable_string: String = "trailing bad_chars*(()())".to_owned(); 262 | let expected: String = "trailing_bad_chars".to_owned(); 263 | assert_eq!(to_snake_case(&convertable_string), expected) 264 | } 265 | 266 | #[test] 267 | fn leading_bad_chars() { 268 | let convertable_string: String = "-!#$%leading bad chars".to_owned(); 269 | let expected: String = "leading_bad_chars".to_owned(); 270 | assert_eq!(to_snake_case(&convertable_string), expected) 271 | } 272 | 273 | #[test] 274 | fn wrapped_in_bad_chars() { 275 | let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<>><>))".to_owned(); 276 | let expected: String = "wrapped_in_bad_chars".to_owned(); 277 | assert_eq!(to_snake_case(&convertable_string), expected) 278 | } 279 | 280 | #[test] 281 | fn has_a_sign() { 282 | let convertable_string: String = "has a + sign".to_owned(); 283 | let expected: String = "has_a_sign".to_owned(); 284 | assert_eq!(to_snake_case(&convertable_string), expected) 285 | } 286 | 287 | #[test] 288 | fn is_correct_from_camel_case() { 289 | let convertable_string: String = "fooBar".to_owned(); 290 | assert_eq!(is_snake_case(&convertable_string), false) 291 | } 292 | 293 | #[test] 294 | fn is_correct_from_pascal_case() { 295 | let convertable_string: String = "FooBar".to_owned(); 296 | assert_eq!(is_snake_case(&convertable_string), false) 297 | } 298 | 299 | #[test] 300 | fn is_correct_from_kebab_case() { 301 | let convertable_string: String = "foo-bar".to_owned(); 302 | assert_eq!(is_snake_case(&convertable_string), false) 303 | } 304 | 305 | #[test] 306 | fn is_correct_from_sentence_case() { 307 | let convertable_string: String = "Foo bar".to_owned(); 308 | assert_eq!(is_snake_case(&convertable_string), false) 309 | } 310 | 311 | #[test] 312 | fn is_correct_from_title_case() { 313 | let convertable_string: String = "Foo Bar".to_owned(); 314 | assert_eq!(is_snake_case(&convertable_string), false) 315 | } 316 | 317 | #[test] 318 | fn is_correct_from_train_case() { 319 | let convertable_string: String = "Foo-Bar".to_owned(); 320 | assert_eq!(is_snake_case(&convertable_string), false) 321 | } 322 | 323 | #[test] 324 | fn is_correct_from_screaming_snake_case() { 325 | let convertable_string: String = "FOO_BAR".to_owned(); 326 | assert_eq!(is_snake_case(&convertable_string), false) 327 | } 328 | 329 | #[test] 330 | fn is_correct_from_snake_case() { 331 | let convertable_string: String = "foo_bar".to_owned(); 332 | assert_eq!(is_snake_case(&convertable_string), true) 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /src/cases/tablecase/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | #[cfg(feature = "heavyweight")] 3 | use string::pluralize::to_plural; 4 | #[cfg(feature = "heavyweight")] 5 | use cases::case::*; 6 | #[cfg(feature = "heavyweight")] 7 | /// Converts a `&str` to `table-case` `String` 8 | /// 9 | /// ``` 10 | /// use inflector::cases::tablecase::to_table_case; 11 | /// let mock_string: &str = "foo-bar"; 12 | /// let expected_string: String = "foo_bars".to_string(); 13 | /// let asserted_string: String = to_table_case(mock_string); 14 | /// assert!(asserted_string == expected_string); 15 | /// ``` 16 | /// 17 | /// ``` 18 | /// use inflector::cases::tablecase::to_table_case; 19 | /// let mock_string: &str = "FOO_BAR"; 20 | /// let expected_string: String = "foo_bars".to_string(); 21 | /// let asserted_string: String = to_table_case(mock_string); 22 | /// assert!(asserted_string == expected_string); 23 | /// ``` 24 | /// 25 | /// ``` 26 | /// use inflector::cases::tablecase::to_table_case; 27 | /// let mock_string: &str = "foo_bar"; 28 | /// let expected_string: String = "foo_bars".to_string(); 29 | /// let asserted_string: String = to_table_case(mock_string); 30 | /// assert!(asserted_string == expected_string); 31 | /// ``` 32 | /// 33 | /// ``` 34 | /// use inflector::cases::tablecase::to_table_case; 35 | /// let mock_string: &str = "Foo Bar"; 36 | /// let expected_string: String = "foo_bars".to_string(); 37 | /// let asserted_string: String = to_table_case(mock_string); 38 | /// assert!(asserted_string == expected_string); 39 | /// ``` 40 | /// 41 | /// ``` 42 | /// use inflector::cases::tablecase::to_table_case; 43 | /// let mock_string: &str = "Foo bar"; 44 | /// let expected_string: String = "foo_bars".to_string(); 45 | /// let asserted_string: String = to_table_case(mock_string); 46 | /// assert!(asserted_string == expected_string); 47 | /// ``` 48 | /// 49 | /// ``` 50 | /// use inflector::cases::tablecase::to_table_case; 51 | /// let mock_string: &str = "FooBar"; 52 | /// let expected_string: String = "foo_bars".to_string(); 53 | /// let asserted_string: String = to_table_case(mock_string); 54 | /// assert!(asserted_string == expected_string); 55 | /// ``` 56 | /// 57 | /// ``` 58 | /// use inflector::cases::tablecase::to_table_case; 59 | /// let mock_string: &str = "fooBar"; 60 | /// let expected_string: String = "foo_bars".to_string(); 61 | /// let asserted_string: String = to_table_case(mock_string); 62 | /// assert!(asserted_string == expected_string); 63 | /// ``` 64 | pub fn to_table_case(non_table_case_string: &str) -> String { 65 | let snaked: String = to_case_snake_like(non_table_case_string, "_", "lower"); 66 | let split: (&str, &str) = snaked.split_at(snaked.rfind('_').unwrap_or(0)); 67 | format!("{}{}", split.0, to_plural(split.1)) 68 | } 69 | 70 | #[cfg(feature = "heavyweight")] 71 | /// Determines if a `&str` is `table-case` 72 | /// 73 | /// ``` 74 | /// use inflector::cases::tablecase::is_table_case; 75 | /// let mock_string: &str = "foo_bar_strings"; 76 | /// let asserted_bool: bool = is_table_case(mock_string); 77 | /// assert!(asserted_bool == true); 78 | /// ``` 79 | /// 80 | /// ``` 81 | /// use inflector::cases::tablecase::is_table_case; 82 | /// let mock_string: &str = "foo-bar-string-that-is-really-really-long"; 83 | /// let asserted_bool: bool = is_table_case(mock_string); 84 | /// assert!(asserted_bool == false); 85 | /// ``` 86 | /// 87 | /// ``` 88 | /// use inflector::cases::tablecase::is_table_case; 89 | /// let mock_string: &str = "FooBarIsAReallyReallyLongString"; 90 | /// let asserted_bool: bool = is_table_case(mock_string); 91 | /// assert!(asserted_bool == false); 92 | /// ``` 93 | /// 94 | /// ``` 95 | /// use inflector::cases::tablecase::is_table_case; 96 | /// let mock_string: &str = "fooBarIsAReallyReallyLongString"; 97 | /// let asserted_bool: bool = is_table_case(mock_string); 98 | /// assert!(asserted_bool == false); 99 | /// ``` 100 | /// 101 | /// ``` 102 | /// use inflector::cases::tablecase::is_table_case; 103 | /// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG"; 104 | /// let asserted_bool: bool = is_table_case(mock_string); 105 | /// assert!(asserted_bool == false); 106 | /// ``` 107 | /// 108 | /// ``` 109 | /// use inflector::cases::tablecase::is_table_case; 110 | /// let mock_string: &str = "foo_bar_string_that_is_really_really_long"; 111 | /// let asserted_bool: bool = is_table_case(mock_string); 112 | /// assert!(asserted_bool == false); 113 | /// ``` 114 | /// 115 | /// ``` 116 | /// use inflector::cases::tablecase::is_table_case; 117 | /// let mock_string: &str = "Foo bar string that is really really long"; 118 | /// let asserted_bool: bool = is_table_case(mock_string); 119 | /// assert!(asserted_bool == false); 120 | /// ``` 121 | /// 122 | /// ``` 123 | /// use inflector::cases::tablecase::is_table_case; 124 | /// let mock_string: &str = "Foo Bar Is A Really Really Long String"; 125 | /// let asserted_bool: bool = is_table_case(mock_string); 126 | /// assert!(asserted_bool == false); 127 | /// ``` 128 | pub fn is_table_case(test_string: &str) -> bool { 129 | to_table_case(&test_string.clone()) == test_string 130 | } 131 | 132 | #[cfg(all(feature = "unstable", test))] 133 | #[cfg(feature = "heavyweight")] 134 | mod benchmarks { 135 | extern crate test; 136 | use self::test::Bencher; 137 | 138 | #[bench] 139 | fn bench_table_case(b: &mut Bencher) { 140 | b.iter(|| super::to_table_case("Foo bar")); 141 | } 142 | 143 | #[bench] 144 | fn bench_is_table_case(b: &mut Bencher) { 145 | b.iter(|| super::is_table_case("Foo bar")); 146 | } 147 | } 148 | 149 | #[cfg(test)] 150 | #[cfg(feature = "heavyweight")] 151 | mod tests { 152 | use ::to_table_case; 153 | use ::is_table_case; 154 | 155 | #[test] 156 | fn from_camel_case() { 157 | let convertable_string: String = "fooBar".to_owned(); 158 | let expected: String = "foo_bars".to_owned(); 159 | assert_eq!(to_table_case(&convertable_string), expected) 160 | } 161 | 162 | #[test] 163 | fn from_pascal_case() { 164 | let convertable_string: String = "FooBar".to_owned(); 165 | let expected: String = "foo_bars".to_owned(); 166 | assert_eq!(to_table_case(&convertable_string), expected) 167 | } 168 | 169 | #[test] 170 | fn from_kebab_case() { 171 | let convertable_string: String = "foo-bar".to_owned(); 172 | let expected: String = "foo_bars".to_owned(); 173 | assert_eq!(to_table_case(&convertable_string), expected) 174 | } 175 | 176 | #[test] 177 | fn from_sentence_case() { 178 | let convertable_string: String = "Foo bar".to_owned(); 179 | let expected: String = "foo_bars".to_owned(); 180 | assert_eq!(to_table_case(&convertable_string), expected) 181 | } 182 | 183 | #[test] 184 | fn from_title_case() { 185 | let convertable_string: String = "Foo Bar".to_owned(); 186 | let expected: String = "foo_bars".to_owned(); 187 | assert_eq!(to_table_case(&convertable_string), expected) 188 | } 189 | 190 | #[test] 191 | fn from_train_case() { 192 | let convertable_string: String = "Foo-Bar".to_owned(); 193 | let expected: String = "foo_bars".to_owned(); 194 | assert_eq!(to_table_case(&convertable_string), expected) 195 | } 196 | 197 | #[test] 198 | fn from_screaming_snake_case() { 199 | let convertable_string: String = "FOO_BAR".to_owned(); 200 | let expected: String = "foo_bars".to_owned(); 201 | assert_eq!(to_table_case(&convertable_string), expected) 202 | } 203 | 204 | #[test] 205 | fn from_snake_case() { 206 | let convertable_string: String = "foo_bar".to_owned(); 207 | let expected: String = "foo_bars".to_owned(); 208 | assert_eq!(to_table_case(&convertable_string), expected) 209 | } 210 | 211 | #[test] 212 | fn from_table_case() { 213 | let convertable_string: String = "foo_bars".to_owned(); 214 | let expected: String = "foo_bars".to_owned(); 215 | assert_eq!(to_table_case(&convertable_string), expected) 216 | } 217 | 218 | #[test] 219 | fn is_correct_from_camel_case() { 220 | let convertable_string: String = "fooBar".to_owned(); 221 | assert_eq!(is_table_case(&convertable_string), false) 222 | } 223 | 224 | #[test] 225 | fn is_correct_from_pascal_case() { 226 | let convertable_string: String = "FooBar".to_owned(); 227 | assert_eq!(is_table_case(&convertable_string), false) 228 | } 229 | 230 | #[test] 231 | fn is_correct_from_kebab_case() { 232 | let convertable_string: String = "foo-bar".to_owned(); 233 | assert_eq!(is_table_case(&convertable_string), false) 234 | } 235 | 236 | #[test] 237 | fn is_correct_from_sentence_case() { 238 | let convertable_string: String = "Foo bar".to_owned(); 239 | assert_eq!(is_table_case(&convertable_string), false) 240 | } 241 | 242 | #[test] 243 | fn is_correct_from_title_case() { 244 | let convertable_string: String = "Foo Bar".to_owned(); 245 | assert_eq!(is_table_case(&convertable_string), false) 246 | } 247 | 248 | #[test] 249 | fn is_correct_from_train_case() { 250 | let convertable_string: String = "Foo-Bar".to_owned(); 251 | assert_eq!(is_table_case(&convertable_string), false) 252 | } 253 | 254 | #[test] 255 | fn is_correct_from_screaming_snake_case() { 256 | let convertable_string: String = "FOO_BAR".to_owned(); 257 | assert_eq!(is_table_case(&convertable_string), false) 258 | } 259 | 260 | #[test] 261 | fn is_correct_from_snake_case() { 262 | let convertable_string: String = "foo_bar".to_owned(); 263 | assert_eq!(is_table_case(&convertable_string), false) 264 | } 265 | 266 | #[test] 267 | fn is_correct_from_table_case() { 268 | let convertable_string: String = "foo_bars".to_owned(); 269 | assert_eq!(is_table_case(&convertable_string), true) 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /src/cases/titlecase/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | use cases::case::*; 3 | /// Converts a `&str` to `Title Case` `String` 4 | /// 5 | /// ``` 6 | /// use inflector::cases::titlecase::to_title_case; 7 | /// let mock_string: &str = "Foo bar"; 8 | /// let expected_string: String = "Foo Bar".to_string(); 9 | /// let asserted_string: String = to_title_case(mock_string); 10 | /// assert!(asserted_string == expected_string); 11 | /// 12 | /// ``` 13 | /// ``` 14 | /// use inflector::cases::titlecase::to_title_case; 15 | /// let mock_string: &str = "FooBar"; 16 | /// let expected_string: String = "Foo Bar".to_string(); 17 | /// let asserted_string: String = to_title_case(mock_string); 18 | /// assert!(asserted_string == expected_string); 19 | /// 20 | /// ``` 21 | /// ``` 22 | /// use inflector::cases::titlecase::to_title_case; 23 | /// let mock_string: &str = "fooBar"; 24 | /// let expected_string: String = "Foo Bar".to_string(); 25 | /// let asserted_string: String = to_title_case(mock_string); 26 | /// assert!(asserted_string == expected_string); 27 | /// 28 | /// ``` 29 | /// ``` 30 | /// use inflector::cases::titlecase::to_title_case; 31 | /// let mock_string: &str = "FOO_BAR"; 32 | /// let expected_string: String = "Foo Bar".to_string(); 33 | /// let asserted_string: String = to_title_case(mock_string); 34 | /// assert!(asserted_string == expected_string); 35 | /// 36 | /// ``` 37 | /// ``` 38 | /// use inflector::cases::titlecase::to_title_case; 39 | /// let mock_string: &str = "foo_bar"; 40 | /// let expected_string: String = "Foo Bar".to_string(); 41 | /// let asserted_string: String = to_title_case(mock_string); 42 | /// assert!(asserted_string == expected_string); 43 | /// 44 | /// ``` 45 | /// ``` 46 | /// use inflector::cases::titlecase::to_title_case; 47 | /// let mock_string: &str = "foo-bar"; 48 | /// let expected_string: String = "Foo Bar".to_string(); 49 | /// let asserted_string: String = to_title_case(mock_string); 50 | /// assert!(asserted_string == expected_string); 51 | /// 52 | /// ``` 53 | pub fn to_title_case(non_title_case_string: &str) -> String { 54 | let options = CamelOptions { 55 | new_word: true, 56 | last_char: ' ', 57 | first_word: true, 58 | injectable_char: ' ', 59 | has_seperator: true, 60 | inverted: false, 61 | }; 62 | to_case_camel_like(non_title_case_string, options) 63 | } 64 | 65 | /// Determines if a `&str` is `Title Case` 66 | /// 67 | /// ``` 68 | /// use inflector::cases::titlecase::is_title_case; 69 | /// let mock_string: &str = "foo-bar-string-that-is-really-really-long"; 70 | /// let asserted_bool: bool = is_title_case(mock_string); 71 | /// assert!(asserted_bool == false); 72 | /// 73 | /// ``` 74 | /// ``` 75 | /// use inflector::cases::titlecase::is_title_case; 76 | /// let mock_string: &str = "FooBarIsAReallyReallyLongString"; 77 | /// let asserted_bool: bool = is_title_case(mock_string); 78 | /// assert!(asserted_bool == false); 79 | /// 80 | /// ``` 81 | /// ``` 82 | /// use inflector::cases::titlecase::is_title_case; 83 | /// let mock_string: &str = "fooBarIsAReallyReallyLongString"; 84 | /// let asserted_bool: bool = is_title_case(mock_string); 85 | /// assert!(asserted_bool == false); 86 | /// 87 | /// ``` 88 | /// ``` 89 | /// use inflector::cases::titlecase::is_title_case; 90 | /// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG"; 91 | /// let asserted_bool: bool = is_title_case(mock_string); 92 | /// assert!(asserted_bool == false); 93 | /// 94 | /// ``` 95 | /// ``` 96 | /// use inflector::cases::titlecase::is_title_case; 97 | /// let mock_string: &str = "foo_bar_string_that_is_really_really_long"; 98 | /// let asserted_bool: bool = is_title_case(mock_string); 99 | /// assert!(asserted_bool == false); 100 | /// 101 | /// ``` 102 | /// ``` 103 | /// use inflector::cases::titlecase::is_title_case; 104 | /// let mock_string: &str = "Foo bar string that is really really long"; 105 | /// let asserted_bool: bool = is_title_case(mock_string); 106 | /// assert!(asserted_bool == false); 107 | /// 108 | /// ``` 109 | /// ``` 110 | /// use inflector::cases::titlecase::is_title_case; 111 | /// let mock_string: &str = "foo"; 112 | /// let asserted_bool: bool = is_title_case(mock_string); 113 | /// assert!(asserted_bool == false); 114 | /// 115 | /// ``` 116 | /// ``` 117 | /// use inflector::cases::titlecase::is_title_case; 118 | /// let mock_string: &str = "Foo Bar String That Is Really Really Long"; 119 | /// let asserted_bool: bool = is_title_case(mock_string); 120 | /// assert!(asserted_bool == true); 121 | /// 122 | /// ``` 123 | pub fn is_title_case(test_string: &str) -> bool { 124 | test_string == to_title_case(test_string.clone()) 125 | } 126 | 127 | #[cfg(all(feature = "unstable", test))] 128 | mod benchmarks { 129 | extern crate test; 130 | use self::test::Bencher; 131 | 132 | #[bench] 133 | fn bench_title(b: &mut Bencher) { 134 | b.iter(|| super::to_title_case("Foo BAR")); 135 | } 136 | 137 | #[bench] 138 | fn bench_is_title(b: &mut Bencher) { 139 | b.iter(|| super::is_title_case("Foo bar")); 140 | } 141 | 142 | #[bench] 143 | fn bench_title_from_snake(b: &mut Bencher) { 144 | b.iter(|| super::to_title_case("foo_bar")); 145 | } 146 | 147 | } 148 | 149 | 150 | #[cfg(test)] 151 | mod tests { 152 | use ::to_title_case; 153 | use ::is_title_case; 154 | 155 | #[test] 156 | fn from_camel_case() { 157 | let convertable_string: String = "fooBar".to_owned(); 158 | let expected: String = "Foo Bar".to_owned(); 159 | assert_eq!(to_title_case(&convertable_string), expected) 160 | } 161 | 162 | #[test] 163 | fn from_pascal_case() { 164 | let convertable_string: String = "FooBar".to_owned(); 165 | let expected: String = "Foo Bar".to_owned(); 166 | assert_eq!(to_title_case(&convertable_string), expected) 167 | } 168 | 169 | #[test] 170 | fn from_kebab_case() { 171 | let convertable_string: String = "foo-bar".to_owned(); 172 | let expected: String = "Foo Bar".to_owned(); 173 | assert_eq!(to_title_case(&convertable_string), expected) 174 | } 175 | 176 | #[test] 177 | fn from_sentence_case() { 178 | let convertable_string: String = "Foo bar".to_owned(); 179 | let expected: String = "Foo Bar".to_owned(); 180 | assert_eq!(to_title_case(&convertable_string), expected) 181 | } 182 | 183 | #[test] 184 | fn from_title_case() { 185 | let convertable_string: String = "Foo Bar".to_owned(); 186 | let expected: String = "Foo Bar".to_owned(); 187 | assert_eq!(to_title_case(&convertable_string), expected) 188 | } 189 | 190 | #[test] 191 | fn from_train_case() { 192 | let convertable_string: String = "Foo-Bar".to_owned(); 193 | let expected: String = "Foo Bar".to_owned(); 194 | assert_eq!(to_title_case(&convertable_string), expected) 195 | } 196 | 197 | #[test] 198 | fn from_screaming_snake_case() { 199 | let convertable_string: String = "FOO_BAR".to_owned(); 200 | let expected: String = "Foo Bar".to_owned(); 201 | assert_eq!(to_title_case(&convertable_string), expected) 202 | } 203 | 204 | #[test] 205 | fn from_snake_case() { 206 | let convertable_string: String = "foo_bar".to_owned(); 207 | let expected: String = "Foo Bar".to_owned(); 208 | assert_eq!(to_title_case(&convertable_string), expected) 209 | } 210 | 211 | #[test] 212 | fn from_case_with_loads_of_space() { 213 | let convertable_string: String = "foo bar".to_owned(); 214 | let expected: String = "Foo Bar".to_owned(); 215 | assert_eq!(to_title_case(&convertable_string), expected) 216 | } 217 | 218 | #[test] 219 | fn a_name_with_a_dot() { 220 | let convertable_string: String = "Robert C. Martin".to_owned(); 221 | let expected: String = "Robert C Martin".to_owned(); 222 | assert_eq!(to_title_case(&convertable_string), expected) 223 | } 224 | 225 | #[test] 226 | fn random_text_with_bad_chars() { 227 | let convertable_string: String = "Random text with *(bad) chars".to_owned(); 228 | let expected: String = "Random Text With Bad Chars".to_owned(); 229 | assert_eq!(to_title_case(&convertable_string), expected) 230 | } 231 | 232 | #[test] 233 | fn trailing_bad_chars() { 234 | let convertable_string: String = "trailing bad_chars*(()())".to_owned(); 235 | let expected: String = "Trailing Bad Chars".to_owned(); 236 | assert_eq!(to_title_case(&convertable_string), expected) 237 | } 238 | 239 | #[test] 240 | fn leading_bad_chars() { 241 | let convertable_string: String = "-!#$%leading bad chars".to_owned(); 242 | let expected: String = "Leading Bad Chars".to_owned(); 243 | assert_eq!(to_title_case(&convertable_string), expected) 244 | } 245 | 246 | #[test] 247 | fn wrapped_in_bad_chars() { 248 | let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<>><>))".to_owned(); 249 | let expected: String = "Wrapped In Bad Chars".to_owned(); 250 | assert_eq!(to_title_case(&convertable_string), expected) 251 | } 252 | 253 | #[test] 254 | fn has_a_sign() { 255 | let convertable_string: String = "has a + sign".to_owned(); 256 | let expected: String = "Has A Sign".to_owned(); 257 | assert_eq!(to_title_case(&convertable_string), expected) 258 | } 259 | 260 | #[test] 261 | fn is_correct_from_camel_case() { 262 | let convertable_string: String = "fooBar".to_owned(); 263 | assert_eq!(is_title_case(&convertable_string), false) 264 | } 265 | 266 | #[test] 267 | fn is_correct_from_pascal_case() { 268 | let convertable_string: String = "FooBar".to_owned(); 269 | assert_eq!(is_title_case(&convertable_string), false) 270 | } 271 | 272 | #[test] 273 | fn is_correct_from_kebab_case() { 274 | let convertable_string: String = "foo-bar".to_owned(); 275 | assert_eq!(is_title_case(&convertable_string), false) 276 | } 277 | 278 | #[test] 279 | fn is_correct_from_sentence_case() { 280 | let convertable_string: String = "Foo bar".to_owned(); 281 | assert_eq!(is_title_case(&convertable_string), false) 282 | } 283 | 284 | #[test] 285 | fn is_correct_from_title_case() { 286 | let convertable_string: String = "Foo Bar".to_owned(); 287 | assert_eq!(is_title_case(&convertable_string), true) 288 | } 289 | 290 | #[test] 291 | fn is_correct_from_train_case() { 292 | let convertable_string: String = "Foo-Bar".to_owned(); 293 | assert_eq!(is_title_case(&convertable_string), false) 294 | } 295 | 296 | #[test] 297 | fn is_correct_from_screaming_snake_case() { 298 | let convertable_string: String = "FOO_BAR".to_owned(); 299 | assert_eq!(is_title_case(&convertable_string), false) 300 | } 301 | 302 | #[test] 303 | fn is_correct_from_snake_case() { 304 | let convertable_string: String = "foo_bar".to_owned(); 305 | assert_eq!(is_title_case(&convertable_string), false) 306 | } 307 | } 308 | 309 | -------------------------------------------------------------------------------- /src/cases/traincase/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | use cases::case::*; 3 | /// Determines if a `&str` is `Train-Case` 4 | /// 5 | /// ``` 6 | /// use inflector::cases::traincase::is_train_case; 7 | /// let mock_string: &str = "Foo-Bar-String-That-Is-Really-Really-Long"; 8 | /// let asserted_bool: bool = is_train_case(mock_string); 9 | /// assert!(asserted_bool == true); 10 | /// 11 | /// ``` 12 | /// 13 | /// ``` 14 | /// use inflector::cases::traincase::is_train_case; 15 | /// let mock_string: &str = "foo-bar-string-that-is-really-really-long"; 16 | /// let asserted_bool: bool = is_train_case(mock_string); 17 | /// assert!(asserted_bool == false); 18 | /// 19 | /// ``` 20 | /// 21 | /// ``` 22 | /// use inflector::cases::traincase::is_train_case; 23 | /// let mock_string: &str = "FooBarIsAReallyReallyLongString"; 24 | /// let asserted_bool: bool = is_train_case(mock_string); 25 | /// assert!(asserted_bool == false); 26 | /// 27 | /// ``` 28 | /// 29 | /// ``` 30 | /// use inflector::cases::traincase::is_train_case; 31 | /// let mock_string: &str = "fooBarIsAReallyReallyLongString"; 32 | /// let asserted_bool: bool = is_train_case(mock_string); 33 | /// assert!(asserted_bool == false); 34 | /// 35 | /// ``` 36 | /// 37 | /// ``` 38 | /// use inflector::cases::traincase::is_train_case; 39 | /// let mock_string: &str = "foo_bar_string_that_is_really_really_long"; 40 | /// let asserted_bool: bool = is_train_case(mock_string); 41 | /// assert!(asserted_bool == false); 42 | /// 43 | /// ``` 44 | /// 45 | /// ``` 46 | /// use inflector::cases::traincase::is_train_case; 47 | /// let mock_string: &str = "Foo bar string that is really really long"; 48 | /// let asserted_bool: bool = is_train_case(mock_string); 49 | /// assert!(asserted_bool == false); 50 | /// 51 | /// ``` 52 | /// 53 | /// ``` 54 | /// use inflector::cases::traincase::is_train_case; 55 | /// let mock_string: &str = "Foo Bar Is A Really Really Long String"; 56 | /// let asserted_bool: bool = is_train_case(mock_string); 57 | /// assert!(asserted_bool == false); 58 | /// 59 | /// ``` 60 | pub fn is_train_case(test_string: &str) -> bool { 61 | test_string == to_train_case(test_string.clone()) 62 | } 63 | 64 | 65 | /// Converts a `&str` to `Train-Case` `String` 66 | /// 67 | /// ``` 68 | /// use inflector::cases::traincase::to_train_case; 69 | /// let mock_string: &str = "foo-bar"; 70 | /// let expected_string: String = "Foo-Bar".to_string(); 71 | /// let asserted_string: String = to_train_case(mock_string); 72 | /// assert!(asserted_string == expected_string); 73 | /// 74 | /// ``` 75 | /// 76 | /// ``` 77 | /// use inflector::cases::traincase::to_train_case; 78 | /// let mock_string: &str = "FOO_BAR"; 79 | /// let expected_string: String = "Foo-Bar".to_string(); 80 | /// let asserted_string: String = to_train_case(mock_string); 81 | /// assert!(asserted_string == expected_string); 82 | /// 83 | /// ``` 84 | /// 85 | /// ``` 86 | /// use inflector::cases::traincase::to_train_case; 87 | /// let mock_string: &str = "foo_bar"; 88 | /// let expected_string: String = "Foo-Bar".to_string(); 89 | /// let asserted_string: String = to_train_case(mock_string); 90 | /// assert!(asserted_string == expected_string); 91 | /// 92 | /// ``` 93 | /// 94 | /// ``` 95 | /// use inflector::cases::traincase::to_train_case; 96 | /// let mock_string: &str = "Foo Bar"; 97 | /// let expected_string: String = "Foo-Bar".to_string(); 98 | /// let asserted_string: String = to_train_case(mock_string); 99 | /// assert!(asserted_string == expected_string); 100 | /// 101 | /// ``` 102 | /// 103 | /// ``` 104 | /// use inflector::cases::traincase::to_train_case; 105 | /// let mock_string: &str = "Foo bar"; 106 | /// let expected_string: String = "Foo-Bar".to_string(); 107 | /// let asserted_string: String = to_train_case(mock_string); 108 | /// assert!(asserted_string == expected_string); 109 | /// 110 | /// ``` 111 | /// 112 | /// ``` 113 | /// use inflector::cases::traincase::to_train_case; 114 | /// let mock_string: &str = "FooBar"; 115 | /// let expected_string: String = "Foo-Bar".to_string(); 116 | /// let asserted_string: String = to_train_case(mock_string); 117 | /// assert!(asserted_string == expected_string); 118 | /// 119 | /// ``` 120 | /// 121 | /// ``` 122 | /// use inflector::cases::traincase::to_train_case; 123 | /// let mock_string: &str = "fooBar"; 124 | /// let expected_string: String = "Foo-Bar".to_string(); 125 | /// let asserted_string: String = to_train_case(mock_string); 126 | /// assert!(asserted_string == expected_string); 127 | /// 128 | /// ``` 129 | pub fn to_train_case(non_train_case_string: &str) -> String { 130 | let options = CamelOptions { 131 | new_word: true, 132 | last_char: ' ', 133 | first_word: true, 134 | injectable_char: '-', 135 | has_seperator: true, 136 | inverted: false, 137 | }; 138 | to_case_camel_like(non_train_case_string, options) 139 | } 140 | 141 | #[cfg(all(feature = "unstable", test))] 142 | mod benchmarks { 143 | extern crate test; 144 | use self::test::Bencher; 145 | 146 | #[bench] 147 | fn bench_train(b: &mut Bencher) { 148 | b.iter(|| super::to_train_case("Foo bar")); 149 | } 150 | 151 | #[bench] 152 | fn bench_is_train(b: &mut Bencher) { 153 | b.iter(|| super::is_train_case("Foo bar")); 154 | } 155 | 156 | #[bench] 157 | fn bench_train_from_snake(b: &mut Bencher) { 158 | b.iter(|| super::to_train_case("test_test_test")); 159 | } 160 | 161 | } 162 | 163 | #[cfg(test)] 164 | mod tests { 165 | use ::to_train_case; 166 | use ::is_train_case; 167 | 168 | #[test] 169 | fn from_camel_case() { 170 | let convertable_string: String = "fooBar".to_owned(); 171 | let expected: String = "Foo-Bar".to_owned(); 172 | assert_eq!(to_train_case(&convertable_string), expected) 173 | } 174 | 175 | #[test] 176 | fn from_pascal_case() { 177 | let convertable_string: String = "FooBar".to_owned(); 178 | let expected: String = "Foo-Bar".to_owned(); 179 | assert_eq!(to_train_case(&convertable_string), expected) 180 | } 181 | 182 | #[test] 183 | fn from_kebab_case() { 184 | let convertable_string: String = "foo-bar".to_owned(); 185 | let expected: String = "Foo-Bar".to_owned(); 186 | assert_eq!(to_train_case(&convertable_string), expected) 187 | } 188 | 189 | #[test] 190 | fn from_sentence_case() { 191 | let convertable_string: String = "Foo bar".to_owned(); 192 | let expected: String = "Foo-Bar".to_owned(); 193 | assert_eq!(to_train_case(&convertable_string), expected) 194 | } 195 | 196 | #[test] 197 | fn from_title_case() { 198 | let convertable_string: String = "Foo Bar".to_owned(); 199 | let expected: String = "Foo-Bar".to_owned(); 200 | assert_eq!(to_train_case(&convertable_string), expected) 201 | } 202 | 203 | #[test] 204 | fn from_train_case() { 205 | let convertable_string: String = "Foo-Bar".to_owned(); 206 | let expected: String = "Foo-Bar".to_owned(); 207 | assert_eq!(to_train_case(&convertable_string), expected) 208 | } 209 | 210 | #[test] 211 | fn from_screaming_snake_case() { 212 | let convertable_string: String = "FOO_BAR".to_owned(); 213 | let expected: String = "Foo-Bar".to_owned(); 214 | assert_eq!(to_train_case(&convertable_string), expected) 215 | } 216 | 217 | #[test] 218 | fn from_snake_case() { 219 | let convertable_string: String = "foo_bar".to_owned(); 220 | let expected: String = "Foo-Bar".to_owned(); 221 | assert_eq!(to_train_case(&convertable_string), expected) 222 | } 223 | 224 | #[test] 225 | fn from_case_with_loads_of_space() { 226 | let convertable_string: String = "foo bar".to_owned(); 227 | let expected: String = "Foo-Bar".to_owned(); 228 | assert_eq!(to_train_case(&convertable_string), expected) 229 | } 230 | 231 | #[test] 232 | fn a_name_with_a_dot() { 233 | let convertable_string: String = "Robert C. Martin".to_owned(); 234 | let expected: String = "Robert-C-Martin".to_owned(); 235 | assert_eq!(to_train_case(&convertable_string), expected) 236 | } 237 | 238 | #[test] 239 | fn random_text_with_bad_chars() { 240 | let convertable_string: String = "Random text with *(bad) chars".to_owned(); 241 | let expected: String = "Random-Text-With-Bad-Chars".to_owned(); 242 | assert_eq!(to_train_case(&convertable_string), expected) 243 | } 244 | 245 | #[test] 246 | fn trailing_bad_chars() { 247 | let convertable_string: String = "trailing bad_chars*(()())".to_owned(); 248 | let expected: String = "Trailing-Bad-Chars".to_owned(); 249 | assert_eq!(to_train_case(&convertable_string), expected) 250 | } 251 | 252 | #[test] 253 | fn leading_bad_chars() { 254 | let convertable_string: String = "-!#$%leading bad chars".to_owned(); 255 | let expected: String = "Leading-Bad-Chars".to_owned(); 256 | assert_eq!(to_train_case(&convertable_string), expected) 257 | } 258 | 259 | #[test] 260 | fn wrapped_in_bad_chars() { 261 | let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<>><>))".to_owned(); 262 | let expected: String = "Wrapped-In-Bad-Chars".to_owned(); 263 | assert_eq!(to_train_case(&convertable_string), expected) 264 | } 265 | 266 | #[test] 267 | fn has_a_sign() { 268 | let convertable_string: String = "has a + sign".to_owned(); 269 | let expected: String = "Has-A-Sign".to_owned(); 270 | assert_eq!(to_train_case(&convertable_string), expected) 271 | } 272 | 273 | #[test] 274 | fn is_correct_from_camel_case() { 275 | let convertable_string: String = "fooBar".to_owned(); 276 | assert_eq!(is_train_case(&convertable_string), false) 277 | } 278 | 279 | #[test] 280 | fn is_correct_from_pascal_case() { 281 | let convertable_string: String = "FooBar".to_owned(); 282 | assert_eq!(is_train_case(&convertable_string), false) 283 | } 284 | 285 | #[test] 286 | fn is_correct_from_kebab_case() { 287 | let convertable_string: String = "foo-bar".to_owned(); 288 | assert_eq!(is_train_case(&convertable_string), false) 289 | } 290 | 291 | #[test] 292 | fn is_correct_from_sentence_case() { 293 | let convertable_string: String = "Foo bar".to_owned(); 294 | assert_eq!(is_train_case(&convertable_string), false) 295 | } 296 | 297 | #[test] 298 | fn is_correct_from_title_case() { 299 | let convertable_string: String = "Foo Bar".to_owned(); 300 | assert_eq!(is_train_case(&convertable_string), false) 301 | } 302 | 303 | #[test] 304 | fn is_correct_from_train_case() { 305 | let convertable_string: String = "Foo-Bar".to_owned(); 306 | assert_eq!(is_train_case(&convertable_string), true) 307 | } 308 | 309 | #[test] 310 | fn is_correct_from_screaming_snake_case() { 311 | let convertable_string: String = "FOO_BAR".to_owned(); 312 | assert_eq!(is_train_case(&convertable_string), false) 313 | } 314 | 315 | #[test] 316 | fn is_correct_from_snake_case() { 317 | let convertable_string: String = "foo_bar".to_owned(); 318 | assert_eq!(is_train_case(&convertable_string), false) 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /src/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")] 16 | extern 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 31 | pub mod cases; 32 | /// Provides number inflections 33 | /// - Ordinalize 34 | /// - Deordinalize 35 | pub mod numbers; 36 | /// Provides suffix inflections 37 | /// - Foreign key 38 | pub mod suffix; 39 | /// Provides string inflections 40 | /// - Deconstantize 41 | /// - Demodulize 42 | /// - Pluralize 43 | /// - Singularize 44 | #[cfg(feature = "heavyweight")] 45 | pub mod string; 46 | 47 | 48 | #[cfg(feature = "heavyweight")] 49 | use cases::classcase::to_class_case; 50 | #[cfg(feature = "heavyweight")] 51 | use cases::classcase::is_class_case; 52 | 53 | use cases::camelcase::to_camel_case; 54 | use cases::camelcase::is_camel_case; 55 | 56 | use cases::pascalcase::to_pascal_case; 57 | use cases::pascalcase::is_pascal_case; 58 | 59 | use cases::snakecase::to_snake_case; 60 | use cases::snakecase::is_snake_case; 61 | 62 | use cases::screamingsnakecase::to_screaming_snake_case; 63 | use cases::screamingsnakecase::is_screaming_snake_case; 64 | 65 | use cases::kebabcase::to_kebab_case; 66 | use cases::kebabcase::is_kebab_case; 67 | 68 | use cases::traincase::to_train_case; 69 | use cases::traincase::is_train_case; 70 | 71 | use cases::sentencecase::to_sentence_case; 72 | use cases::sentencecase::is_sentence_case; 73 | 74 | use cases::titlecase::to_title_case; 75 | use cases::titlecase::is_title_case; 76 | 77 | #[cfg(feature = "heavyweight")] 78 | use cases::tablecase::to_table_case; 79 | #[cfg(feature = "heavyweight")] 80 | use cases::tablecase::is_table_case; 81 | 82 | use numbers::ordinalize::ordinalize; 83 | use numbers::deordinalize::deordinalize; 84 | 85 | use suffix::foreignkey::to_foreign_key; 86 | use suffix::foreignkey::is_foreign_key; 87 | 88 | #[cfg(feature = "heavyweight")] 89 | use string::demodulize::demodulize; 90 | #[cfg(feature = "heavyweight")] 91 | use string::deconstantize::deconstantize; 92 | 93 | #[cfg(feature = "heavyweight")] 94 | use string::pluralize::to_plural; 95 | #[cfg(feature = "heavyweight")] 96 | use string::singularize::to_singular; 97 | 98 | #[allow(missing_docs)] 99 | pub 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)] 153 | pub trait InflectorNumbers { 154 | fn ordinalize(&self) -> String; 155 | } 156 | 157 | 158 | macro_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 | 169 | macro_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 | 180 | macro_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 | 192 | macro_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 | 233 | macro_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 | 245 | implement_string_for![ 246 | Inflector; 247 | String, str 248 | ]; 249 | 250 | implement_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))] 256 | mod 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 | } 333 | -------------------------------------------------------------------------------- /src/numbers/deordinalize/mod.rs: -------------------------------------------------------------------------------- 1 | /// Deorginalizes a `&str` 2 | /// 3 | /// ``` 4 | /// use inflector::numbers::deordinalize::deordinalize; 5 | /// let mock_string: &str = "0.1"; 6 | /// let expected_string: String = "0.1".to_owned(); 7 | /// let asserted_string: String = deordinalize(mock_string); 8 | /// assert!(asserted_string == expected_string); 9 | /// 10 | /// ``` 11 | /// ``` 12 | /// use inflector::numbers::deordinalize::deordinalize; 13 | /// let mock_string: &str = "-1st"; 14 | /// let expected_string: String = "-1".to_owned(); 15 | /// let asserted_string: String = deordinalize(mock_string); 16 | /// assert!(asserted_string == expected_string); 17 | /// 18 | /// ``` 19 | /// ``` 20 | /// use inflector::numbers::deordinalize::deordinalize; 21 | /// let mock_string: &str = "0th"; 22 | /// let expected_string: String = "0".to_owned(); 23 | /// let asserted_string: String = deordinalize(mock_string); 24 | /// assert!(asserted_string == expected_string); 25 | /// 26 | /// ``` 27 | /// ``` 28 | /// use inflector::numbers::deordinalize::deordinalize; 29 | /// let mock_string: &str = "1st"; 30 | /// let expected_string: String = "1".to_owned(); 31 | /// let asserted_string: String = deordinalize(mock_string); 32 | /// assert!(asserted_string == expected_string); 33 | /// 34 | /// ``` 35 | /// ``` 36 | /// use inflector::numbers::deordinalize::deordinalize; 37 | /// let mock_string: &str = "2nd"; 38 | /// let expected_string: String = "2".to_owned(); 39 | /// let asserted_string: String = deordinalize(mock_string); 40 | /// assert!(asserted_string == expected_string); 41 | /// 42 | /// ``` 43 | /// ``` 44 | /// use inflector::numbers::deordinalize::deordinalize; 45 | /// let mock_string: &str = "3rd"; 46 | /// let expected_string: String = "3".to_owned(); 47 | /// let asserted_string: String = deordinalize(mock_string); 48 | /// assert!(asserted_string == expected_string); 49 | /// 50 | /// ``` 51 | /// ``` 52 | /// use inflector::numbers::deordinalize::deordinalize; 53 | /// let mock_string: &str = "9th"; 54 | /// let expected_string: String = "9".to_owned(); 55 | /// let asserted_string: String = deordinalize(mock_string); 56 | /// assert!(asserted_string == expected_string); 57 | /// 58 | /// ``` 59 | /// ``` 60 | /// use inflector::numbers::deordinalize::deordinalize; 61 | /// let mock_string: &str = "12th"; 62 | /// let expected_string: String = "12".to_owned(); 63 | /// let asserted_string: String = deordinalize(mock_string); 64 | /// assert!(asserted_string == expected_string); 65 | /// 66 | /// ``` 67 | /// ``` 68 | /// use inflector::numbers::deordinalize::deordinalize; 69 | /// let mock_string: &str = "12000th"; 70 | /// let expected_string: String = "12000".to_owned(); 71 | /// let asserted_string: String = deordinalize(mock_string); 72 | /// assert!(asserted_string == expected_string); 73 | /// 74 | /// ``` 75 | /// ``` 76 | /// use inflector::numbers::deordinalize::deordinalize; 77 | /// let mock_string: &str = "12001th"; 78 | /// let expected_string: String = "12001".to_owned(); 79 | /// let asserted_string: String = deordinalize(mock_string); 80 | /// assert!(asserted_string == expected_string); 81 | /// 82 | /// ``` 83 | /// ``` 84 | /// use inflector::numbers::deordinalize::deordinalize; 85 | /// let mock_string: &str = "12002nd"; 86 | /// let expected_string: String = "12002".to_owned(); 87 | /// let asserted_string: String = deordinalize(mock_string); 88 | /// assert!(asserted_string == expected_string); 89 | /// 90 | /// ``` 91 | /// ``` 92 | /// use inflector::numbers::deordinalize::deordinalize; 93 | /// let mock_string: &str = "12003rd"; 94 | /// let expected_string: String = "12003".to_owned(); 95 | /// let asserted_string: String = deordinalize(mock_string); 96 | /// assert!(asserted_string == expected_string); 97 | /// 98 | /// ``` 99 | /// ``` 100 | /// use inflector::numbers::deordinalize::deordinalize; 101 | /// let mock_string: &str = "12004th"; 102 | /// let expected_string: String = "12004".to_owned(); 103 | /// let asserted_string: String = deordinalize(mock_string); 104 | /// assert!(asserted_string == expected_string); 105 | /// 106 | /// ``` 107 | pub fn deordinalize(non_ordinalized_string: &str) -> String { 108 | if non_ordinalized_string.contains('.') { 109 | non_ordinalized_string.to_owned() 110 | } else { 111 | non_ordinalized_string.trim_end_matches("st") 112 | .trim_end_matches("nd") 113 | .trim_end_matches("rd") 114 | .trim_end_matches("th") 115 | .to_owned() 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/numbers/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | /// Provides ordinalization of a string. 3 | /// 4 | /// Example string "1" becomes "1st" 5 | pub mod ordinalize; 6 | /// Provides deordinalization of a string. 7 | /// 8 | /// Example string "1st" becomes "1" 9 | pub mod deordinalize; 10 | -------------------------------------------------------------------------------- /src/numbers/ordinalize/mod.rs: -------------------------------------------------------------------------------- 1 | /// Orginalizes a `&str` 2 | /// 3 | /// ``` 4 | /// use inflector::numbers::ordinalize::ordinalize; 5 | /// let mock_string: &str = "a"; 6 | /// let expected_string: String = "a".to_owned(); 7 | /// let asserted_string: String = ordinalize(mock_string); 8 | /// assert!(asserted_string == expected_string); 9 | /// 10 | /// ``` 11 | /// ``` 12 | /// use inflector::numbers::ordinalize::ordinalize; 13 | /// let mock_string: &str = "0.1"; 14 | /// let expected_string: String = "0.1".to_owned(); 15 | /// let asserted_string: String = ordinalize(mock_string); 16 | /// assert!(asserted_string == expected_string); 17 | /// 18 | /// ``` 19 | /// ``` 20 | /// use inflector::numbers::ordinalize::ordinalize; 21 | /// let mock_string: &str = "-1"; 22 | /// let expected_string: String = "-1st".to_owned(); 23 | /// let asserted_string: String = ordinalize(mock_string); 24 | /// assert!(asserted_string == expected_string); 25 | /// 26 | /// ``` 27 | /// ``` 28 | /// use inflector::numbers::ordinalize::ordinalize; 29 | /// let mock_string: &str = "0"; 30 | /// let expected_string: String = "0th".to_owned(); 31 | /// let asserted_string: String = ordinalize(mock_string); 32 | /// assert!(asserted_string == expected_string); 33 | /// 34 | /// ``` 35 | /// ``` 36 | /// use inflector::numbers::ordinalize::ordinalize; 37 | /// let mock_string: &str = "1"; 38 | /// let expected_string: String = "1st".to_owned(); 39 | /// let asserted_string: String = ordinalize(mock_string); 40 | /// assert!(asserted_string == expected_string); 41 | /// 42 | /// ``` 43 | /// ``` 44 | /// use inflector::numbers::ordinalize::ordinalize; 45 | /// let mock_string: &str = "2"; 46 | /// let expected_string: String = "2nd".to_owned(); 47 | /// let asserted_string: String = ordinalize(mock_string); 48 | /// assert!(asserted_string == expected_string); 49 | /// 50 | /// ``` 51 | /// ``` 52 | /// use inflector::numbers::ordinalize::ordinalize; 53 | /// let mock_string: &str = "3"; 54 | /// let expected_string: String = "3rd".to_owned(); 55 | /// let asserted_string: String = ordinalize(mock_string); 56 | /// assert!(asserted_string == expected_string); 57 | /// 58 | /// ``` 59 | /// ``` 60 | /// use inflector::numbers::ordinalize::ordinalize; 61 | /// let mock_string: &str = "9"; 62 | /// let expected_string: String = "9th".to_owned(); 63 | /// let asserted_string: String = ordinalize(mock_string); 64 | /// assert!(asserted_string == expected_string); 65 | /// 66 | /// ``` 67 | /// ``` 68 | /// use inflector::numbers::ordinalize::ordinalize; 69 | /// let mock_string: &str = "12"; 70 | /// let expected_string: String = "12th".to_owned(); 71 | /// let asserted_string: String = ordinalize(mock_string); 72 | /// assert!(asserted_string == expected_string); 73 | /// 74 | /// ``` 75 | /// ``` 76 | /// use inflector::numbers::ordinalize::ordinalize; 77 | /// let mock_string: &str = "12000"; 78 | /// let expected_string: String = "12000th".to_owned(); 79 | /// let asserted_string: String = ordinalize(mock_string); 80 | /// assert!(asserted_string == expected_string); 81 | /// 82 | /// ``` 83 | /// ``` 84 | /// use inflector::numbers::ordinalize::ordinalize; 85 | /// let mock_string: &str = "12001"; 86 | /// let expected_string: String = "12001st".to_owned(); 87 | /// let asserted_string: String = ordinalize(mock_string); 88 | /// assert!(asserted_string == expected_string); 89 | /// 90 | /// ``` 91 | /// ``` 92 | /// use inflector::numbers::ordinalize::ordinalize; 93 | /// let mock_string: &str = "12002"; 94 | /// let expected_string: String = "12002nd".to_owned(); 95 | /// let asserted_string: String = ordinalize(mock_string); 96 | /// assert!(asserted_string == expected_string); 97 | /// 98 | /// ``` 99 | /// ``` 100 | /// use inflector::numbers::ordinalize::ordinalize; 101 | /// let mock_string: &str = "12003"; 102 | /// let expected_string: String = "12003rd".to_owned(); 103 | /// let asserted_string: String = ordinalize(mock_string); 104 | /// assert!(asserted_string == expected_string); 105 | /// 106 | /// ``` 107 | /// ``` 108 | /// use inflector::numbers::ordinalize::ordinalize; 109 | /// let mock_string: &str = "12004"; 110 | /// let expected_string: String = "12004th".to_owned(); 111 | /// let asserted_string: String = ordinalize(mock_string); 112 | /// assert!(asserted_string == expected_string); 113 | /// 114 | /// ``` 115 | pub fn ordinalize(non_ordinalized_string: &str) -> String { 116 | let chars: Vec = non_ordinalized_string.clone().chars().collect(); 117 | let last_number: char = chars[chars.len() - 1]; 118 | if is_ordinalizable(last_number) { 119 | return non_ordinalized_string.to_owned(); 120 | } 121 | if chars.len() > 1 { 122 | if second_last_number_is_one(chars) { 123 | return format!("{}{}", non_ordinalized_string, "th"); 124 | } else if string_contains_decimal(non_ordinalized_string.to_owned()) { 125 | return non_ordinalized_string.to_owned(); 126 | } 127 | } 128 | match last_number { 129 | '1' => format!("{}{}", non_ordinalized_string, "st"), 130 | '2' => format!("{}{}", non_ordinalized_string, "nd"), 131 | '3' => format!("{}{}", non_ordinalized_string, "rd"), 132 | _ => format!("{}{}", non_ordinalized_string, "th"), 133 | } 134 | } 135 | 136 | fn is_ordinalizable(last_number: char) -> bool { 137 | !last_number.is_numeric() 138 | } 139 | 140 | fn second_last_number_is_one(chars: Vec) -> bool { 141 | let second_last_number: char = chars[chars.len() - 2]; 142 | second_last_number == '1' 143 | } 144 | 145 | fn string_contains_decimal(non_ordinalized_string: String) -> bool { 146 | non_ordinalized_string.contains('.') 147 | } 148 | -------------------------------------------------------------------------------- /src/string/constants/mod.rs: -------------------------------------------------------------------------------- 1 | pub const UNACCONTABLE_WORDS: [&'static str; 202] = ["accommodation", 2 | "adulthood", 3 | "advertising", 4 | "advice", 5 | "aggression", 6 | "aid", 7 | "air", 8 | "aircraft", 9 | "alcohol", 10 | "anger", 11 | "applause", 12 | "arithmetic", 13 | "assistance", 14 | "athletics", 15 | 16 | "bacon", 17 | "baggage", 18 | "beef", 19 | "biology", 20 | "blood", 21 | "botany", 22 | "bread", 23 | "butter", 24 | 25 | "carbon", 26 | "cardboard", 27 | "cash", 28 | "chalk", 29 | "chaos", 30 | "chess", 31 | "crossroads", 32 | "countryside", 33 | 34 | "dancing", 35 | "deer", 36 | "dignity", 37 | "dirt", 38 | "dust", 39 | 40 | "economics", 41 | "education", 42 | "electricity", 43 | "engineering", 44 | "enjoyment", 45 | "envy", 46 | "equipment", 47 | "ethics", 48 | "evidence", 49 | "evolution", 50 | 51 | "fame", 52 | "fiction", 53 | "flour", 54 | "flu", 55 | "food", 56 | "fuel", 57 | "fun", 58 | "furniture", 59 | 60 | "gallows", 61 | "garbage", 62 | "garlic", 63 | "genetics", 64 | "gold", 65 | "golf", 66 | "gossip", 67 | "grammar", 68 | "gratitude", 69 | "grief", 70 | "guilt", 71 | "gymnastics", 72 | 73 | "happiness", 74 | "hardware", 75 | "harm", 76 | "hate", 77 | "hatred", 78 | "health", 79 | "heat", 80 | "help", 81 | "homework", 82 | "honesty", 83 | "honey", 84 | "hospitality", 85 | "housework", 86 | "humour", 87 | "hunger", 88 | "hydrogen", 89 | 90 | "ice", 91 | "importance", 92 | "inflation", 93 | "information", 94 | "innocence", 95 | "iron", 96 | "irony", 97 | 98 | "jam", 99 | "jewelry", 100 | "judo", 101 | 102 | "karate", 103 | "knowledge", 104 | 105 | "lack", 106 | "laughter", 107 | "lava", 108 | "leather", 109 | "leisure", 110 | "lightning", 111 | "linguine", 112 | "linguini", 113 | "linguistics", 114 | "literature", 115 | "litter", 116 | "livestock", 117 | "logic", 118 | "loneliness", 119 | "luck", 120 | "luggage", 121 | 122 | "macaroni", 123 | "machinery", 124 | "magic", 125 | "management", 126 | "mankind", 127 | "marble", 128 | "mathematics", 129 | "mayonnaise", 130 | "measles", 131 | "methane", 132 | "milk", 133 | "money", 134 | "mud", 135 | "music", 136 | "mumps", 137 | 138 | "nature", 139 | "news", 140 | "nitrogen", 141 | "nonsense", 142 | "nurture", 143 | "nutrition", 144 | 145 | "obedience", 146 | "obesity", 147 | "oxygen", 148 | 149 | "pasta", 150 | "patience", 151 | "physics", 152 | "poetry", 153 | "pollution", 154 | "poverty", 155 | "pride", 156 | "psychology", 157 | "publicity", 158 | "punctuation", 159 | 160 | "quartz", 161 | 162 | "racism", 163 | "relaxation", 164 | "reliability", 165 | "research", 166 | "respect", 167 | "revenge", 168 | "rice", 169 | "rubbish", 170 | "rum", 171 | 172 | "safety", 173 | "scenery", 174 | "seafood", 175 | "seaside", 176 | "series", 177 | "shame", 178 | "sheep", 179 | "shopping", 180 | "sleep", 181 | "smoke", 182 | "smoking", 183 | "snow", 184 | "soap", 185 | "software", 186 | "soil", 187 | "spaghetti", 188 | "species", 189 | "steam", 190 | "stuff", 191 | "stupidity", 192 | "sunshine", 193 | "symmetry", 194 | 195 | "tennis", 196 | "thirst", 197 | "thunder", 198 | "timber", 199 | "traffic", 200 | "transportation", 201 | "trust", 202 | 203 | "underwear", 204 | "unemployment", 205 | "unity", 206 | 207 | "validity", 208 | "veal", 209 | "vegetation", 210 | "vegetarianism", 211 | "vengeance", 212 | "violence", 213 | "vitality", 214 | 215 | "warmth", 216 | "wealth", 217 | "weather", 218 | "welfare", 219 | "wheat", 220 | "wildlife", 221 | "wisdom", 222 | "yoga", 223 | 224 | "zinc", 225 | "zoology"]; 226 | -------------------------------------------------------------------------------- /src/string/deconstantize/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "heavyweight")] 2 | use cases::classcase::to_class_case; 3 | 4 | #[cfg(feature = "heavyweight")] 5 | /// Deconstantizes a `&str` 6 | /// 7 | /// ``` 8 | /// use inflector::string::deconstantize::deconstantize; 9 | /// let mock_string: &str = "Bar"; 10 | /// let expected_string: String = "".to_owned(); 11 | /// let asserted_string: String = deconstantize(mock_string); 12 | /// assert!(asserted_string == expected_string); 13 | /// 14 | /// ``` 15 | /// ``` 16 | /// use inflector::string::deconstantize::deconstantize; 17 | /// let mock_string: &str = "::Bar"; 18 | /// let expected_string: String = "".to_owned(); 19 | /// let asserted_string: String = deconstantize(mock_string); 20 | /// assert!(asserted_string == expected_string); 21 | /// 22 | /// ``` 23 | /// ``` 24 | /// use inflector::string::deconstantize::deconstantize; 25 | /// let mock_string: &str = "Foo::Bar"; 26 | /// let expected_string: String = "Foo".to_owned(); 27 | /// let asserted_string: String = deconstantize(mock_string); 28 | /// assert!(asserted_string == expected_string); 29 | /// 30 | /// ``` 31 | /// ``` 32 | /// use inflector::string::deconstantize::deconstantize; 33 | /// let mock_string: &str = "Test::Foo::Bar"; 34 | /// let expected_string: String = "Foo".to_owned(); 35 | /// let asserted_string: String = deconstantize(mock_string); 36 | /// assert!(asserted_string == expected_string); 37 | /// 38 | /// ``` 39 | pub fn deconstantize(non_deconstantized_string: &str) -> String { 40 | if non_deconstantized_string.contains("::") { 41 | let split_string: Vec<&str> = non_deconstantized_string.split("::").collect(); 42 | if split_string.len() > 1 { 43 | to_class_case(split_string[split_string.len() - 2]) 44 | } else { 45 | "".to_owned() 46 | } 47 | } else { 48 | "".to_owned() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/string/demodulize/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "heavyweight")] 2 | use cases::classcase::to_class_case; 3 | 4 | #[cfg(feature = "heavyweight")] 5 | /// Demodulize a `&str` 6 | /// 7 | /// ``` 8 | /// use inflector::string::demodulize::demodulize; 9 | /// let mock_string: &str = "Bar"; 10 | /// let expected_string: String = "Bar".to_owned(); 11 | /// let asserted_string: String = demodulize(mock_string); 12 | /// assert!(asserted_string == expected_string); 13 | /// 14 | /// ``` 15 | /// ``` 16 | /// use inflector::string::demodulize::demodulize; 17 | /// let mock_string: &str = "::Bar"; 18 | /// let expected_string: String = "Bar".to_owned(); 19 | /// let asserted_string: String = demodulize(mock_string); 20 | /// assert!(asserted_string == expected_string); 21 | /// 22 | /// ``` 23 | /// ``` 24 | /// use inflector::string::demodulize::demodulize; 25 | /// let mock_string: &str = "Foo::Bar"; 26 | /// let expected_string: String = "Bar".to_owned(); 27 | /// let asserted_string: String = demodulize(mock_string); 28 | /// assert!(asserted_string == expected_string); 29 | /// 30 | /// ``` 31 | /// ``` 32 | /// use inflector::string::demodulize::demodulize; 33 | /// let mock_string: &str = "Test::Foo::Bar"; 34 | /// let expected_string: String = "Bar".to_owned(); 35 | /// let asserted_string: String = demodulize(mock_string); 36 | /// assert!(asserted_string == expected_string); 37 | /// 38 | /// ``` 39 | pub fn demodulize(non_demodulize_string: &str) -> String { 40 | if non_demodulize_string.contains("::") { 41 | let split_string: Vec<&str> = non_demodulize_string.split("::").collect(); 42 | to_class_case(split_string[split_string.len() - 1]) 43 | } else { 44 | non_demodulize_string.to_owned() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/string/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | /// Provides demodulize a string. 3 | /// 4 | /// Example string `Foo::Bar` becomes `Bar` 5 | #[cfg(feature = "heavyweight")] 6 | pub mod demodulize; 7 | /// Provides deconstantizea string. 8 | /// 9 | /// Example string `Foo::Bar` becomes `Foo` 10 | #[cfg(feature = "heavyweight")] 11 | pub mod deconstantize; 12 | /// Provides conversion to plural strings. 13 | /// 14 | /// Example string `FooBar` -> `FooBars` 15 | #[cfg(feature = "heavyweight")] 16 | pub mod pluralize; 17 | /// Provides conversion to singular strings. 18 | /// 19 | /// Example string `FooBars` -> `FooBar` 20 | #[cfg(feature = "heavyweight")] 21 | pub mod singularize; 22 | 23 | mod constants; 24 | -------------------------------------------------------------------------------- /src/string/pluralize/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | use regex::Regex; 3 | use string::constants::UNACCONTABLE_WORDS; 4 | 5 | macro_rules! add_rule{ 6 | ($r:ident, $rule:expr => $replace:expr) => { 7 | $r.push((Regex::new($rule).unwrap(), $replace)); 8 | } 9 | } 10 | 11 | macro_rules! rules{ 12 | ($r:ident; $($rule:expr => $replace:expr), *) => { 13 | $( 14 | add_rule!{$r, $rule => $replace} 15 | )* 16 | } 17 | } 18 | 19 | 20 | lazy_static!{ 21 | static ref RULES: Vec<(Regex, &'static str)> = { 22 | let mut r = Vec::with_capacity(24); 23 | rules![r; 24 | r"(\w*)s$" => "s", 25 | r"(\w*([^aeiou]ese))$" => "", 26 | r"(\w*(ax|test))is$" => "es", 27 | r"(\w*(alias|[^aou]us|tlas|gas|ris))$" => "es", 28 | r"(\w*(e[mn]u))s?$" => "s", 29 | r"(\w*([^l]ias|[aeiou]las|[emjzr]as|[iu]am))$" => "", 30 | r"(\w*(alumn|syllab|octop|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat))(?:us|i)$" => "i", 31 | r"(\w*(alumn|alg|vertebr))(?:a|ae)$" => "ae", 32 | r"(\w*(seraph|cherub))(?:im)?$" => "im", 33 | r"(\w*(her|at|gr))o$" => "oes", 34 | r"(\w*(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|automat|quor))(?:a|um)$" => "a", 35 | r"(\w*(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat))(?:a|on)$" => "a", 36 | r"(\w*)sis$" => "ses", 37 | r"(\w*(kni|wi|li))fe$" => "ves", 38 | r"(\w*(ar|l|ea|eo|oa|hoo))f$" => "ves", 39 | r"(\w*([^aeiouy]|qu))y$" => "ies", 40 | r"(\w*([^ch][ieo][ln]))ey$" => "ies", 41 | r"(\w*(x|ch|ss|sh|zz)es)$" => "", 42 | r"(\w*(x|ch|ss|sh|zz))$" => "es", 43 | r"(\w*(matr|cod|mur|sil|vert|ind|append))(?:ix|ex)$" => "ices", 44 | r"(\w*(m|l)(?:ice|ouse))$" => "ice", 45 | r"(\w*(pe)(?:rson|ople))$" => "ople", 46 | r"(\w*(child))(?:ren)?$" => "ren", 47 | r"(\w*eaux)$" => "" 48 | ]; 49 | r 50 | }; 51 | } 52 | 53 | macro_rules! special_cases{ 54 | ($s:ident, $($singular: expr => $plural:expr), *) => { 55 | match &$s[..] { 56 | $( 57 | $singular => { 58 | return $plural.to_owned(); 59 | }, 60 | )* 61 | _ => () 62 | } 63 | } 64 | } 65 | 66 | 67 | /// Converts a `&str` to pluralized `String` 68 | /// 69 | /// ``` 70 | /// use inflector::string::pluralize::to_plural; 71 | /// let mock_string: &str = "foo_bar"; 72 | /// let expected_string: String = "foo_bars".to_owned(); 73 | /// let asserted_string: String = to_plural(mock_string); 74 | /// assert_eq!(asserted_string, expected_string); 75 | /// 76 | /// ``` 77 | /// ``` 78 | /// use inflector::string::pluralize::to_plural; 79 | /// let mock_string: &str = "ox"; 80 | /// let expected_string: String = "oxen".to_owned(); 81 | /// let asserted_string: String = to_plural(mock_string); 82 | /// assert_eq!(asserted_string, expected_string); 83 | /// 84 | /// ``` 85 | /// ``` 86 | /// use inflector::string::pluralize::to_plural; 87 | /// let mock_string: &str = "crate"; 88 | /// let expected_string: String = "crates".to_owned(); 89 | /// let asserted_string: String = to_plural(mock_string); 90 | /// assert_eq!(asserted_string, expected_string); 91 | /// 92 | /// ``` 93 | /// ``` 94 | /// use inflector::string::pluralize::to_plural; 95 | /// let mock_string: &str = "boxes"; 96 | /// let expected_string: String = "boxes".to_owned(); 97 | /// let asserted_string: String = to_plural(mock_string); 98 | /// assert_eq!(asserted_string, expected_string); 99 | /// 100 | /// ``` 101 | /// ``` 102 | /// use inflector::string::pluralize::to_plural; 103 | /// let mock_string: &str = "vengeance"; 104 | /// let expected_string: String = "vengeance".to_owned(); 105 | /// let asserted_string: String = to_plural(mock_string); 106 | /// assert_eq!(asserted_string, expected_string); 107 | /// 108 | /// ``` 109 | /// ``` 110 | /// use inflector::string::pluralize::to_plural; 111 | /// let mock_string: &str = "yoga"; 112 | /// let expected_string: String = "yoga".to_owned(); 113 | /// let asserted_string: String = to_plural(mock_string); 114 | /// assert_eq!(asserted_string, expected_string); 115 | /// 116 | /// ``` 117 | /// ``` 118 | /// use inflector::string::pluralize::to_plural; 119 | /// let mock_string: &str = "geometry"; 120 | /// let expected_string: String = "geometries".to_owned(); 121 | /// let asserted_string: String = to_plural(mock_string); 122 | /// assert_eq!(asserted_string, expected_string); 123 | /// 124 | /// ``` 125 | /// 126 | pub fn to_plural(non_plural_string: &str) -> String { 127 | if UNACCONTABLE_WORDS.contains(&non_plural_string.as_ref()) { 128 | non_plural_string.to_owned() 129 | } else { 130 | special_cases![non_plural_string, 131 | "ox" => "oxen", 132 | "man" => "men", 133 | "woman" => "women", 134 | "die" => "dice", 135 | "yes" => "yeses", 136 | "foot" => "feet", 137 | "eave" => "eaves", 138 | "goose" => "geese", 139 | "tooth" => "teeth", 140 | "quiz" => "quizzes" 141 | ]; 142 | for &(ref rule, replace) in RULES.iter().rev() { 143 | if let Some(c) = rule.captures(&non_plural_string) { 144 | if let Some(c) = c.get(1) { 145 | return format!("{}{}", c.as_str(), replace); 146 | } 147 | } 148 | } 149 | 150 | format!("{}s", non_plural_string) 151 | } 152 | } 153 | 154 | 155 | #[cfg(test)] 156 | mod tests { 157 | 158 | macro_rules! as_item { 159 | ($i:item) => { $i }; 160 | } 161 | 162 | macro_rules! make_tests{ 163 | ($($singular:ident => $plural:ident); *) =>{ 164 | $( 165 | as_item! { 166 | #[test] 167 | fn $singular(){ 168 | assert_eq!( 169 | stringify!($plural), 170 | super::to_plural(stringify!($singular)) 171 | ); 172 | } 173 | } 174 | )* 175 | } 176 | } 177 | 178 | #[test] 179 | fn boxes() { 180 | assert_eq!("boxes", super::to_plural("box")); 181 | } 182 | 183 | make_tests!{ 184 | geometry => geometries; 185 | ox => oxen; 186 | woman => women; 187 | test => tests; 188 | axis => axes; 189 | knife => knives; 190 | agendum => agenda; 191 | elf => elves; 192 | zoology => zoology 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/string/singularize/mod.rs: -------------------------------------------------------------------------------- 1 | use regex::Regex; 2 | use string::constants::UNACCONTABLE_WORDS; 3 | 4 | macro_rules! special_cases{ 5 | ($s:ident, $($singular: expr => $plural:expr), *) => { 6 | match &$s[..] { 7 | $( 8 | $singular => { 9 | return $plural.to_owned(); 10 | }, 11 | )* 12 | _ => () 13 | } 14 | } 15 | } 16 | 17 | 18 | /// Converts a `&str` to singularized `String` 19 | /// 20 | /// ``` 21 | /// use inflector::string::singularize::to_singular; 22 | /// let mock_string: &str = "foo_bars"; 23 | /// let expected_string: String = "foo_bar".to_owned(); 24 | /// let asserted_string: String = to_singular(mock_string); 25 | /// assert!(asserted_string == expected_string); 26 | /// 27 | /// ``` 28 | /// ``` 29 | /// use inflector::string::singularize::to_singular; 30 | /// let mock_string: &str = "oxen"; 31 | /// let expected_string: String = "ox".to_owned(); 32 | /// let asserted_string: String = to_singular(mock_string); 33 | /// assert!(asserted_string == expected_string); 34 | /// 35 | /// ``` 36 | /// ``` 37 | /// use inflector::string::singularize::to_singular; 38 | /// let mock_string: &str = "crates"; 39 | /// let expected_string: String = "crate".to_owned(); 40 | /// let asserted_string: String = to_singular(mock_string); 41 | /// assert!(asserted_string == expected_string); 42 | /// 43 | /// ``` 44 | /// ``` 45 | /// use inflector::string::singularize::to_singular; 46 | /// let mock_string: &str = "oxen"; 47 | /// let expected_string: String = "ox".to_owned(); 48 | /// let asserted_string: String = to_singular(mock_string); 49 | /// assert!(asserted_string == expected_string); 50 | /// 51 | /// ``` 52 | /// ``` 53 | /// use inflector::string::singularize::to_singular; 54 | /// let mock_string: &str = "boxes"; 55 | /// let expected_string: String = "box".to_owned(); 56 | /// let asserted_string: String = to_singular(mock_string); 57 | /// assert!(asserted_string == expected_string); 58 | /// 59 | /// ``` 60 | /// ``` 61 | /// use inflector::string::singularize::to_singular; 62 | /// let mock_string: &str = "vengeance"; 63 | /// let expected_string: String = "vengeance".to_owned(); 64 | /// let asserted_string: String = to_singular(mock_string); 65 | /// assert!(asserted_string == expected_string); 66 | /// 67 | /// ``` 68 | /// ``` 69 | /// use inflector::string::singularize::to_singular; 70 | /// let mock_string: &str = "yoga"; 71 | /// let expected_string: String = "yoga".to_owned(); 72 | /// let asserted_string: String = to_singular(mock_string); 73 | /// assert!(asserted_string == expected_string); 74 | /// 75 | /// ``` 76 | /// 77 | pub fn to_singular(non_singular_string: &str) -> String { 78 | if UNACCONTABLE_WORDS.contains(&non_singular_string.as_ref()) { 79 | non_singular_string.to_owned() 80 | } else { 81 | special_cases![non_singular_string, 82 | "oxen" => "ox", 83 | "boxes" => "box", 84 | "men" => "man", 85 | "women" => "woman", 86 | "dice" => "die", 87 | "yeses" => "yes", 88 | "feet" => "foot", 89 | "eaves" => "eave", 90 | "geese" => "goose", 91 | "teeth" => "tooth", 92 | "quizzes" => "quiz" 93 | ]; 94 | for &(ref rule, replace) in RULES.iter().rev() { 95 | if let Some(captures) = rule.captures(&non_singular_string) { 96 | if let Some(c) = captures.get(1) { 97 | let mut buf = String::new(); 98 | captures.expand(&format!("{}{}", c.as_str(), replace), &mut buf); 99 | return buf; 100 | } 101 | } 102 | } 103 | 104 | format!("{}", non_singular_string) 105 | } 106 | } 107 | 108 | macro_rules! add_rule{ 109 | ($r:ident, $rule:expr => $replace:expr) => { 110 | $r.push((Regex::new($rule).unwrap(), $replace)); 111 | } 112 | } 113 | 114 | macro_rules! rules{ 115 | ($r:ident; $($rule:expr => $replace:expr), *) => { 116 | $( 117 | add_rule!{$r, $rule => $replace} 118 | )* 119 | } 120 | } 121 | 122 | 123 | lazy_static!{ 124 | static ref RULES: Vec<(Regex, &'static str)> = { 125 | let mut r = Vec::with_capacity(27); 126 | rules![r; 127 | r"(\w*)s$" => "", 128 | r"(\w*)(ss)$" => "$2", 129 | r"(n)ews$" => "ews", 130 | r"(\w*)(o)es$" => "", 131 | r"(\w*)([ti])a$" => "um", 132 | r"((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$" => "sis", 133 | r"(^analy)(sis|ses)$" => "sis", 134 | r"(\w*)([^f])ves$" => "fe", 135 | r"(\w*)(hive)s$" => "", 136 | r"(\w*)(tive)s$" => "", 137 | r"(\w*)([lr])ves$" => "f", 138 | r"(\w*([^aeiouy]|qu))ies$" => "y", 139 | r"(s)eries$" => "eries", 140 | r"(m)ovies$" => "ovie", 141 | r"(\w*)(x|ch|ss|sh)es$" => "$2", 142 | r"(m|l)ice$" => "ouse", 143 | r"(bus)(es)?$" => "", 144 | r"(shoe)s$" => "", 145 | r"(cris|test)(is|es)$" => "is", 146 | r"^(a)x[ie]s$" => "xis", 147 | r"(octop|vir)(us|i)$" => "us", 148 | r"(alias|status)(es)?$" => "", 149 | r"^(ox)en" => "", 150 | r"(vert|ind)ices$" => "ex", 151 | r"(matr)ices$" => "ix", 152 | r"(quiz)zes$" => "", 153 | r"(database)s$" => "" 154 | ]; 155 | r 156 | }; 157 | } 158 | 159 | #[test] 160 | fn singularize_ies_suffix() { 161 | assert_eq!("reply", to_singular("replies")); 162 | assert_eq!("lady", to_singular("ladies")); 163 | assert_eq!("soliloquy", to_singular("soliloquies")); 164 | } 165 | 166 | #[test] 167 | fn singularize_ss_suffix() { 168 | assert_eq!("glass", to_singular("glass")); 169 | assert_eq!("access", to_singular("access")); 170 | assert_eq!("glass", to_singular("glasses")); 171 | assert_eq!("witch", to_singular("witches")); 172 | assert_eq!("dish", to_singular("dishes")); 173 | } 174 | 175 | #[test] 176 | fn singularize_string_if_a_regex_will_match() { 177 | let expected_string: String = "ox".to_owned(); 178 | let asserted_string: String = to_singular("oxen"); 179 | assert!(expected_string == asserted_string); 180 | 181 | } 182 | 183 | #[test] 184 | fn singularize_string_returns_none_option_if_no_match() { 185 | let expected_string: String = "bacon".to_owned(); 186 | let asserted_string: String = to_singular("bacon"); 187 | 188 | assert!(expected_string == asserted_string); 189 | } 190 | -------------------------------------------------------------------------------- /src/suffix/foreignkey/mod.rs: -------------------------------------------------------------------------------- 1 | use cases::snakecase::to_snake_case; 2 | 3 | /// Converts a `&str` to a `foreign_key` 4 | /// 5 | /// ``` 6 | /// use inflector::suffix::foreignkey::to_foreign_key; 7 | /// let mock_string: &str = "foo_bar"; 8 | /// let expected_string: String = "foo_bar_id".to_owned(); 9 | /// let asserted_string: String = to_foreign_key(mock_string); 10 | /// assert!(asserted_string == expected_string); 11 | /// 12 | /// ``` 13 | /// ``` 14 | /// use inflector::suffix::foreignkey::to_foreign_key; 15 | /// let mock_string: &str = "Foo bar"; 16 | /// let expected_string: String = "foo_bar_id".to_owned(); 17 | /// let asserted_string: String = to_foreign_key(mock_string); 18 | /// assert!(asserted_string == expected_string); 19 | /// 20 | /// ``` 21 | /// ``` 22 | /// use inflector::suffix::foreignkey::to_foreign_key; 23 | /// let mock_string: &str = "Foo Bar"; 24 | /// let expected_string: String = "foo_bar_id".to_owned(); 25 | /// let asserted_string: String = to_foreign_key(mock_string); 26 | /// assert!(asserted_string == expected_string); 27 | /// 28 | /// ``` 29 | /// ``` 30 | /// use inflector::suffix::foreignkey::to_foreign_key; 31 | /// let mock_string: &str = "Foo::Bar"; 32 | /// let expected_string: String = "bar_id".to_owned(); 33 | /// let asserted_string: String = to_foreign_key(mock_string); 34 | /// assert!(asserted_string == expected_string); 35 | /// 36 | /// ``` 37 | /// ``` 38 | /// use inflector::suffix::foreignkey::to_foreign_key; 39 | /// let mock_string: &str = "Test::Foo::Bar"; 40 | /// let expected_string: String = "bar_id".to_owned(); 41 | /// let asserted_string: String = to_foreign_key(mock_string); 42 | /// assert!(asserted_string == expected_string); 43 | /// 44 | /// ``` 45 | /// ``` 46 | /// use inflector::suffix::foreignkey::to_foreign_key; 47 | /// let mock_string: &str = "FooBar"; 48 | /// let expected_string: String = "foo_bar_id".to_owned(); 49 | /// let asserted_string: String = to_foreign_key(mock_string); 50 | /// assert!(asserted_string == expected_string); 51 | /// 52 | /// ``` 53 | /// ``` 54 | /// use inflector::suffix::foreignkey::to_foreign_key; 55 | /// let mock_string: &str = "fooBar"; 56 | /// let expected_string: String = "foo_bar_id".to_owned(); 57 | /// let asserted_string: String = to_foreign_key(mock_string); 58 | /// assert!(asserted_string == expected_string); 59 | /// 60 | /// ``` 61 | /// ``` 62 | /// use inflector::suffix::foreignkey::to_foreign_key; 63 | /// let mock_string: &str = "fooBar3"; 64 | /// let expected_string: String = "foo_bar_3_id".to_owned(); 65 | /// let asserted_string: String = to_foreign_key(mock_string); 66 | /// assert!(asserted_string == expected_string); 67 | /// 68 | /// ``` 69 | pub fn to_foreign_key(non_foreign_key_string: &str) -> String { 70 | if non_foreign_key_string.contains("::") { 71 | let split_string: Vec<&str> = non_foreign_key_string.split("::").collect(); 72 | safe_convert(split_string[split_string.len() - 1]) 73 | } else { 74 | safe_convert(non_foreign_key_string) 75 | } 76 | } 77 | fn safe_convert(safe_string: &str) -> String { 78 | let snake_cased: String = to_snake_case(safe_string); 79 | if snake_cased.ends_with("_id") { 80 | snake_cased 81 | } else { 82 | format!("{}{}", snake_cased, "_id") 83 | } 84 | } 85 | 86 | /// Determines if a `&str` is a `foreign_key` 87 | /// 88 | /// ``` 89 | /// use inflector::suffix::foreignkey::is_foreign_key; 90 | /// let mock_string: &str = "Foo bar string that is really really long"; 91 | /// let asserted_bool: bool = is_foreign_key(mock_string); 92 | /// assert!(asserted_bool == false); 93 | /// 94 | /// ``` 95 | /// ``` 96 | /// use inflector::suffix::foreignkey::is_foreign_key; 97 | /// let mock_string: &str = "foo-bar-string-that-is-really-really-long"; 98 | /// let asserted_bool: bool = is_foreign_key(mock_string); 99 | /// assert!(asserted_bool == false); 100 | /// 101 | /// ``` 102 | /// ``` 103 | /// use inflector::suffix::foreignkey::is_foreign_key; 104 | /// let mock_string: &str = "FooBarIsAReallyReallyLongString"; 105 | /// let asserted_bool: bool = is_foreign_key(mock_string); 106 | /// assert!(asserted_bool == false); 107 | /// 108 | /// ``` 109 | /// ``` 110 | /// use inflector::suffix::foreignkey::is_foreign_key; 111 | /// let mock_string: &str = "Foo Bar Is A Really Really Long String"; 112 | /// let asserted_bool: bool = is_foreign_key(mock_string); 113 | /// assert!(asserted_bool == false); 114 | /// 115 | /// ``` 116 | /// ``` 117 | /// use inflector::suffix::foreignkey::is_foreign_key; 118 | /// let mock_string: &str = "fooBarIsAReallyReallyLongString"; 119 | /// let asserted_bool: bool = is_foreign_key(mock_string); 120 | /// assert!(asserted_bool == false); 121 | /// 122 | /// ``` 123 | /// ``` 124 | /// use inflector::suffix::foreignkey::is_foreign_key; 125 | /// let mock_string: &str = "foo_bar_string_that_is_really_really_long"; 126 | /// let asserted_bool: bool = is_foreign_key(mock_string); 127 | /// assert!(asserted_bool == false); 128 | /// 129 | /// ``` 130 | /// ``` 131 | /// use inflector::suffix::foreignkey::is_foreign_key; 132 | /// let mock_string: &str = "foo_bar_string_that_is_really_really_long_id"; 133 | /// let asserted_bool: bool = is_foreign_key(mock_string); 134 | /// assert!(asserted_bool == true); 135 | /// 136 | /// ``` 137 | pub fn is_foreign_key(test_string: &str) -> bool { 138 | to_foreign_key(test_string.clone()) == test_string 139 | } 140 | -------------------------------------------------------------------------------- /src/suffix/mod.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | /// Provides foreign key conversion for String. 3 | /// 4 | /// Example string `foo` becomes `foo_id` 5 | pub mod foreignkey; 6 | -------------------------------------------------------------------------------- /tests/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | extern crate inflector; 3 | 4 | use inflector::Inflector; 5 | use inflector::InflectorNumbers; 6 | 7 | macro_rules! str_tests { 8 | ( $($test_name:ident => $imp_trait:ident => $to_cast:expr => $casted:expr), *) => { 9 | $( 10 | #[test] 11 | fn $test_name() { 12 | assert_eq!($to_cast.$imp_trait(), $casted) 13 | } 14 | )* 15 | } 16 | } 17 | 18 | macro_rules! string_tests { 19 | ( $($test_name:ident => $imp_trait:ident => $to_cast:expr => $casted:expr), *) => { 20 | $( 21 | #[test] 22 | fn $test_name() { 23 | assert_eq!($to_cast.to_string().$imp_trait(), $casted) 24 | } 25 | )* 26 | } 27 | } 28 | 29 | macro_rules! number_tests { 30 | ( $($test_name:ident => $imp_trait:ident => $typ:ident => $to_cast:expr => $casted:expr), *) => { 31 | $( 32 | #[test] 33 | fn $test_name() { 34 | let to_cast: $typ = $to_cast; 35 | assert_eq!(to_cast.$imp_trait(), $casted) 36 | } 37 | )* 38 | } 39 | } 40 | 41 | macro_rules! gated_str_tests { 42 | ( $($test_name:ident => $imp_trait:ident => $to_cast:expr => $casted:expr), *) => { 43 | $( 44 | #[test] 45 | #[cfg(feature = "heavyweight")] 46 | fn $test_name() { 47 | assert_eq!($to_cast.$imp_trait(), $casted) 48 | } 49 | )* 50 | } 51 | } 52 | 53 | macro_rules! gated_string_tests { 54 | ( $($test_name:ident => $imp_trait:ident => $to_cast:expr => $casted:expr), *) => { 55 | $( 56 | #[test] 57 | #[cfg(feature = "heavyweight")] 58 | fn $test_name() { 59 | assert_eq!($to_cast.to_string().$imp_trait(), $casted) 60 | } 61 | )* 62 | } 63 | } 64 | 65 | str_tests![ 66 | str_to_camel => to_camel_case => "foo_bar" => "fooBar".to_string(), 67 | str_is_camel => is_camel_case => "fooBar" => true, 68 | str_is_not_camel => is_camel_case => "foo_bar" => false, 69 | str_to_screaming_snake => to_screaming_snake_case => "fooBar" => "FOO_BAR".to_string(), 70 | str_is_screaming_snake => is_screaming_snake_case => "FOO_BAR" => true, 71 | str_is_not_screaming_snake => is_screaming_snake_case => "foo_bar" => false, 72 | str_to_snake => to_snake_case => "fooBar" => "foo_bar".to_string(), 73 | str_is_snake => is_snake_case => "foo_bar" => true, 74 | str_is_not_snake => is_snake_case => "fooBar" => false, 75 | str_to_kebab => to_kebab_case => "fooBar" => "foo-bar".to_string(), 76 | str_is_kebab => is_kebab_case => "foo-bar" => true, 77 | str_is_not_kebab => is_kebab_case => "fooBar" => false, 78 | str_to_train => to_train_case => "fooBar" => "Foo-Bar".to_string(), 79 | str_is_train => is_train_case => "Foo-Bar" => true, 80 | str_is_not_train => is_train_case => "FOO-Bar" => false, 81 | str_to_sentence => to_sentence_case => "fooBar" => "Foo bar".to_string(), 82 | str_is_sentence => is_sentence_case => "Foo bar" => true, 83 | str_is_not_sentence => is_sentence_case => "foo_bar" => false, 84 | str_to_title => to_title_case => "fooBar" => "Foo Bar".to_string(), 85 | str_is_title => is_title_case => "Foo Bar" => true, 86 | str_is_not_title => is_title_case => "Foo_Bar" => false, 87 | str_ordinalize => ordinalize => "1" => "1st".to_string(), 88 | str_deordinalize => deordinalize => "1st" => "1".to_string(), 89 | str_to_foreign_key => to_foreign_key => "Foo::Bar" => "bar_id".to_string(), 90 | str_is_foreign_key => is_foreign_key => "bar_id" => true, 91 | str_is_not_foreign_key => is_foreign_key => "bar" => false 92 | ]; 93 | 94 | gated_str_tests![ 95 | str_to_class_case => to_class_case => "foo" => "Foo".to_string(), 96 | str_is_class_case => is_class_case => "Foo" => true, 97 | str_is_not_class_case => is_class_case => "foo" => false, 98 | str_to_table => to_table_case => "fooBar" => "foo_bars".to_string(), 99 | str_is_table => is_table_case => "foo_bars" => true, 100 | str_is_not_table => is_table_case => "fooBars" => false, 101 | str_pluralize => to_plural => "crate" => "crates".to_string(), 102 | str_singular => to_singular => "crates" => "crate".to_string(), 103 | str_demodulize => demodulize => "Foo::Bar" => "Bar".to_string(), 104 | str_deconstantize => deconstantize => "Foo::Bar" => "Foo".to_string() 105 | ]; 106 | 107 | string_tests![ 108 | string_to_camel => to_camel_case => "foo_bar".to_string() => "fooBar".to_string(), 109 | string_is_camel => is_camel_case => "fooBar".to_string() => true, 110 | string_is_not_camel => is_camel_case => "foo_bar".to_string() => false, 111 | string_to_screaming_snake => to_screaming_snake_case => "fooBar".to_string() => "FOO_BAR".to_string(), 112 | string_is_screaming_snake => is_screaming_snake_case => "FOO_BAR".to_string() => true, 113 | string_is_not_screaming_snake => is_screaming_snake_case => "foo_bar".to_string() => false, 114 | string_to_snake => to_snake_case => "fooBar".to_string() => "foo_bar".to_string(), 115 | string_is_snake => is_snake_case => "foo_bar".to_string() => true, 116 | string_is_not_snake => is_snake_case => "fooBar".to_string() => false, 117 | string_to_kebab => to_kebab_case => "fooBar".to_string() => "foo-bar".to_string(), 118 | string_is_kebab => is_kebab_case => "foo-bar".to_string() => true, 119 | string_is_not_kebab => is_kebab_case => "fooBar".to_string() => false, 120 | string_to_train => to_train_case => "fooBar".to_string() => "Foo-Bar".to_string(), 121 | string_is_train => is_train_case => "Foo-Bar".to_string() => true, 122 | string_is_not_train => is_train_case => "foo-Bar".to_string() => false, 123 | string_to_sentence => to_sentence_case => "fooBar".to_string() => "Foo bar".to_string(), 124 | string_is_sentence => is_sentence_case => "Foo bar".to_string() => true, 125 | string_is_not_sentence => is_sentence_case => "fooBar".to_string() => false, 126 | string_to_title => to_title_case => "fooBar".to_string() => "Foo Bar".to_string(), 127 | string_is_title => is_title_case => "Foo Bar".to_string() => true, 128 | string_is_not_title => is_title_case => "fooBar".to_string() => false, 129 | string_ordinalize => ordinalize => "1".to_string() => "1st".to_string(), 130 | string_deordinalize => deordinalize => "1st".to_string() => "1".to_string(), 131 | string_to_foreign_key => to_foreign_key => "Foo::Bar".to_string() => "bar_id".to_string(), 132 | string_is_foreign_key => is_foreign_key => "bar_id".to_string() => true, 133 | string_is_not_foreign_key => is_foreign_key => "bar".to_string() => false 134 | ]; 135 | 136 | gated_string_tests![ 137 | string_to_class_case => to_class_case => "foo".to_string() => "Foo".to_string(), 138 | string_is_class_case => is_class_case => "Foo".to_string() => true, 139 | string_is_not_class_case => is_class_case => "ooBar".to_string() => false, 140 | string_to_table => to_table_case => "fooBar".to_string() => "foo_bars".to_string(), 141 | string_is_table => is_table_case => "foo_bars".to_string() => true, 142 | string_is_not_table => is_table_case => "fooBar".to_string() => false, 143 | string_pluralize => to_plural => "crate".to_string() => "crates".to_string(), 144 | string_singular => to_singular => "crates".to_string() => "crate".to_string(), 145 | string_demodulize => demodulize => "Foo::Bar".to_string() => "Bar".to_string(), 146 | string_deconstantize => deconstantize => "Foo::Bar".to_string() => "Foo".to_string() 147 | ]; 148 | 149 | number_tests![ 150 | i8_ordinalize => ordinalize => i8 => 1 => "1st".to_string(), 151 | i16_ordinalize => ordinalize => i16 => 1 => "1st".to_string(), 152 | i32_ordinalize => ordinalize => i32 => 1 => "1st".to_string(), 153 | i64_ordinalize => ordinalize => i64 => 1 => "1st".to_string(), 154 | u8_ordinalize => ordinalize => u8 => 1 => "1st".to_string(), 155 | u16_ordinalize => ordinalize => u16 => 1 => "1st".to_string(), 156 | u32_ordinalize => ordinalize => u32 => 1 => "1st".to_string(), 157 | u64_ordinalize => ordinalize => u64 => 1 => "1st".to_string(), 158 | isize_ordinalize => ordinalize => isize => 1 => "1st".to_string(), 159 | usize_ordinalize => ordinalize => usize => 1 => "1st".to_string(), 160 | f32_ordinalize => ordinalize => f32 => 1.0 => "1st".to_string(), 161 | f64_ordinalize => ordinalize => f64 => 1.0 => "1st".to_string() 162 | ]; 163 | --------------------------------------------------------------------------------