Giter Club home page Giter Club logo

heck's Introduction

heck is a case conversion library

"I specifically requested the opposite of this."

This library exists to provide case conversion between common cases like CamelCase and snake_case. It is intended to be unicode aware, internally consistent, and reasonably well performing.

Definition of a word boundary

Word boundaries are defined by non-alphanumeric characters, as well as within those words in this manner:

  1. If an uppercase character is followed by lowercase letters, a word boundary is considered to be just prior to that uppercase character.
  2. If multiple uppercase characters are consecutive, they are considered to be within a single word, except that the last will be part of the next word if it is followed by lowercase characters (see rule 1).

That is, "HelloWorld" is segmented Hello|World whereas "XMLHttpRequest" is segmented XML|Http|Request.

Characters not within words (such as spaces, punctuations, and underscores) are not included in the output string except as they are a part of the case being converted to. Multiple adjacent word boundaries (such as a series of underscores) are folded into one. ("hello__world" in snake case is therefore "hello_world", not the exact same string). Leading or trailing word boundary indicators are dropped, except insofar as CamelCase capitalizes the first word.

Cases contained in this library:

  1. UpperCamelCase
  2. lowerCamelCase
  3. snake_case
  4. kebab-case
  5. SHOUTY_SNAKE_CASE
  6. Title Case
  7. SHOUTY-KEBAB-CASE
  8. Train-Case

MSRV

The minimum supported Rust version for this crate is 1.56.0. This may change in minor or patch releases, but we probably won't ever require a very recent version. If you would like to have a stronger guarantee than that, please open an issue.

License

heck is distributed under the terms of both the MIT license and the Apache License (Version 2.0).

See LICENSE-APACHE and LICENSE-MIT for details.

heck's People

Contributors

danburkert avatar efx avatar erickt avatar jplatte avatar osspial avatar rblaine95 avatar rj00a avatar sof3 avatar tgockel avatar withoutboats avatar xiretza avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

heck's Issues

MSRV 1.21.0 -> 1.32.0 in 0.3.2

This ticket doesn't require action, its just for your information.

Testing indicates that 0.3.2 changes the effective MSRV from 1.21.0 to 1.32.0

https://kentfredric.github.io/rust-vmatrix/crates-h/he/heck/

snapshot_20201222_121923

The failure on Rust < 1.32.0 is

   Compiling heck v0.3.2                                                                                   
     Running `rustc --edition=2018 --crate-name heck /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs --color always --crate-type lib --emit=dep-info,link -C debuginfo=2 -C metadata=32eb5a3c0212b004 -C extra-filename=-32eb5a3c0212b004 --out-dir /tmp/qytZ3MVwzh/vcheck_pl/heck-rustc1_31_1_1/target/debug/deps -L dependency=/tmp/qytZ3MVwzh/vcheck_pl/heck-rustc1_31_1_1/target/debug/deps --extern unicode_segmentation=/tmp/qytZ3MVwzh/vcheck_pl/heck-rustc1_31_1_1/target/debug/deps/libunicode_segmentation-6857939efaf46537.rlib --cap-lints allow -C linker=x86_64-pc-linux-gnu-gcc`
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:48:9
   |                                                                                                       
40 | mod camel;                                                                                            
   | ---------- not an extern crate passed with `--extern`                                                 
...                                                                                                        
48 | pub use camel::CamelCase;                                                                             
   |         ^^^^^                                                                                         
   |                                                                                                       
note: this import refers to the module defined here                                                        
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:40:1
   |                                                                                                       
40 | mod camel;                                                                                            
   | ^^^^^^^^^^                                                                                            
                                                                                                           
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:49:9
   |                                                                                                       
41 | mod kebab;                                                                                            
   | ---------- not an extern crate passed with `--extern`                                                 
...                                                                                                        
49 | pub use kebab::KebabCase;                                                                             
   |         ^^^^^                                                                                         
   |                                                                                                       
note: this import refers to the module defined here                                                        
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:41:1
   |                                                                                                       
