Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Header-Case #9

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
.PHONY: benchmark docs lint test

docs:
which godoc2ghmd || ( go get github.com/DevotedHealth/godoc2ghmd && go mod tidy )
which godoc2ghmd || go install github.com/DevotedHealth/godoc2ghmd
godoc2ghmd -template .readme.tmpl github.com/ettle/strcase > README.md

test:
go test -cover ./...

lint:
which golangci-lint || ( go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.27.0 && go mod tidy )
which golangci-lint || go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.27.0
golangci-lint run
golangci-lint run benchmark/*.go

Expand Down
70 changes: 47 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Example usage

strcase.ToKebab("helloWorld") // hello-world
strcase.ToKEBAB("helloWorld") // HELLO-WORLD
strcase.ToHeader("helloWorld") // Hello-World

strcase.ToPascal("hello-world") // HelloWorld
strcase.ToCamel("hello-world") // helloWorld
Expand All @@ -32,7 +33,7 @@ Example usage
strcase.ToSnake("FOOBar") // foo_bar

// Support Go initialisms
strcase.ToGoCamel("http_response") // HTTPResponse
strcase.ToGoPascal("http_response") // HTTPResponse

// Specify case and delimiter
strcase.ToCase("HelloWorld", strcase.UpperCase, '.') // HELLO.WORLD
Expand Down Expand Up @@ -76,7 +77,7 @@ the initialisms if you wish to add additional ones, such as "SSL" or "CMS" or
domain specific ones to your industry.


ToGoCamel("http_response") // HTTPResponse
ToGoPascal("http_response") // HTTPResponse
ToGoSnake("http_response") // HTTP_response

### Test coverage
Expand All @@ -96,35 +97,35 @@ Hopefully I was fair to each library and happy to rerun benchmarks differently
or reword my commentary based on suggestions or updates.


// This package
// Go intialisms and custom casers are slower
BenchmarkToTitle-4 992491 1559 ns/op 32 B/op 1 allocs/op
BenchmarkToSnake-4 1000000 1475 ns/op 32 B/op 1 allocs/op
BenchmarkToSNAKE-4 1000000 1609 ns/op 32 B/op 1 allocs/op
BenchmarkToGoSnake-4 275010 3697 ns/op 44 B/op 4 allocs/op
BenchmarkToCustomCaser-4 342704 4191 ns/op 56 B/op 4 allocs/op
// This package - faster then almost all libraries
// Initialisms are more complicated and slightly slower, but still faster then other libraries that do less
BenchmarkToTitle-4 7821166 221 ns/op 32 B/op 1 allocs/op
BenchmarkToSnake-4 9378589 202 ns/op 32 B/op 1 allocs/op
BenchmarkToSNAKE-4 6174453 223 ns/op 32 B/op 1 allocs/op
BenchmarkToGoSnake-4 3114266 434 ns/op 44 B/op 4 allocs/op
BenchmarkToCustomCaser-4 2973855 448 ns/op 56 B/op 4 allocs/op

// Segment has very fast snake case and camel case libraries
// No features or customization, but very very fast
BenchmarkSegment-4 1303809 938 ns/op 16 B/op 1 allocs/op
BenchmarkSegment-4 24003495 64.9 ns/op 16 B/op 1 allocs/op

// Stdlib strings.Title for comparison, even though it only splits on spaces
BenchmarkToTitleStrings-4 1213467 1164 ns/op 16 B/op 1 allocs/op
BenchmarkToTitleStrings-4 11259376 161 ns/op 16 B/op 1 allocs/op

// Other libraries or code snippets
// - Most are slower, by up to an order of magnitude
// - None support initialisms or customization
// - Some generate only camelCase or snake_case
// - Many lack unicode support
BenchmarkToSnakeStoewer-4 973200 2075 ns/op 64 B/op 2 allocs/op
BenchmarkToSnakeStoewer-4 7103268 297 ns/op 64 B/op 2 allocs/op
// Copying small rune arrays is slow
BenchmarkToSnakeSiongui-4 264315 4229 ns/op 48 B/op 10 allocs/op
BenchmarkGoValidator-4 206811 5152 ns/op 184 B/op 9 allocs/op
BenchmarkToSnakeSiongui-4 3710768 413 ns/op 48 B/op 10 allocs/op
BenchmarkGoValidator-4 2416479 1049 ns/op 184 B/op 9 allocs/op
// String alloction is slow
BenchmarkToSnakeFatih-4 82675 12280 ns/op 392 B/op 26 allocs/op
BenchmarkToSnakeIanColeman-4 83276 13903 ns/op 145 B/op 13 allocs/op
BenchmarkToSnakeFatih-4 1000000 2407 ns/op 624 B/op 26 allocs/op
BenchmarkToSnakeIanColeman-4 1005766 1426 ns/op 160 B/op 13 allocs/op
// Regexp is slow
BenchmarkToSnakeGolangPrograms-4 74448 18586 ns/op 176 B/op 11 allocs/op
BenchmarkToSnakeGolangPrograms-4 614689 2237 ns/op 225 B/op 11 allocs/op

// These results aren't a surprise - my initial version of this library was
// painfully slow. I think most of us, without spending some time with
Expand Down Expand Up @@ -168,6 +169,7 @@ custom casers to mimic the behavior of the other package.
* [func ToGoKebab(s string) string](#ToGoKebab)
* [func ToGoPascal(s string) string](#ToGoPascal)
* [func ToGoSnake(s string) string](#ToGoSnake)
* [func ToHeader(s string) string](#ToHeader)
* [func ToKEBAB(s string) string](#ToKEBAB)
* [func ToKebab(s string) string](#ToKebab)
* [func ToPascal(s string) string](#ToPascal)
Expand All @@ -177,6 +179,7 @@ custom casers to mimic the behavior of the other package.
* [func NewCaser(goInitialisms bool, initialismOverrides map[string]bool, splitFn SplitFn) *Caser](#NewCaser)
* [func (c *Caser) ToCamel(s string) string](#Caser.ToCamel)
* [func (c *Caser) ToCase(s string, wordCase WordCase, delimiter rune) string](#Caser.ToCase)
* [func (c *Caser) ToHeader(s string) string](#Caser.ToHeader)
* [func (c *Caser) ToKEBAB(s string) string](#Caser.ToKEBAB)
* [func (c *Caser) ToKebab(s string) string](#Caser.ToKebab)
* [func (c *Caser) ToPascal(s string) string](#Caser.ToPascal)
Expand All @@ -201,26 +204,28 @@ Also known as lowerCamelCase or mixedCase.



## <a name="ToCase">func</a> [ToCase](./strcase.go#L70)
## <a name="ToCase">func</a> [ToCase](./strcase.go#L77)
``` go
func ToCase(s string, wordCase WordCase, delimiter rune) string
```
ToCase returns words in given case and delimiter.



## <a name="ToGoCamel">func</a> [ToGoCamel](./strcase.go#L65)
## <a name="ToGoCamel">func</a> [ToGoCamel](./strcase.go#L67)
``` go
func ToGoCamel(s string) string
```
ToGoCamel returns words in camelCase (capitalized words concatenated together, with first word lower case).
Also known as lowerCamelCase or mixedCase.

Respects Go's common initialisms (e.g. httpResponse -> HTTPResponse).
Respects Go's common initialisms, but first word remains lowercased which is
important for code generator use cases (e.g. toJson -> toJSON, httpResponse
-> httpResponse).



## <a name="ToGoCase">func</a> [ToGoCase](./strcase.go#L77)
## <a name="ToGoCase">func</a> [ToGoCase](./strcase.go#L84)
``` go
func ToGoCase(s string, wordCase WordCase, delimiter rune) string
```
Expand Down Expand Up @@ -262,6 +267,14 @@ Respects Go's common initialisms (e.g. http_response -> HTTP_response).



## <a name="ToHeader">func</a> [ToHeader](./strcase.go#L72)
``` go
func ToHeader(s string) string
```
ToHeader returns words in Header-Case (capitalized words with dashes).



## <a name="ToKEBAB">func</a> [ToKEBAB](./strcase.go#L37)
``` go
func ToKEBAB(s string) string
Expand Down Expand Up @@ -357,7 +370,7 @@ Also known as lowerCamelCase or mixedCase.



### <a name="Caser.ToCase">func</a> (\*Caser) [ToCase](./caser.go#L85)
### <a name="Caser.ToCase">func</a> (\*Caser) [ToCase](./caser.go#L90)
``` go
func (c *Caser) ToCase(s string, wordCase WordCase, delimiter rune) string
```
Expand All @@ -366,6 +379,15 @@ ToCase returns words with a given case and delimiter.



### <a name="Caser.ToHeader">func</a> (\*Caser) [ToHeader](./caser.go#L85)
``` go
func (c *Caser) ToHeader(s string) string
```
ToHeader returns words in Header-Case (capitalized words with dashes).




### <a name="Caser.ToKEBAB">func</a> (\*Caser) [ToKEBAB](./caser.go#L68)
``` go
func (c *Caser) ToKEBAB(s string) string
Expand Down Expand Up @@ -469,7 +491,6 @@ NewSplitFn returns a SplitFn based on the options provided.
NewSplitFn covers the majority of common options that other strcase
libraries provide and should allow you to simply create a custom caser.
For more complicated use cases, feel free to write your own SplitFn
nolint:gocyclo



Expand Down Expand Up @@ -524,6 +545,9 @@ const (
// TitleCase - Only first letter upper cased (Example)
TitleCase
// CamelCase - TitleCase except lower case first word (exampleText)
// Notably, even if the first word is an initialism, it will be lower
// cased. This is important for code generators where capital letters
// mean exported functions. i.e. jsonString(), not JSONString()
CamelCase
)
```
Expand Down
10 changes: 10 additions & 0 deletions benchmark/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ func BenchmarkToSNAKE(b *testing.B) {
b.Fatalf("Expected %s, got %s", expected, s)
}
}
func BenchmarkToHeader(b *testing.B) {
var s string
for n := 0; n < b.N; n++ {
s = strcase.ToHeader(testCamel)
}
expected := testHeader
if expected != s {
b.Fatalf("Expected %s, got %s", expected, s)
}
}
func BenchmarkToGoSnake(b *testing.B) {
var s string
for n := 0; n < b.N; n++ {
Expand Down
5 changes: 5 additions & 0 deletions caser.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ func (c *Caser) ToCamel(s string) string {
return convert(s, c.splitFn, '\x00', CamelCase, c.initialisms)
}

// ToHeader returns words in Header-Case (capitalized words with dashes).
func (c *Caser) ToHeader(s string) string {
return convert(s, c.splitFn, '-', TitleCase, c.initialisms)
}

// ToCase returns words with a given case and delimiter.
func (c *Caser) ToCase(s string, wordCase WordCase, delimiter rune) string {
return convert(s, c.splitFn, delimiter, wordCase, c.initialisms)
Expand Down
3 changes: 3 additions & 0 deletions caser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func TestCaserAll(t *testing.T) {
KEBAB string
pascal string
camel string
header string
title string
}
for _, test := range []data{
Expand All @@ -29,6 +30,7 @@ func TestCaserAll(t *testing.T) {
KEBAB: "HELLO-WORLD!",
pascal: "HelloWorld!",
camel: "helloWorld!",
header: "Hello-World!",
title: "Hello World!",
},
} {
Expand All @@ -41,6 +43,7 @@ func TestCaserAll(t *testing.T) {
KEBAB: c.ToKEBAB(test.input),
pascal: c.ToPascal(test.input),
camel: c.ToCamel(test.input),
header: c.ToHeader(test.input),
title: c.ToCase(test.input, TitleCase, ' '),
}
assert.Equal(t, test, output)
Expand Down
1 change: 1 addition & 0 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Example usage

strcase.ToKebab("helloWorld") // hello-world
strcase.ToKEBAB("helloWorld") // HELLO-WORLD
strcase.ToHeader("helloWorld") // Hello-World

strcase.ToPascal("hello-world") // HelloWorld
strcase.ToCamel("hello-world") // helloWorld
Expand Down
5 changes: 5 additions & 0 deletions strcase.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ func ToGoCamel(s string) string {
return convertWithGoInitialisms(s, 0, CamelCase)
}

// ToHeader returns words in Header-Case (capitalized words with dashes).
func ToHeader(s string) string {
return convertWithoutInitialisms(s, '-', TitleCase)
}

// ToCase returns words in given case and delimiter.
func ToCase(s string, wordCase WordCase, delimiter rune) string {
return convertWithoutInitialisms(s, delimiter, wordCase)
Expand Down
Loading