mirror of https://github.com/dmarkham/enumer.git
Merge pull request #19 from pascaldekloe/master
Replace naming convention library. Eliminates transformer code.
This commit is contained in:
commit
c4e9df231f
|
@ -33,7 +33,7 @@ func TestEndToEnd(t *testing.T) {
|
|||
defer os.RemoveAll(dir)
|
||||
// Create stringer in temporary directory.
|
||||
stringer := filepath.Join(dir, "stringer.exe")
|
||||
err = run("go", "build", "-o", stringer, "enumer.go", "sql.go", "stringer.go", "transformer.go")
|
||||
err = run("go", "build", "-o", stringer, "enumer.go", "sql.go", "stringer.go")
|
||||
if err != nil {
|
||||
t.Fatalf("building stringer: %s", err)
|
||||
}
|
||||
|
|
10
stringer.go
10
stringer.go
|
@ -78,6 +78,8 @@ import (
|
|||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/pascaldekloe/name"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -285,18 +287,18 @@ func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) {
|
|||
}
|
||||
|
||||
func (g *Generator) transformValueNames(values []Value, transformMethod string) {
|
||||
var transform func(string) string
|
||||
var sep rune
|
||||
switch transformMethod {
|
||||
case "snake":
|
||||
transform = toSnakeCase
|
||||
sep = '_'
|
||||
case "kebab":
|
||||
transform = toKebabCase
|
||||
sep = '-'
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
for i := range values {
|
||||
values[i].name = transform(values[i].name)
|
||||
values[i].name = strings.ToLower(name.Delimit(values[i].name, sep))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/camelcase"
|
||||
)
|
||||
|
||||
func transform(src, delim string) string {
|
||||
entries := camelcase.Split(src)
|
||||
if len(entries) <= 1 {
|
||||
return strings.ToLower(src)
|
||||
}
|
||||
|
||||
result := strings.ToLower(entries[0])
|
||||
for i := 1; i < len(entries); i++ {
|
||||
result += delim + strings.ToLower(entries[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func toSnakeCase(src string) string {
|
||||
return transform(src, "_")
|
||||
}
|
||||
|
||||
func toKebabCase(src string) string {
|
||||
return transform(src, "-")
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTransform(t *testing.T) {
|
||||
result := transform("CamelCaseStringValue", ".")
|
||||
|
||||
const expected = "camel.case.string.value"
|
||||
if result != expected {
|
||||
t.Errorf("\ngot: %s\n====\nexpected: %s", result, expected)
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
language: go
|
||||
go: 1.4
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Fatih Arslan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,58 +0,0 @@
|
|||
# CamelCase [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/camelcase) [![Build Status](http://img.shields.io/travis/fatih/camelcase.svg?style=flat-square)](https://travis-ci.org/fatih/camelcase)
|
||||
|
||||
CamelCase is a Golang (Go) package to split the words of a camelcase type
|
||||
string into a slice of words. It can be used to convert a camelcase word (lower
|
||||
or upper case) into any type of word.
|
||||
|
||||
## Splitting rules:
|
||||
|
||||
1. If string is not valid UTF-8, return it without splitting as
|
||||
single item array.
|
||||
2. Assign all unicode characters into one of 4 sets: lower case
|
||||
letters, upper case letters, numbers, and all other characters.
|
||||
3. Iterate through characters of string, introducing splits
|
||||
between adjacent characters that belong to different sets.
|
||||
4. Iterate through array of split strings, and if a given string
|
||||
is upper case:
|
||||
* if subsequent string is lower case:
|
||||
* move last character of upper case string to beginning of
|
||||
lower case string
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/fatih/camelcase
|
||||
```
|
||||
|
||||
## Usage and examples
|
||||
|
||||
```go
|
||||
splitted := camelcase.Split("GolangPackage")
|
||||
|
||||
fmt.Println(splitted[0], splitted[1]) // prints: "Golang", "Package"
|
||||
```
|
||||
|
||||
Both lower camel case and upper camel case are supported. For more info please
|
||||
check: [http://en.wikipedia.org/wiki/CamelCase](http://en.wikipedia.org/wiki/CamelCase)
|
||||
|
||||
Below are some example cases:
|
||||
|
||||
```
|
||||
"" => []
|
||||
"lowercase" => ["lowercase"]
|
||||
"Class" => ["Class"]
|
||||
"MyClass" => ["My", "Class"]
|
||||
"MyC" => ["My", "C"]
|
||||
"HTML" => ["HTML"]
|
||||
"PDFLoader" => ["PDF", "Loader"]
|
||||
"AString" => ["A", "String"]
|
||||
"SimpleXMLParser" => ["Simple", "XML", "Parser"]
|
||||
"vimRPCPlugin" => ["vim", "RPC", "Plugin"]
|
||||
"GL11Version" => ["GL", "11", "Version"]
|
||||
"99Bottles" => ["99", "Bottles"]
|
||||
"May5" => ["May", "5"]
|
||||
"BFG9000" => ["BFG", "9000"]
|
||||
"BöseÜberraschung" => ["Böse", "Überraschung"]
|
||||
"Two spaces" => ["Two", " ", "spaces"]
|
||||
"BadUTF8\xe2\xe2\xa1" => ["BadUTF8\xe2\xe2\xa1"]
|
||||
```
|
|
@ -1,90 +0,0 @@
|
|||
// Package camelcase is a micro package to split the words of a camelcase type
|
||||
// string into a slice of words.
|
||||
package camelcase
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Split splits the camelcase word and returns a list of words. It also
|
||||
// supports digits. Both lower camel case and upper camel case are supported.
|
||||
// For more info please check: http://en.wikipedia.org/wiki/CamelCase
|
||||
//
|
||||
// Examples
|
||||
//
|
||||
// "" => [""]
|
||||
// "lowercase" => ["lowercase"]
|
||||
// "Class" => ["Class"]
|
||||
// "MyClass" => ["My", "Class"]
|
||||
// "MyC" => ["My", "C"]
|
||||
// "HTML" => ["HTML"]
|
||||
// "PDFLoader" => ["PDF", "Loader"]
|
||||
// "AString" => ["A", "String"]
|
||||
// "SimpleXMLParser" => ["Simple", "XML", "Parser"]
|
||||
// "vimRPCPlugin" => ["vim", "RPC", "Plugin"]
|
||||
// "GL11Version" => ["GL", "11", "Version"]
|
||||
// "99Bottles" => ["99", "Bottles"]
|
||||
// "May5" => ["May", "5"]
|
||||
// "BFG9000" => ["BFG", "9000"]
|
||||
// "BöseÜberraschung" => ["Böse", "Überraschung"]
|
||||
// "Two spaces" => ["Two", " ", "spaces"]
|
||||
// "BadUTF8\xe2\xe2\xa1" => ["BadUTF8\xe2\xe2\xa1"]
|
||||
//
|
||||
// Splitting rules
|
||||
//
|
||||
// 1) If string is not valid UTF-8, return it without splitting as
|
||||
// single item array.
|
||||
// 2) Assign all unicode characters into one of 4 sets: lower case
|
||||
// letters, upper case letters, numbers, and all other characters.
|
||||
// 3) Iterate through characters of string, introducing splits
|
||||
// between adjacent characters that belong to different sets.
|
||||
// 4) Iterate through array of split strings, and if a given string
|
||||
// is upper case:
|
||||
// if subsequent string is lower case:
|
||||
// move last character of upper case string to beginning of
|
||||
// lower case string
|
||||
func Split(src string) (entries []string) {
|
||||
// don't split invalid utf8
|
||||
if !utf8.ValidString(src) {
|
||||
return []string{src}
|
||||
}
|
||||
entries = []string{}
|
||||
var runes [][]rune
|
||||
lastClass := 0
|
||||
class := 0
|
||||
// split into fields based on class of unicode character
|
||||
for _, r := range src {
|
||||
switch true {
|
||||
case unicode.IsLower(r):
|
||||
class = 1
|
||||
case unicode.IsUpper(r):
|
||||
class = 2
|
||||
case unicode.IsDigit(r):
|
||||
class = 3
|
||||
default:
|
||||
class = 4
|
||||
}
|
||||
if class == lastClass {
|
||||
runes[len(runes)-1] = append(runes[len(runes)-1], r)
|
||||
} else {
|
||||
runes = append(runes, []rune{r})
|
||||
}
|
||||
lastClass = class
|
||||
}
|
||||
// handle upper case -> lower case sequences, e.g.
|
||||
// "PDFL", "oader" -> "PDF", "Loader"
|
||||
for i := 0; i < len(runes)-1; i++ {
|
||||
if unicode.IsUpper(runes[i][0]) && unicode.IsLower(runes[i+1][0]) {
|
||||
runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...)
|
||||
runes[i] = runes[i][:len(runes[i])-1]
|
||||
}
|
||||
}
|
||||
// construct []string from results
|
||||
for _, s := range runes {
|
||||
if len(s) > 0 {
|
||||
entries = append(entries, string(s))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package camelcase
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleSplit() {
|
||||
|
||||
for _, c := range []string{
|
||||
"",
|
||||
"lowercase",
|
||||
"Class",
|
||||
"MyClass",
|
||||
"MyC",
|
||||
"HTML",
|
||||
"PDFLoader",
|
||||
"AString",
|
||||
"SimpleXMLParser",
|
||||
"vimRPCPlugin",
|
||||
"GL11Version",
|
||||
"99Bottles",
|
||||
"May5",
|
||||
"BFG9000",
|
||||
"BöseÜberraschung",
|
||||
"Two spaces",
|
||||
"BadUTF8\xe2\xe2\xa1",
|
||||
} {
|
||||
fmt.Printf("%#v => %#v\n", c, Split(c))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// "" => []string{}
|
||||
// "lowercase" => []string{"lowercase"}
|
||||
// "Class" => []string{"Class"}
|
||||
// "MyClass" => []string{"My", "Class"}
|
||||
// "MyC" => []string{"My", "C"}
|
||||
// "HTML" => []string{"HTML"}
|
||||
// "PDFLoader" => []string{"PDF", "Loader"}
|
||||
// "AString" => []string{"A", "String"}
|
||||
// "SimpleXMLParser" => []string{"Simple", "XML", "Parser"}
|
||||
// "vimRPCPlugin" => []string{"vim", "RPC", "Plugin"}
|
||||
// "GL11Version" => []string{"GL", "11", "Version"}
|
||||
// "99Bottles" => []string{"99", "Bottles"}
|
||||
// "May5" => []string{"May", "5"}
|
||||
// "BFG9000" => []string{"BFG", "9000"}
|
||||
// "BöseÜberraschung" => []string{"Böse", "Überraschung"}
|
||||
// "Two spaces" => []string{"Two", " ", "spaces"}
|
||||
// "BadUTF8\xe2\xe2\xa1" => []string{"BadUTF8\xe2\xe2\xa1"}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
To the extent possible under law, Pascal S. de Kloe has waived all
|
||||
copyright and related or neighboring rights to Colfer. This work is
|
||||
published from The Netherlands.
|
|
@ -0,0 +1,6 @@
|
|||
[![GoDoc](https://godoc.org/github.com/pascaldekloe/name?status.svg)](https://godoc.org/github.com/pascaldekloe/name)
|
||||
|
||||
Naming convention library for the Go programming language (golang).
|
||||
|
||||
This is free and unencumbered software released into the
|
||||
[public domain](http://creativecommons.org/publicdomain/zero/1.0).
|
|
@ -0,0 +1,112 @@
|
|||
// Package name implements naming conventions.
|
||||
package name
|
||||
|
||||
import "unicode"
|
||||
|
||||
// CamelCase returns the medial capitals form of word sequence s.
|
||||
// The input can be any case or even just a bunch of words.
|
||||
// Upper case abbreviations are preserved.
|
||||
// Argument upper sets the casing for the first rune.
|
||||
func CamelCase(s string, upper bool) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
out := make([]rune, 1, len(s)+5)
|
||||
for i, r := range s {
|
||||
if i == 0 {
|
||||
if upper {
|
||||
r = unicode.ToUpper(r)
|
||||
}
|
||||
out[0] = r
|
||||
continue
|
||||
}
|
||||
|
||||
if i == 1 {
|
||||
if !upper && unicode.Is(unicode.Lower, r) {
|
||||
out[0] = unicode.ToLower(out[0])
|
||||
}
|
||||
|
||||
upper = false
|
||||
}
|
||||
|
||||
switch {
|
||||
case unicode.IsLetter(r):
|
||||
if upper {
|
||||
r = unicode.ToUpper(r)
|
||||
}
|
||||
|
||||
fallthrough
|
||||
case unicode.IsNumber(r):
|
||||
upper = false
|
||||
out = append(out, r)
|
||||
|
||||
default:
|
||||
upper = true
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return string(out)
|
||||
}
|
||||
|
||||
// SnakeCase is an alias for Delimit(s, '_').
|
||||
func SnakeCase(s string) string {
|
||||
return Delimit(s, '_')
|
||||
}
|
||||
|
||||
// DotSeparated is an alias for Delimit(s, '.').
|
||||
func DotSeparated(s string) string {
|
||||
return Delimit(s, '.')
|
||||
}
|
||||
|
||||
// Delimit returns word sequence s delimited with sep.
|
||||
// The input can be any case or even just a bunch of words.
|
||||
// Upper case abbreviations are preserved. Use strings.ToLower
|
||||
// and strings.ToUpper to enforce a letter case.
|
||||
func Delimit(s string, sep rune) string {
|
||||
out := make([]rune, 0, len(s)+5)
|
||||
|
||||
for _, r := range s {
|
||||
switch {
|
||||
case unicode.IsUpper(r):
|
||||
if last := len(out) - 1; last >= 0 && unicode.IsLower(out[last]) {
|
||||
out = append(out, sep)
|
||||
}
|
||||
|
||||
case unicode.IsLetter(r):
|
||||
if i := len(out) - 1; i >= 0 {
|
||||
if last := out[i]; unicode.IsUpper(last) {
|
||||
out = out[:i]
|
||||
if i > 0 && out[i-1] != sep {
|
||||
out = append(out, sep)
|
||||
}
|
||||
out = append(out, unicode.ToLower(last))
|
||||
}
|
||||
}
|
||||
|
||||
case !unicode.IsNumber(r):
|
||||
if i := len(out); i != 0 && out[i-1] != sep {
|
||||
out = append(out, sep)
|
||||
}
|
||||
continue
|
||||
|
||||
}
|
||||
out = append(out, r)
|
||||
}
|
||||
|
||||
if len(out) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// trim tailing separator
|
||||
if i := len(out) - 1; out[i] == sep {
|
||||
out = out[:i]
|
||||
}
|
||||
|
||||
if len(out) == 1 {
|
||||
out[0] = unicode.ToLower(out[0])
|
||||
}
|
||||
|
||||
return string(out)
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package name
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
type goldenCase struct {
|
||||
snake, lowerCamel, upperCamel string
|
||||
}
|
||||
|
||||
var goldenCases = []goldenCase{
|
||||
{"", "", ""},
|
||||
{"i", "i", "I"},
|
||||
{"name", "name", "Name"},
|
||||
{"ID", "ID", "ID"},
|
||||
{"wi_fi", "wiFi", "WiFi"},
|
||||
|
||||
// single outer abbreviation
|
||||
{"vitamin_C", "vitaminC", "VitaminC"},
|
||||
{"T_cell", "TCell", "TCell"},
|
||||
|
||||
// double outer abbreviation
|
||||
{"master_DB", "masterDB", "MasterDB"},
|
||||
{"IO_bounds", "IOBounds", "IOBounds"},
|
||||
|
||||
// tripple outer abbreviation
|
||||
{"main_API", "mainAPI", "MainAPI"},
|
||||
{"TCP_conn", "TCPConn", "TCPConn"},
|
||||
|
||||
// inner abbreviation
|
||||
{"raw_URL_query", "rawURLQuery", "RawURLQuery"},
|
||||
|
||||
// numbers
|
||||
{"4x4", "4x4", "4x4"},
|
||||
{"no5", "no5", "No5"},
|
||||
{"DB2", "DB2", "DB2"},
|
||||
{"3M", "3M", "3M"},
|
||||
{"7_up", "7Up", "7Up"},
|
||||
{"20th", "20th", "20th"},
|
||||
}
|
||||
|
||||
func TestSnakeToSnake(t *testing.T) {
|
||||
for _, golden := range goldenCases {
|
||||
s := golden.snake
|
||||
if got := SnakeCase(s); got != s {
|
||||
t.Errorf("%q: got %q", s, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLowerCamelToLowerCamel(t *testing.T) {
|
||||
for _, golden := range goldenCases {
|
||||
s := golden.lowerCamel
|
||||
if got := CamelCase(s, false); got != s {
|
||||
t.Errorf("%q: got %q", s, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpperCamelToUpperCamel(t *testing.T) {
|
||||
for _, golden := range goldenCases {
|
||||
s := golden.upperCamel
|
||||
if got := CamelCase(s, true); got != s {
|
||||
t.Errorf("%q: got %q", s, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnakeToLowerCamel(t *testing.T) {
|
||||
for _, golden := range goldenCases {
|
||||
snake, want := golden.snake, golden.lowerCamel
|
||||
if got := CamelCase(snake, false); got != want {
|
||||
t.Errorf("%q: got %q, want %q", snake, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnakeToUpperCamel(t *testing.T) {
|
||||
for _, golden := range goldenCases {
|
||||
snake, want := golden.snake, golden.upperCamel
|
||||
if got := CamelCase(snake, true); got != want {
|
||||
t.Errorf("%q: got %q, want %q", snake, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLowerCamelToSnake(t *testing.T) {
|
||||
for _, golden := range goldenCases {
|
||||
camel, want := golden.lowerCamel, golden.snake
|
||||
if got := SnakeCase(camel); got != want {
|
||||
t.Errorf("%q: got %q, want %q", camel, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpperCamelToSnake(t *testing.T) {
|
||||
for _, golden := range goldenCases {
|
||||
camel, want := golden.upperCamel, golden.snake
|
||||
if got := SnakeCase(camel); got != want {
|
||||
t.Errorf("%q: got %q, want %q", camel, got, want)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package name_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pascaldekloe/name"
|
||||
)
|
||||
|
||||
func ExampleCamelCase() {
|
||||
fmt.Println(name.CamelCase("pascal case", true))
|
||||
fmt.Println(name.CamelCase("snake_to_camel AND CamelToCamel?", false))
|
||||
|
||||
// Output:
|
||||
// PascalCase
|
||||
// snakeToCamelANDCamelToCamel
|
||||
}
|
||||
|
||||
func ExampleDelimit() {
|
||||
// Garbage to Lisp-case:
|
||||
fmt.Println(name.Delimit("* All Hype is aGoodThing (TM)", '-'))
|
||||
|
||||
// Builds a Java property key:
|
||||
fmt.Println(name.DotSeparated("WebCrawler#socketTimeout"))
|
||||
|
||||
// Output:
|
||||
// all-hype-is-a-good-thing-TM
|
||||
// web.crawler.socket.timeout
|
||||
}
|
Loading…
Reference in New Issue