41 | mod kebab;                                                                                            
   | ^^^^^^^^^^                                                                                            
                                                                                                           
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:50:9
   |                                                                                                       
42 | mod mixed;                                                                                            
   | ---------- not an extern crate passed with `--extern`                                                 
...                                                                                                        
50 | pub use mixed::MixedCase;                                                                             
   |         ^^^^^                                                                                         
   |                                                                                                       
note: this import refers to the module defined here                                                        
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:42:1
   |                                                                                                       
42 | mod mixed;                                                                                            
   | ^^^^^^^^^^                                                                                            
                                                                                                           
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:51:9
   |                                                                                                       
43 | mod shouty_kebab;                                                                                     
   | ----------------- not an extern crate passed with `--extern`                                          
...                                                                                                        
51 | pub use shouty_kebab::ShoutyKebabCase;                                                                
   |         ^^^^^^^^^^^^                                                                                  
   |                                                                                                       
note: this import refers to the module defined here                                                        
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:43:1
   |                                                                                                       
43 | mod shouty_kebab;                                                                                     
   | ^^^^^^^^^^^^^^^^^                                                                                     
                                                                                                           
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:52:9
   |                                                                                                       
44 | mod shouty_snake;                                                                                     
   | ----------------- not an extern crate passed with `--extern`                                          
...                                                                                                        
52 | pub use shouty_snake::{ShoutySnakeCase, ShoutySnekCase};                                              
   |         ^^^^^^^^^^^^                                                                                  
   |                                                                                                       
note: this import refers to the module defined here                                                        
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:44:1
   |                                                                                                       
44 | mod shouty_snake;                                                                                     
   | ^^^^^^^^^^^^^^^^^                                                                                     
                                                                                                           
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:53:9
   |                                                                                                       
45 | mod snake;                                                                                            
   | ---------- not an extern crate passed with `--extern`                                                 
...                                                                                                        
53 | pub use snake::{SnakeCase, SnekCase};                                                                 
   |         ^^^^^                                                                                         
   |                                                                                                       
note: this import refers to the module defined here                                                        
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:45:1
   |                                                                                                       
45 | mod snake;                                                                                            
   | ^^^^^^^^^^                                                                                            
                                                                                                           
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:54:9
   |                                                                                                       
46 | mod title;                                                                                            
   | ---------- not an extern crate passed with `--extern`                                                 
...                                                                                                        
54 | pub use title::TitleCase;                                                                             
   |         ^^^^^                                                                                         
   |                                                                                                       
note: this import refers to the module defined here                                                        
  --> /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs:46:1
   |                                                                                                       
46 | mod title;                                                                                            
   | ^^^^^^^^^^                                                                                            
                                                                                                           
error: aborting due to 7 previous errors                                                                   
                                                                                                           
For more information about this error, try `rustc --explain E0658`.                                        
error: Could not compile `heck`.                                                                           

Caused by:
  process didn't exit successfully: `rustc --edition=2018 --crate-name heck /tmp/qytZ3MVwzh/vcheck_pl/cargo_1/.cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.2/src/lib.rs --color always --crate-type lib --emit=dep-info,link -C debuginfo=2 -C metadata=32eb5a3c0212b004 -C extra-filename=-32eb5a3c0212b004 --out-dir /tmp/qytZ3MVwzh/vcheck_pl/heck-rustc1_31_1_1/target/debug/deps -L dependency=/tmp/qytZ3MVwzh/vcheck_pl/heck-rustc1_31_1_1/target/debug/deps --extern unicode_segmentation=/tmp/qytZ3MVwzh/vcheck_pl/heck-rustc1_31_1_1/target/debug/deps/libunicode_segmentation-6857939efaf46537.rlib --cap-lints allow -C linker=x86_64-pc-linux-gnu-gcc` (exit code: 1)
>>>> rustc 1.31.1 w/ heck version 0.3.2 fail

Casual observation suggests this regression was introduced by this change:

d750607

I believe there is sometimes some value in incrementing semver when changing minimum supported rust.

Though documenting the minimum supported rust somewhere top-level (README) also goes a long way.

Setting up a CI server to check your documented MSRV sticks is also quite welcome.

In the event this issue is not helpful, just let me know and I'll try to avoid filing similar issues on this crate in future.

NB: I don't directly use heck, I'm just doing build testing across the ecosystem.

Handle Japanese character more correctly

The way heck handle some languages seems to be incorrect. In languages like Japanese or Chinese their is usually no spaces between words, however heck detect some between every characters.
See Plume-org/Plume#326 for more details, when using kebab-case.
(I personally don't speak Japanese nor Chinese)

[feature] Option to treat consecutive uppercase characters in PascalCase as separate words

From the docs:

That is, “HelloWorld” is segmented Hello|World whereas “XMLHttpRequest” is segmented XML|Http|Request.

I have identifiers with single character words in them. I'd love it if they were snake_cased as separate words, e.g.:

assert_eq!("ABCD".to_snake_case_from_pascal_case_strict() == "a_b_c_d")
assert_eq!("ABCcD".to_snake_case_from_pascal_case_strict() == "a_b_cc_d")

This would be the exact inverse of to_pascal_case() for snake_case text, i.e.:

assert_eq!(text.to_snake_case().to_pascal_case().to_snake_case_from_pascal_case_strict() == text.to_snake_case())

Plaground link

Sentence case

Is it possible to add sentence case?

Sentence case is when only the first letter of the first word is capitalised.

Maintainance status

Hey!

Seeing that the last commit happened on December 2018 and the repository has some new feature PRs that haven't been touched for partially 2 years: What is the maintenance status of the crate? It seems "abandoned" at this point. The last merge was the license update in the README file.

The crate is heavily used in the Rust ecosystem, with 469,000 downloads this month alone, being used in 169 crates directly and 2,767 crates transitively. It would be a shame to let the crate be. I know that new features aren't always appreciated, but new text transformations are something that fit perfectly into heck ;)

That being said, if your capacities are low and you can't invest the time at the moment, I'd like to offer to sort out issues and merge PRs accordingly. I already do this for env_logger under the @env-logger-rs organization. And that is a crate that is as much used as this one :)

A viable alternative would be to move it to an organization, allowing for easier collaboration and allows people to add new maintainers if wished.

Thanks for taking your time to read this!
/cc @withoutboats @erickt

Consider making the `transform` function public

It'd be convenient if transform was public.

Someone with a more esoteric case that doesn't make sense to build in (say lowercase.separated.by.dots) can re-use the same word boundary separator logic for that and for the more usual cases.

Features not behaving additively

I ran into issues using a library that had this library at two places in the dependency graph.

as noted for the example below when the Unicode feature is enabled it changes the observed behavior of seemly non-Unicode strings

I would expect the bellow test to pass and have the same behavior both with:
cargo test
cargo test --features unicode (outputs Entity.allay.ambientWithItem instead of the behavior bellow)

t!(test9: "entity.allay.ambient_with_item" => "EntityAllayAmbientWithItem");

Consider renaming traits to `ToSnekCase`, etc

I think the standard naming convention for one method verb trait is Verb. That is, in case of heck, I think it's more idiomatic to prepend To to each trait. This might be a good occasion to publish 1.0 as well :D

Consider supporting "UPPER CASE"

There is already "Title Case" so it seems it would make sense to also support converting all letters to upper case and keeping the separator spaces.

Plurals of abbreviations are converted from mixed/title to snake incorrectly

Test cases from here. (I had the same problem in that code.)

extern crate heck;

use heck::SnakeCase;

fn main() {
    // Some cases of "ABc" should be converted to "abc" instead of "a_bc".
    // Mostly (always?) happens with plurals of abbreviations.

    assert_eq!("JSONSchemas".to_snake_case(), "json_schemas"); // Actual: json_schemas
    assert_eq!("externalIPs".to_snake_case(), "external_ips"); // Actual: external_i_ps
    assert_eq!("nonResourceURLs".to_snake_case(), "non_resource_urls"); // Actual: non_resource_ur_ls
    assert_eq!("serverAddressByClientCIDRs".to_snake_case(), "server_address_by_client_cidrs"); // Actual: server_address_by_client_cid_rs
    assert_eq!("targetWWNs".to_snake_case(), "target_wwns"); // Actual: target_ww_ns
}

UTS 55 conformance

Unicode Technical Standard #55 specifies a concept of "identifier word boundary":

An identifier word boundary is defined by the following rules, using the notation from Section 1.1, Notation, in Unicode Standard Annex #29, Unicode Text Segmentation [UAX29].

Treat a letter followed by a sequence of nonspacing or enclosing marks as that letter.

The regular expressions for the following rules incorporate this one; only the text descriptions rely on it.

🐫 CamelBoundary. An identifier word boundary exists after a lowercase or non-Greek titlecase letter followed by an uppercase or titlecase letter:

[ \p{Ll} [\p{Lt}-\p{Grek}] ] [\p{Mn}\p{Me}]* ÷ [\p{Lu}\p{Lt}]

🎩 HATBoundary. An identifier word boundary exists before an uppercase or titlecase letter followed by a lowercase letter, or before a non-Greek titlecase letter:

÷ [\p{Lu}\p{Lt}] [\p{Mn}\p{Me}]* \p{Ll} | [\p{Lt}-\p{Grek}]

🐍 snake_boundary. An identifier word boundary exists either side either side of a Punctuation character which is not an Other_Punctuation character:

÷ [\p{P}-\p{Po}]
[\p{P}-\p{Po}] ÷

No other identifier word boundaries exist.

Any × Any

It would be nice if heck could follow this spec.

Release 0.3.4

#27 is not a breaking change, so I'd like to release it as v0.3.4. This means creating a branch for v0.3.x off the "Forbid unsafe code" commit, since the one after that introduced a breaking change.

Additionally to minimize breakage when the current traits are removed in favor of methods on the ConvertCase trait (the more I think about it the more I like that idea), the new methods should immediately be available with the old ones being deprecated. This means that the most obvious upgrade path if one doesn't want deprecation warnings is switching everything to the new trait directly, minimizing the possibility of ambiguity errors for the method calls.

Case-insensitive equality/ordering

Is it practical to compare strings in a snek-case-insensitive manner? I would like to know whether two strings are convertible to the same SnekCase/CamelCase/etc. without allocating a new String to hold the intermediates. Can heck's internal methods, such as transform, help with such needs?

Not same snake_case conversion than serde

I've noticed that uppercase strings are treated differently by heck and serde, example:

use heck::ToSnakeCase;

#[derive(serde::Serialize)]
#[serde(rename_all="snake_case")]
enum Test{
    A1,
    Bc2,
    ED3, 
}

fn main(){
    assert_eq!(serde_json_to_string(Test::A1),"A1".to_snake_case());
    assert_eq!(serde_json_to_string(Test::Bc2),"Bc2".to_snake_case());
    assert_eq!(serde_json_to_string(Test::ED3),"ED3".to_snake_case());
}

fn serde_json_to_string(value : Test) -> String{
   serde_json::to_value(&value).unwrap().as_str().unwrap().to_owned()
}

output :

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `"e_d3"`,
 right: `"ed3"`', src/main.rs:14:5

Unexpected casing when using numbers

This seems very related to #18.

When converting v1alpha1 to PascalCase, I expect the result to be V1Alpha1, however, V1alpha1 is produced. Adding an API mentioned in #18 (comment) could solve this issue by setting number_starts_word: true.

Is there currently any way to produce the expected outcome, or should this be accepted as intended behaviour?

Consider a different word boundary rule

If a series of multiple uppercase characters is followed by 1 or more lowercase letter, consider placing the word boundary before the last uppercase letter.

That is: "HELLOWorld" -> "HELLO|World" rather than "HELLOW|orld".

But if there are no lowercase characters after, the word boundary is not inserted. "HELLO_world" -> "HELLO|world" not "HELL|O|world".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.