├── .gitignore ├── .goreleaser.yml ├── .travis.yml ├── LICENSE ├── README.md ├── case.go ├── case_test.go ├── cmd └── casec │ ├── convert.go │ ├── convert_test.go │ ├── main.go │ ├── parse.go │ └── parse_test.go ├── convert.go ├── convert_test.go ├── go.mod ├── go.sum └── testdata ├── pascal2snake.py.in ├── pascal2snake.py.out ├── pascal2snake_ignore.py.in ├── pascal2snake_ignore.py.out ├── snake2camel.go.in ├── snake2camel.go.out ├── snake2camel_ignore.go.in ├── snake2camel_ignore.go.out ├── snake2pascal_lines_ignore.go.in └── snake2pascal_lines_ignore.go.out /.gitignore: -------------------------------------------------------------------------------- 1 | # Vendor 2 | vendor/ 3 | 4 | # Build & binary 5 | dist/ 6 | flog 7 | 8 | # Editors 9 | .vscode/ 10 | 11 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | project_name: casec 2 | 3 | before: 4 | hooks: 5 | - go mod download 6 | 7 | builds: 8 | - main: ./cmd/casec 9 | binary: casec 10 | goos: 11 | - windows 12 | - darwin 13 | - linux 14 | goarch: 15 | - amd64 16 | 17 | changelog: 18 | sort: asc 19 | filters: 20 | exclude: 21 | - '^docs:' 22 | - Update README.md 23 | - Merge pull request 24 | - Merge branch 25 | 26 | archive: 27 | format: tar.gz 28 | name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" 29 | files: 30 | - LICENSE 31 | - README.md 32 | 33 | release: 34 | github: 35 | owner: mingrammer 36 | name: casec 37 | name_template: '{{.Tag}}' 38 | 39 | brew: 40 | name: casec 41 | github: 42 | owner: mingrammer 43 | name: homebrew-casec 44 | commit_author: 45 | name: mingrammer 46 | email: mingrammer@gmail.com 47 | homepage: https://github.com/mingrammer/casec 48 | description: "A text case converter" 49 | install: bin.install "casec" 50 | test: | 51 | system "#{bin}/casec -v" 52 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - "1.13.x" 5 | - "master" 6 | 7 | os: 8 | - linux 9 | - osx 10 | 11 | env: 12 | - GO111MODULE=on 13 | 14 | script: 15 | - go build ./cmd/casec 16 | - go test -v . 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 mingrammer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

Casec

4 | 5 |

6 | 7 | 8 | 9 | 10 |

11 | 12 | 13 |

14 | A text case converter 15 |

16 |


17 | 18 | casec is a text case converter for programmers. casec now supports `upper`, `lower`, `title`, `camel`, `pascal`, `snake`, `kebab` (or `lisp`) cases. 19 | 20 | It also provides case conversion library not only command line tool. 21 | 22 | ## Installation 23 | 24 | ### Using go get 25 | 26 | > Go version 1.10 or higher is required. 27 | 28 | ``` 29 | go get github.com/mingrammer/casec/... 30 | ``` 31 | 32 | If you want to only download the `casec` library 33 | 34 | ``` 35 | go get github.com/mingrammer/casec 36 | ``` 37 | 38 | ### Using [homebrew](https://brew.sh) 39 | 40 | ``` 41 | brew tap mingrammer/casec 42 | brew install casec 43 | ``` 44 | 45 | ### Using .tar.gz archive 46 | 47 | Download gzip file from [Github Releases](https://github.com/mingrammer/casec/releases/latest) according to your OS. Then, copy the unzipped executable to under system path. 48 | 49 | ## Usage 50 | 51 | ### CLI 52 | 53 | Convert all words to snake case. 54 | 55 | ```bash 56 | $ casec -t snake main.py 57 | ``` 58 | 59 | Convert all snake case to camel case. 60 | 61 | ```bash 62 | $ casec -f snake -t camel internal.go 63 | ``` 64 | 65 | Convert only 20~50 lines from snake case to camel case. 66 | 67 | ```bash 68 | $ casec -f snake -t camel -l 20:50 internal.go 69 | ``` 70 | 71 | Show how would have been converted. (dry-run) 72 | 73 | ```bash 74 | $ casec -f snake -t kebab -n match.lisp 75 | ``` 76 | 77 | Convert all camel case to snake case except for words you don't want to convert. It is useful for preventing the keywords (reserved words) or conventions from converting. 78 | 79 | ```bash 80 | $ casec -f snake -t pascal -i '^package|var|const|if|for|range|return|func|go$' redis.go 81 | ``` 82 | 83 | You can pass multiple ignore expressions. 84 | 85 | ```bash 86 | $ casec -f snake -t pascal -i '^package|var|const|if|for|range|return|func|go$' -i '^github|com$' redis.go 87 | ``` 88 | 89 | ### Library 90 | 91 | > See details in [GoDoc](https://godoc.org/github.com/mingrammer/casec) 92 | 93 | ```go 94 | package main 95 | 96 | import ( 97 | "fmt" 98 | 99 | "github.com/mingrammer/casec" 100 | ) 101 | 102 | func main() { 103 | fmt.Println(casec.IsSnake("this_is_snake")) 104 | // Output: true 105 | fmt.Println(casec.IsCamel("thisIsNot_camelCase")) 106 | // Output: false 107 | fmt.Println(casec.Invert("Invert Me")) 108 | // Output: iNVERT mE 109 | fmt.Println(casec.ToCamel("write_rune")) 110 | // Output: writeRune 111 | fmt.Println(casec.ToSnake("IPAddress")) 112 | // Output: ip_address 113 | fmt.Println(casec.ToKebab("simpleJSONParser")) 114 | // Output: simple-json-parser 115 | } 116 | ``` 117 | 118 | ## Known issues 119 | 120 | casec separates the words with non-letters (except `-` and `_`) including `.` and `/` letters. So, the `ignore` option of casec can not recognize the dot-or-slash separated word (ex. `"github.com/mingrammer/cfmt"`) as a single chunk. So if you want to prevent the import path of Go source code, for example, `import "github.com/mingrammer/cfmt"` from converting, you should pass the ignore expression as `-i "^(github|com|mingrammer|cfmt)$"`. 121 | 122 | Here is a (maybe) solution for solving this issue. 123 | 124 | 1. Treat the string surrounded with quotes ("" or '') as a single word optionally. 125 | 126 | ## License 127 | 128 | MIT 129 | -------------------------------------------------------------------------------- /case.go: -------------------------------------------------------------------------------- 1 | package casec 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | 7 | "github.com/mingrammer/cfmt" 8 | ) 9 | 10 | // Case-specific delimiter 11 | const ( 12 | SnakeDelimiter = '_' 13 | KebabDelimiter = '-' 14 | ) 15 | 16 | // IsUpperCase checks the string is uppercase 17 | func IsUpper(s string) bool { 18 | return s == strings.ToUpper(s) 19 | } 20 | 21 | // IsLowerCase checks the string is lowercase 22 | func IsLower(s string) bool { 23 | return s == strings.ToLower(s) 24 | } 25 | 26 | // IsTitleCase checks the string is titlecase 27 | func IsTitle(s string) bool { 28 | return s == ToTitle(s) 29 | } 30 | 31 | // IsCamelCase checks the string is camelcase 32 | func IsCamel(s string) bool { 33 | return s == ToCamel(s) 34 | } 35 | 36 | // IsPascalCase checks the string is pascalcase 37 | func IsPascal(s string) bool { 38 | return s == ToPascal(s) 39 | } 40 | 41 | // IsSnakeCase checks the string is snakecase 42 | func IsSnake(s string) bool { 43 | return s == ToSnake(s) 44 | } 45 | 46 | // IsKebabCase checks the string is kebabcase 47 | func IsKebab(s string) bool { 48 | return s == ToKebab(s) 49 | } 50 | 51 | // IsCaseOf checks whether the string is a specific case 52 | func IsCaseOf(c, s string) (bool, error) { 53 | switch c { 54 | case "upper": 55 | return IsUpper(s), nil 56 | case "lower": 57 | return IsLower(s), nil 58 | case "title": 59 | return IsTitle(s), nil 60 | case "camel": 61 | return IsCamel(s), nil 62 | case "pascal": 63 | return IsPascal(s), nil 64 | case "snake": 65 | return IsSnake(s), nil 66 | case "kebab", "lisp": 67 | return IsKebab(s), nil 68 | } 69 | return false, errors.New(cfmt.Serrorf("%s is not valid case", c)) 70 | } 71 | -------------------------------------------------------------------------------- /case_test.go: -------------------------------------------------------------------------------- 1 | package casec 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestIsUpper(t *testing.T) { 8 | testCases := []struct { 9 | text string 10 | expected bool 11 | }{ 12 | {text: "CASE", expected: true}, 13 | {text: "UPPER_CASE", expected: true}, 14 | {text: "Case", expected: false}, 15 | {text: "cASE", expected: false}, 16 | } 17 | 18 | for i, tc := range testCases { 19 | if is := IsUpper(tc.text); is != tc.expected { 20 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, is) 21 | } 22 | } 23 | } 24 | 25 | func TestIsLower(t *testing.T) { 26 | testCases := []struct { 27 | text string 28 | expected bool 29 | }{ 30 | {text: "case", expected: true}, 31 | {text: "lower_case", expected: true}, 32 | {text: "Case", expected: false}, 33 | {text: "casE", expected: false}, 34 | } 35 | 36 | for i, tc := range testCases { 37 | if is := IsLower(tc.text); is != tc.expected { 38 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, is) 39 | } 40 | } 41 | } 42 | 43 | func TestIsTitle(t *testing.T) { 44 | testCases := []struct { 45 | text string 46 | expected bool 47 | }{ 48 | {text: "Case", expected: true}, 49 | {text: "Title Case", expected: true}, 50 | {text: "case", expected: false}, 51 | {text: "casE", expected: false}, 52 | } 53 | 54 | for i, tc := range testCases { 55 | if is := IsTitle(tc.text); is != tc.expected { 56 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, is) 57 | } 58 | } 59 | } 60 | 61 | func TestIsCamel(t *testing.T) { 62 | testCases := []struct { 63 | text string 64 | expected bool 65 | }{ 66 | {text: "case", expected: true}, 67 | {text: "camelCase", expected: true}, 68 | {text: "PascalCase", expected: false}, 69 | {text: "snake_case", expected: false}, 70 | } 71 | 72 | for i, tc := range testCases { 73 | if is := IsCamel(tc.text); is != tc.expected { 74 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, is) 75 | } 76 | } 77 | } 78 | 79 | func TestIsPascal(t *testing.T) { 80 | testCases := []struct { 81 | text string 82 | expected bool 83 | }{ 84 | {text: "Case", expected: true}, 85 | {text: "PascalCase", expected: true}, 86 | {text: "camelCase", expected: false}, 87 | {text: "snake_case", expected: false}, 88 | } 89 | 90 | for i, tc := range testCases { 91 | if is := IsPascal(tc.text); is != tc.expected { 92 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, is) 93 | } 94 | } 95 | } 96 | 97 | func TestIsSnake(t *testing.T) { 98 | testCases := []struct { 99 | text string 100 | expected bool 101 | }{ 102 | {text: "case", expected: true}, 103 | {text: "snake_case", expected: true}, 104 | {text: "camelCase", expected: false}, 105 | {text: "kebab-case", expected: false}, 106 | } 107 | 108 | for i, tc := range testCases { 109 | if is := IsSnake(tc.text); is != tc.expected { 110 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, is) 111 | } 112 | } 113 | } 114 | 115 | func TestIsKebab(t *testing.T) { 116 | testCases := []struct { 117 | text string 118 | expected bool 119 | }{ 120 | {text: "case", expected: true}, 121 | {text: "kebab-ase", expected: true}, 122 | {text: "camelCase", expected: false}, 123 | {text: "snake_case", expected: false}, 124 | } 125 | 126 | for i, tc := range testCases { 127 | if is := IsKebab(tc.text); is != tc.expected { 128 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, is) 129 | } 130 | } 131 | } 132 | 133 | func TestIsCaseOf(t *testing.T) { 134 | testCases := []struct { 135 | kind string 136 | text string 137 | expected bool 138 | }{ 139 | {kind: "upper", text: "UPPERCASE", expected: true}, 140 | {kind: "upper", text: "lowerase", expected: false}, 141 | {kind: "lower", text: "lowercase", expected: true}, 142 | {kind: "lower", text: "UPPERCASE", expected: false}, 143 | {kind: "title", text: "Titlecase", expected: true}, 144 | {kind: "title", text: "lowercase", expected: false}, 145 | {kind: "camel", text: "camelCase", expected: true}, 146 | {kind: "camel", text: "snake_case", expected: false}, 147 | {kind: "pascal", text: "PascalCase", expected: true}, 148 | {kind: "pascal", text: "camelCase", expected: false}, 149 | {kind: "snake", text: "snake_case", expected: true}, 150 | {kind: "snake", text: "camelCase", expected: false}, 151 | {kind: "kebab", text: "kebab-case", expected: true}, 152 | {kind: "kebab", text: "camelCase", expected: false}, 153 | {kind: "unknown", text: "unknown", expected: false}, 154 | } 155 | 156 | for i, tc := range testCases { 157 | if is, _ := IsCaseOf(tc.kind, tc.text); is != tc.expected { 158 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, is) 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /cmd/casec/convert.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | "regexp" 6 | "strings" 7 | "unicode" 8 | 9 | "github.com/mingrammer/casec" 10 | ) 11 | 12 | func isCaseSeparator(r rune) bool { 13 | return r == casec.SnakeDelimiter || r == casec.KebabDelimiter 14 | } 15 | 16 | func convertWord(word, src, tgt string) string { 17 | if src != "" { 18 | if is, _ := casec.IsCaseOf(src, word); is { 19 | word, _ = casec.ToCaseFor(tgt, word) 20 | } 21 | } 22 | return word 23 | } 24 | 25 | func convertText(text, src, tgt string, start, end int, ignoreRe *regexp.Regexp) string { 26 | var convLines []string 27 | lines := strings.Split(text, "\n") 28 | if start <= 0 { 29 | start = 1 30 | } 31 | if end <= 0 { 32 | end = len(lines) 33 | } 34 | for i, line := range lines { 35 | if i >= start-1 && i <= end-1 { 36 | conv := strings.Builder{} 37 | chunk := strings.Builder{} 38 | size := len(line) 39 | lastLetter := false 40 | for j, r := range line { 41 | if unicode.IsLetter(r) || isCaseSeparator(r) { 42 | chunk.WriteRune(r) 43 | if j < size-1 { 44 | continue 45 | } 46 | lastLetter = true 47 | } 48 | if chunk.Len() > 0 { 49 | word := chunk.String() 50 | if !ignoreRe.MatchString(word) { 51 | word = convertWord(word, src, tgt) 52 | } 53 | conv.WriteString(word) 54 | if lastLetter { 55 | break 56 | } 57 | chunk.Reset() 58 | } 59 | conv.WriteRune(r) 60 | } 61 | line = conv.String() 62 | } 63 | convLines = append(convLines, line) 64 | } 65 | out := strings.Join(convLines, "\n") 66 | return out 67 | } 68 | 69 | func convertFromText(text, src, tgt string, start, end int, ignoreRe *regexp.Regexp) (string, string) { 70 | conv := convertText(text, src, tgt, start, end, ignoreRe) 71 | return text, conv 72 | } 73 | 74 | func convertFromFile(fileName, src, tgt string, start, end int, ignoreRe *regexp.Regexp) (string, string, error) { 75 | b, err := ioutil.ReadFile(fileName) 76 | if err != nil { 77 | return "", "", err 78 | } 79 | text, conv := convertFromText(string(b), src, tgt, start, end, ignoreRe) 80 | return text, conv, nil 81 | } 82 | -------------------------------------------------------------------------------- /cmd/casec/convert_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | "regexp" 6 | "testing" 7 | ) 8 | 9 | func TestConvertText_Pascal2Snake(t *testing.T) { 10 | orig, err := ioutil.ReadFile("../../testdata/pascal2snake.py.in") 11 | if err != nil { 12 | t.Error(err.Error()) 13 | } 14 | expected, err := ioutil.ReadFile("../../testdata/pascal2snake.py.out") 15 | if err != nil { 16 | t.Error(err.Error()) 17 | } 18 | re := regexp.MustCompile("^$") 19 | conv := convertText(string(orig), "pascal", "snake", 0, 0, re) 20 | if conv != string(expected) { 21 | t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), conv) 22 | } 23 | } 24 | 25 | func TestConvertText_Pascal2Snake_Ignore(t *testing.T) { 26 | orig, err := ioutil.ReadFile("../../testdata/pascal2snake_ignore.py.in") 27 | if err != nil { 28 | t.Error(err.Error()) 29 | } 30 | expected, err := ioutil.ReadFile("../../testdata/pascal2snake_ignore.py.out") 31 | if err != nil { 32 | t.Error(err.Error()) 33 | } 34 | re := regexp.MustCompile("^(None|CacheStore|InMemoryStore)$") 35 | conv := convertText(string(orig), "pascal", "snake", 0, 0, re) 36 | if conv != string(expected) { 37 | t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), conv) 38 | } 39 | } 40 | 41 | func TestConvertText_Snake2Camel(t *testing.T) { 42 | orig, err := ioutil.ReadFile("../../testdata/snake2camel.go.in") 43 | if err != nil { 44 | t.Error(err.Error()) 45 | } 46 | expected, err := ioutil.ReadFile("../../testdata/snake2camel.go.out") 47 | if err != nil { 48 | t.Error(err.Error()) 49 | } 50 | re := regexp.MustCompile("^$") 51 | conv := convertText(string(orig), "snake", "camel", 0, 0, re) 52 | if conv != string(expected) { 53 | t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), conv) 54 | } 55 | } 56 | 57 | func TestConvertText_Snake2Camel_Ignore(t *testing.T) { 58 | orig, err := ioutil.ReadFile("../../testdata/snake2camel_ignore.go.in") 59 | if err != nil { 60 | t.Error(err.Error()) 61 | } 62 | expected, err := ioutil.ReadFile("../../testdata/snake2camel_ignore.go.out") 63 | if err != nil { 64 | t.Error(err.Error()) 65 | } 66 | re := regexp.MustCompile("^(apache_common$|apache_combined|apache_error)$") 67 | conv := convertText(string(orig), "snake", "camel", 0, 0, re) 68 | if conv != string(expected) { 69 | t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), conv) 70 | } 71 | } 72 | 73 | func TestConvertText_Snake2Pascal_Lines_Ignore(t *testing.T) { 74 | orig, err := ioutil.ReadFile("../../testdata/snake2pascal_lines_ignore.go.in") 75 | if err != nil { 76 | t.Error(err.Error()) 77 | } 78 | expected, err := ioutil.ReadFile("../../testdata/snake2pascal_lines_ignore.go.out") 79 | if err != nil { 80 | t.Error(err.Error()) 81 | } 82 | re := regexp.MustCompile("^(switch|case|default|return|format|delta)$") 83 | conv := convertText(string(orig), "snake", "pascal", 8, 17, re) 84 | if conv != string(expected) { 85 | t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), conv) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /cmd/casec/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | "os" 8 | "regexp" 9 | 10 | "github.com/mingrammer/cfmt" 11 | "github.com/sergi/go-diff/diffmatchpatch" 12 | "github.com/urfave/cli" 13 | ) 14 | 15 | // CLI information 16 | const ( 17 | AppName = "casec" 18 | Author = "mingrammer" 19 | Email = "mingrammer@gmail.com" 20 | Version = "0.1.3" 21 | Usage = "A text case converter" 22 | UsageText = "casec [OPTIONS/FLAGS] [-x ] []" 23 | ) 24 | 25 | // Custom exit codes 26 | const ( 27 | errNoArguments = iota + 10 28 | errInvalidOptions 29 | ) 30 | 31 | func main() { 32 | app := cli.NewApp() 33 | app.Name = AppName 34 | app.Author = Author 35 | app.Email = Email 36 | app.Version = Version 37 | app.Usage = Usage 38 | app.UsageText = UsageText 39 | app.Flags = []cli.Flag{ 40 | cli.StringFlag{ 41 | Name: "from, f", 42 | Usage: "source `CASE` in {upper,lower,title,camel,pascal,snake,kebab,lisp}", 43 | }, 44 | cli.StringFlag{ 45 | Name: "to, t", 46 | Usage: "target `CASE` in {upper,lower,title,camel,pascal,snake,kebab,lisp}", 47 | }, 48 | cli.StringFlag{ 49 | Name: "lines, l", 50 | Usage: "set lines `M:N` to be converted. empty means first or last line", 51 | }, 52 | cli.StringSliceFlag{ 53 | Name: "ignore, i", 54 | Usage: "ignore the text that matches the `PATTERNS`", 55 | }, 56 | cli.BoolFlag{ 57 | Name: "text, x", 58 | Usage: "read the input as raw text, not a file path", 59 | }, 60 | cli.BoolFlag{ 61 | Name: "dry-run, n", 62 | Usage: "show how would have been converted", 63 | }, 64 | } 65 | app.Action = func(ctx *cli.Context) error { 66 | var err error 67 | var orig string 68 | var conv string 69 | var writer io.WriteCloser 70 | 71 | var src string 72 | var tgt string 73 | var start int 74 | var end int 75 | var ignoreRe *regexp.Regexp 76 | if len(ctx.Args()) == 0 { 77 | return errors.New(cfmt.Serror("There are no arguments")) 78 | } 79 | if src, err = parseSource(ctx.String("from")); err != nil { 80 | return err 81 | } 82 | if tgt, err = parseTarget(ctx.String("to")); err != nil { 83 | return err 84 | } 85 | if start, end, err = parseLines(ctx.String("lines")); err != nil { 86 | return err 87 | } 88 | if ignoreRe, err = parseIgnore(ctx.StringSlice("ignore")); err != nil { 89 | return err 90 | } 91 | input := ctx.Args().Get(0) 92 | 93 | if ctx.Bool("text") { 94 | orig, conv = convertFromText(input, src, tgt, start, end, ignoreRe) 95 | writer = os.Stdout 96 | } else { 97 | orig, conv, err = convertFromFile(input, src, tgt, start, end, ignoreRe) 98 | if err != nil { 99 | return err 100 | } 101 | writer, _ = os.OpenFile(input, os.O_RDWR, 0644) 102 | } 103 | 104 | if ctx.Bool("dry-run") { 105 | dmp := diffmatchpatch.New() 106 | diffs := dmp.DiffMain(orig, conv, false) 107 | fmt.Println(dmp.DiffPrettyText(diffs)) 108 | } else { 109 | writer.Write([]byte(conv)) 110 | writer.Close() 111 | } 112 | return nil 113 | } 114 | 115 | err := app.Run(os.Args) 116 | if err != nil { 117 | fmt.Println(err.Error()) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /cmd/casec/parse.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "regexp" 6 | "strconv" 7 | "strings" 8 | 9 | "github.com/mingrammer/cfmt" 10 | ) 11 | 12 | var validCases = [8]string{"upper", "lower", "title", "camel", "pascal", "snake", "kebab", "lisp"} 13 | 14 | func parseNumber(s string) (int, error) { 15 | if s == "" { 16 | return 0, nil 17 | } 18 | i, err := strconv.Atoi(s) 19 | if err != nil { 20 | return 0, errors.New(cfmt.Serrorf("%s is not numeric", s)) 21 | } 22 | return i, nil 23 | } 24 | 25 | func parseSource(s string) (string, error) { 26 | if s == "" { 27 | return "", nil 28 | } 29 | for _, c := range validCases { 30 | if c == s { 31 | return s, nil 32 | } 33 | } 34 | return "", errors.New(cfmt.Serrorf("%s is not valid case", s)) 35 | } 36 | 37 | func parseTarget(s string) (string, error) { 38 | if s == "" { 39 | return "", errors.New(cfmt.Serrorf("You must specify target case")) 40 | } 41 | for _, c := range validCases { 42 | if c == s { 43 | return s, nil 44 | } 45 | } 46 | return "", errors.New(cfmt.Serrorf("%s is not valid case", s)) 47 | } 48 | 49 | func parseLines(lines string) (int, int, error) { 50 | if lines == "" { 51 | return 0, 0, nil 52 | } 53 | split := strings.Split(lines, ":") 54 | if len(split) != 2 { 55 | return 0, 0, errors.New(cfmt.Serror("lines must be 'M:N' form")) 56 | } 57 | start, err := parseNumber(split[0]) 58 | if err != nil { 59 | return 0, 0, err 60 | } 61 | end, err := parseNumber(split[1]) 62 | if err != nil { 63 | return 0, 0, err 64 | } 65 | if end > 0 && start > end { 66 | return 0, 0, errors.New(cfmt.Serrorf("[%d] is not valid range", lines)) 67 | } 68 | return start, end, nil 69 | } 70 | 71 | func parseIgnore(ignore []string) (*regexp.Regexp, error) { 72 | reExp := "^$" 73 | if len(ignore) > 0 { 74 | reExp = strings.Join(ignore, "|") 75 | } 76 | re, err := regexp.Compile(reExp) 77 | if err != nil { 78 | return nil, errors.New(cfmt.Serrorf("%s is not valid patten", reExp)) 79 | } 80 | return re, nil 81 | } 82 | -------------------------------------------------------------------------------- /cmd/casec/parse_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "regexp" 5 | "testing" 6 | ) 7 | 8 | func TestParseNumber(t *testing.T) { 9 | testCases := []struct { 10 | input string 11 | expected int 12 | }{ 13 | {input: "", expected: 0}, 14 | {input: "3", expected: 3}, 15 | } 16 | 17 | failingTestCases := []struct { 18 | input string 19 | expected int 20 | }{ 21 | {input: "i0", expected: 0}, 22 | } 23 | 24 | for i, tc := range testCases { 25 | n, err := parseNumber(tc.input) 26 | if n != tc.expected { 27 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, n) 28 | } 29 | if err != nil { 30 | t.Errorf("[%d] There must be no errors", i+1) 31 | } 32 | } 33 | 34 | for i, tc := range failingTestCases { 35 | n, err := parseNumber(tc.input) 36 | if n != tc.expected { 37 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, n) 38 | } 39 | if err == nil { 40 | t.Errorf("[%d] There must be errors", i+1) 41 | } 42 | } 43 | } 44 | 45 | func TestParseSource(t *testing.T) { 46 | testCases := []struct { 47 | input string 48 | expected string 49 | }{ 50 | {input: "", expected: ""}, 51 | {input: "snake", expected: "snake"}, 52 | } 53 | 54 | failingTestCases := []struct { 55 | input string 56 | expected string 57 | }{ 58 | {input: "special", expected: ""}, 59 | } 60 | 61 | for i, tc := range testCases { 62 | src, err := parseSource(tc.input) 63 | if src != tc.expected { 64 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, src) 65 | } 66 | if err != nil { 67 | t.Errorf("[%d] There must be no errors", i+1) 68 | } 69 | } 70 | 71 | for i, tc := range failingTestCases { 72 | src, err := parseSource(tc.input) 73 | if src != tc.expected { 74 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, src) 75 | } 76 | if err == nil { 77 | t.Errorf("[%d] There must be errors", i+1) 78 | } 79 | } 80 | } 81 | 82 | func TestParseTarget(t *testing.T) { 83 | testCases := []struct { 84 | input string 85 | expected string 86 | }{ 87 | {input: "camel", expected: "camel"}, 88 | } 89 | 90 | failingTestCases := []struct { 91 | input string 92 | expected string 93 | }{ 94 | {input: "", expected: ""}, 95 | {input: "special", expected: ""}, 96 | } 97 | 98 | for i, tc := range testCases { 99 | tgt, err := parseTarget(tc.input) 100 | if tgt != tc.expected { 101 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, tgt) 102 | } 103 | if err != nil { 104 | t.Errorf("[%d] There must be no errors", i+1) 105 | } 106 | } 107 | 108 | for i, tc := range failingTestCases { 109 | src, err := parseTarget(tc.input) 110 | if src != tc.expected { 111 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, src) 112 | } 113 | if err == nil { 114 | t.Errorf("[%d] There must be errors", i+1) 115 | } 116 | } 117 | } 118 | 119 | func TestParseLines(t *testing.T) { 120 | testCases := []struct { 121 | input string 122 | expected1 int 123 | expected2 int 124 | }{ 125 | {input: "5:10", expected1: 5, expected2: 10}, 126 | {input: "5:", expected1: 5, expected2: 0}, 127 | {input: ":10", expected1: 0, expected2: 10}, 128 | {input: ":", expected1: 0, expected2: 0}, 129 | {input: "", expected1: 0, expected2: 0}, 130 | } 131 | 132 | failingTestCases := []struct { 133 | input string 134 | expected1 int 135 | expected2 int 136 | }{ 137 | {input: "5:2", expected1: 0, expected2: 0}, 138 | {input: "1:10:2", expected1: 0, expected2: 0}, 139 | } 140 | 141 | for i, tc := range testCases { 142 | start, end, err := parseLines(tc.input) 143 | if start != tc.expected1 { 144 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected1, start) 145 | } 146 | if end != tc.expected2 { 147 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected2, end) 148 | } 149 | if err != nil { 150 | t.Errorf("[%d] There must be no errors", i+1) 151 | } 152 | } 153 | 154 | for i, tc := range failingTestCases { 155 | start, end, err := parseLines(tc.input) 156 | if start != tc.expected1 { 157 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected1, start) 158 | } 159 | if end != tc.expected2 { 160 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected2, end) 161 | } 162 | if err == nil { 163 | t.Errorf("[%d] There must be errors", i+1) 164 | } 165 | } 166 | } 167 | 168 | func TestParseIgnore(t *testing.T) { 169 | testCases := []struct { 170 | input []string 171 | expected *regexp.Regexp 172 | }{ 173 | {input: []string{}, expected: regexp.MustCompile("^$")}, 174 | {input: []string{"^*.com$"}, expected: regexp.MustCompile("^*.com$")}, 175 | {input: []string{"github", "bitbucket"}, expected: regexp.MustCompile("github|bitbucket")}, 176 | {input: []string{"^(github|bitbucket)$"}, expected: regexp.MustCompile("^(github|bitbucket)$")}, 177 | } 178 | 179 | failingTestCases := []struct { 180 | input []string 181 | expected *regexp.Regexp 182 | }{ 183 | {input: []string{"*.com"}, expected: nil}, 184 | } 185 | 186 | for i, tc := range testCases { 187 | re, err := parseIgnore(tc.input) 188 | if re.String() != tc.expected.String() { 189 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, re) 190 | } 191 | if err != nil { 192 | t.Errorf("[%d] There must be no errors", i+1) 193 | } 194 | } 195 | 196 | for i, tc := range failingTestCases { 197 | re, err := parseIgnore(tc.input) 198 | if re != nil || tc.expected != nil { 199 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, re) 200 | } 201 | if err == nil { 202 | t.Errorf("[%d] There must be errors", i+1) 203 | } 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /convert.go: -------------------------------------------------------------------------------- 1 | package casec 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | "unicode" 7 | "unicode/utf8" 8 | 9 | "github.com/mingrammer/cfmt" 10 | ) 11 | 12 | func isCaseSeparator(r rune) bool { 13 | return r == SnakeDelimiter || r == KebabDelimiter 14 | } 15 | 16 | func isSeparator(r rune) bool { 17 | return unicode.IsSpace(r) || isCaseSeparator(r) 18 | } 19 | 20 | // Invert inverts the UPPERCASE to lowercase and vice versa 21 | func Invert(s string) string { 22 | var out strings.Builder 23 | for _, r := range s { 24 | switch { 25 | case unicode.IsUpper(r): 26 | out.WriteRune(unicode.ToLower(r)) 27 | case unicode.IsLower(r): 28 | out.WriteRune(unicode.ToUpper(r)) 29 | default: 30 | out.WriteRune(r) 31 | } 32 | } 33 | return out.String() 34 | } 35 | 36 | // ToUpperCase converts the string to uppercase 37 | func ToUpper(s string) string { 38 | if !utf8.ValidString(s) { 39 | return s 40 | } 41 | s = strings.TrimFunc(s, unicode.IsSpace) 42 | return strings.ToUpper(s) 43 | } 44 | 45 | // ToLowerCase converts the string to lowercase 46 | func ToLower(s string) string { 47 | if !utf8.ValidString(s) { 48 | return s 49 | } 50 | s = strings.TrimFunc(s, unicode.IsSpace) 51 | return strings.ToLower(s) 52 | } 53 | 54 | // ToTitleCase converts the string to titlecase 55 | func ToTitle(s string) string { 56 | if !utf8.ValidString(s) { 57 | return s 58 | } 59 | s = strings.TrimFunc(s, unicode.IsSpace) 60 | return strings.Title(s) 61 | } 62 | 63 | // ToCamelCase converts the string to camelcase 64 | // Use strings.Map? 65 | func ToCamel(s string) string { 66 | if !utf8.ValidString(s) { 67 | return s 68 | } 69 | s = strings.TrimFunc(s, unicode.IsSpace) 70 | out := strings.Builder{} 71 | prev := rune(-1) 72 | for _, r := range s { 73 | switch { 74 | case prev < 0: 75 | out.WriteRune(unicode.ToLower(r)) 76 | case isSeparator(prev): 77 | out.WriteRune(unicode.ToTitle(r)) 78 | case !isSeparator(r): 79 | out.WriteRune(r) 80 | } 81 | prev = r 82 | } 83 | return out.String() 84 | } 85 | 86 | // ToPascalCase converts the string to pascalcase 87 | func ToPascal(s string) string { 88 | if !utf8.ValidString(s) { 89 | return s 90 | } 91 | s = strings.TrimFunc(s, unicode.IsSpace) 92 | out := strings.Builder{} 93 | prev := rune(-1) 94 | for _, r := range s { 95 | switch { 96 | case prev < 0: 97 | out.WriteRune(unicode.ToTitle(r)) 98 | case isSeparator(prev): 99 | out.WriteRune(unicode.ToTitle(r)) 100 | case !isSeparator(r): 101 | out.WriteRune(r) 102 | } 103 | prev = r 104 | } 105 | return out.String() 106 | } 107 | 108 | // ToSnakeCase converts the string to snakecase 109 | func ToSnake(s string) string { 110 | if !utf8.ValidString(s) { 111 | return s 112 | } 113 | s = strings.TrimFunc(s, unicode.IsSpace) 114 | out := strings.Builder{} 115 | for i := 0; i < len(s); i++ { 116 | switch { 117 | case unicode.IsUpper(rune(s[i])): 118 | // If the previous letter is lowercase, add '_' letter before the current letter 119 | if i > 0 { 120 | if unicode.IsLower(rune(s[i-1])) { 121 | out.WriteRune(SnakeDelimiter) 122 | } 123 | } 124 | // If the previous letter and the next letter are uppercase and lowercase, respectively, add '_' letter before the current letter 125 | if i > 0 && i < len(s)-1 { 126 | if unicode.IsUpper(rune(s[i-1])) && unicode.IsLower(rune(s[i+1])) { 127 | out.WriteRune(SnakeDelimiter) 128 | } 129 | } 130 | out.WriteRune(unicode.ToLower(rune(s[i]))) 131 | case isSeparator(rune(s[i])): 132 | out.WriteRune(SnakeDelimiter) 133 | default: 134 | out.WriteByte(s[i]) 135 | } 136 | } 137 | return out.String() 138 | } 139 | 140 | // ToKebabCase converts the string to kebabcase 141 | func ToKebab(s string) string { 142 | if !utf8.ValidString(s) { 143 | return s 144 | } 145 | s = strings.TrimFunc(s, unicode.IsSpace) 146 | out := strings.Builder{} 147 | for i := 0; i < len(s); i++ { 148 | switch { 149 | case unicode.IsUpper(rune(s[i])): 150 | // If the previous letter is lowercase, add '-' letter before the current letter 151 | if i > 0 { 152 | if unicode.IsLower(rune(s[i-1])) { 153 | out.WriteRune(KebabDelimiter) 154 | } 155 | } 156 | // If the previous letter and the next letter are uppercase and lowercase, respectively, add '-' letter before the current letter 157 | if i > 0 && i < len(s)-1 { 158 | if unicode.IsUpper(rune(s[i-1])) && unicode.IsLower(rune(s[i+1])) { 159 | out.WriteRune(KebabDelimiter) 160 | } 161 | } 162 | out.WriteRune(unicode.ToLower(rune(s[i]))) 163 | case isSeparator(rune(s[i])): 164 | out.WriteRune(KebabDelimiter) 165 | default: 166 | out.WriteByte(s[i]) 167 | } 168 | } 169 | return out.String() 170 | } 171 | 172 | // ToCaseFor converts the string to specific case 173 | func ToCaseFor(c, s string) (string, error) { 174 | switch c { 175 | case "upper": 176 | return ToUpper(s), nil 177 | case "lower": 178 | return ToLower(s), nil 179 | case "title": 180 | return ToTitle(s), nil 181 | case "camel": 182 | return ToCamel(s), nil 183 | case "pascal": 184 | return ToPascal(s), nil 185 | case "snake": 186 | return ToSnake(s), nil 187 | case "kebab", "lisp": 188 | return ToKebab(s), nil 189 | } 190 | return "", errors.New(cfmt.Serrorf("%s is not valid case", c)) 191 | } 192 | -------------------------------------------------------------------------------- /convert_test.go: -------------------------------------------------------------------------------- 1 | package casec 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestInvert(t *testing.T) { 8 | testCases := []struct { 9 | text string 10 | expected string 11 | }{ 12 | {text: "UPPERCASE", expected: "uppercase"}, 13 | {text: "lowercase", expected: "LOWERCASE"}, 14 | {text: "mIxEdCaSe", expected: "MiXeDcAsE"}, 15 | {text: "weird-Case", expected: "WEIRD-cASE"}, 16 | } 17 | 18 | for i, tc := range testCases { 19 | if s := Invert(tc.text); s != tc.expected { 20 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, s) 21 | } 22 | } 23 | } 24 | 25 | func TestToUpper(t *testing.T) { 26 | testCases := []struct { 27 | text string 28 | expected string 29 | }{ 30 | {text: "case", expected: "CASE"}, 31 | {text: "upper_case", expected: "UPPER_CASE"}, 32 | {text: "This is a sentence", expected: "THIS IS A SENTENCE"}, 33 | } 34 | 35 | for i, tc := range testCases { 36 | if s := ToUpper(tc.text); s != tc.expected { 37 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, s) 38 | } 39 | } 40 | } 41 | 42 | func TestToLower(t *testing.T) { 43 | testCases := []struct { 44 | text string 45 | expected string 46 | }{ 47 | {text: "Case", expected: "case"}, 48 | {text: "LOWER_CASE", expected: "lower_case"}, 49 | {text: "This is a sentence", expected: "this is a sentence"}, 50 | } 51 | 52 | for i, tc := range testCases { 53 | if s := ToLower(tc.text); s != tc.expected { 54 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, s) 55 | } 56 | } 57 | } 58 | 59 | func TestToTitle(t *testing.T) { 60 | testCases := []struct { 61 | text string 62 | expected string 63 | }{ 64 | {text: "case", expected: "Case"}, 65 | {text: "title_case", expected: "Title_case"}, 66 | {text: "This is a sentence", expected: "This Is A Sentence"}, 67 | } 68 | 69 | for i, tc := range testCases { 70 | if s := ToTitle(tc.text); s != tc.expected { 71 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, s) 72 | } 73 | } 74 | } 75 | 76 | func TestToCamel(t *testing.T) { 77 | testCases := []struct { 78 | text string 79 | expected string 80 | }{ 81 | {text: "case", expected: "case"}, 82 | {text: "snake_case", expected: "snakeCase"}, 83 | {text: "This is a sentence", expected: "thisIsASentence"}, 84 | {text: "ConsecutiveUPPERCase", expected: "consecutiveUPPERCase"}, 85 | {text: "Unknown-SpecialCase", expected: "unknownSpecialCase"}, 86 | } 87 | 88 | for i, tc := range testCases { 89 | if s := ToCamel(tc.text); s != tc.expected { 90 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, s) 91 | } 92 | } 93 | } 94 | 95 | func TestToPascal(t *testing.T) { 96 | testCases := []struct { 97 | text string 98 | expected string 99 | }{ 100 | {text: "case", expected: "Case"}, 101 | {text: "snake_case", expected: "SnakeCase"}, 102 | {text: "This is a sentence", expected: "ThisIsASentence"}, 103 | {text: "consecutiveUPPERCase", expected: "ConsecutiveUPPERCase"}, 104 | {text: "Unknown-SpecialCase", expected: "UnknownSpecialCase"}, 105 | } 106 | 107 | for i, tc := range testCases { 108 | if s := ToPascal(tc.text); s != tc.expected { 109 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, s) 110 | } 111 | } 112 | } 113 | 114 | func TestToSnake(t *testing.T) { 115 | testCases := []struct { 116 | text string 117 | expected string 118 | }{ 119 | {text: "case", expected: "case"}, 120 | {text: "camelCase", expected: "camel_case"}, 121 | {text: "This is a sentence", expected: "this_is_a_sentence"}, 122 | {text: "ConsecutiveUPPERCase", expected: "consecutive_upper_case"}, 123 | {text: "Unknown-SpecialCase", expected: "unknown_special_case"}, 124 | } 125 | 126 | for i, tc := range testCases { 127 | if s := ToSnake(tc.text); s != tc.expected { 128 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, s) 129 | } 130 | } 131 | } 132 | 133 | func TestToKebab(t *testing.T) { 134 | testCases := []struct { 135 | text string 136 | expected string 137 | }{ 138 | {text: "case", expected: "case"}, 139 | {text: "camelCase", expected: "camel-case"}, 140 | {text: "This is a sentence", expected: "this-is-a-sentence"}, 141 | {text: "ConsecutiveUPPERCase", expected: "consecutive-upper-case"}, 142 | {text: "Unknown-SpecialCase", expected: "unknown-special-case"}, 143 | } 144 | 145 | for i, tc := range testCases { 146 | if s := ToKebab(tc.text); s != tc.expected { 147 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, s) 148 | } 149 | } 150 | } 151 | 152 | func TestToCaseFor(t *testing.T) { 153 | testCases := []struct { 154 | kind string 155 | text string 156 | expected string 157 | }{ 158 | {kind: "upper", text: "uppercase", expected: "UPPERCASE"}, 159 | {kind: "lower", text: "LOWERCASE", expected: "lowercase"}, 160 | {kind: "title", text: "titlecase", expected: "Titlecase"}, 161 | {kind: "camel", text: "camel_case", expected: "camelCase"}, 162 | {kind: "pascal", text: "pascal_case", expected: "PascalCase"}, 163 | {kind: "snake", text: "snakeCase", expected: "snake_case"}, 164 | {kind: "kebab", text: "kebabCase", expected: "kebab-case"}, 165 | {kind: "unknown", text: "unknown", expected: ""}, 166 | } 167 | 168 | for i, tc := range testCases { 169 | if s, _ := ToCaseFor(tc.kind, tc.text); s != tc.expected { 170 | t.Errorf("[%d] Expecting %v, got %v", i+1, tc.expected, s) 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mingrammer/casec 2 | 3 | require ( 4 | github.com/davecgh/go-spew v1.1.1 // indirect 5 | github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e // indirect 6 | github.com/mattn/go-isatty v0.0.4 // indirect 7 | github.com/mingrammer/cfmt v1.1.0 8 | github.com/pmezard/go-difflib v1.0.0 // indirect 9 | github.com/sergi/go-diff v1.0.0 10 | github.com/stretchr/testify v1.2.2 // indirect 11 | github.com/urfave/cli v1.20.0 12 | golang.org/x/sys v0.0.0-20181212120007-b05ddf57801d // indirect 13 | ) 14 | 15 | go 1.13 16 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 4 | github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSDrhDjFlsEYmxpFyIoXmYRon3dt0io31k= 5 | github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= 6 | github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= 7 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 8 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 9 | github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= 10 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 11 | github.com/mingrammer/cfmt v1.1.0 h1:fAALVQC+aa20fCvghuB5W6zBAAsGWKGdcZmexpPrvwo= 12 | github.com/mingrammer/cfmt v1.1.0/go.mod h1:Jqg1Lq43AMo3ggnIEpvIDbca1VSvdHDg0H13eDG+/ys= 13 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 14 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 15 | github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= 16 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 17 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= 18 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 19 | github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= 20 | github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= 21 | golang.org/x/sys v0.0.0-20180315095008-cc7307a45468/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 22 | golang.org/x/sys v0.0.0-20181212120007-b05ddf57801d h1:G59MrP9Qg6bymPjN3yGmqnmuCEH1h0eFP8zpRpl1RiU= 23 | golang.org/x/sys v0.0.0-20181212120007-b05ddf57801d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 24 | -------------------------------------------------------------------------------- /testdata/pascal2snake.py.in: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | 4 | def ParseURI(uri): 5 | """Extracts the host, port and db from an uri""" 6 | host, port, db = uri, 6379, 0 7 | if len(host.split('/')) == 2: 8 | host, db = host.split('/') 9 | if len(host.split(':')) == 2: 10 | host, port = host.split(':') 11 | return host, int(port), int(db) 12 | 13 | 14 | if __name__ == '__main__': 15 | argv = sys.argv 16 | IPAddress, Port, DBNum = ParseURI(argv) 17 | print("ip address: ", IPAddress) 18 | print("port: ", Port) 19 | print("db: ", DBNum) -------------------------------------------------------------------------------- /testdata/pascal2snake.py.out: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | 4 | def parse_uri(uri): 5 | """extracts the host, port and db from an uri""" 6 | host, port, db = uri, 6379, 0 7 | if len(host.split('/')) == 2: 8 | host, db = host.split('/') 9 | if len(host.split(':')) == 2: 10 | host, port = host.split(':') 11 | return host, int(port), int(db) 12 | 13 | 14 | if __name__ == '__main__': 15 | argv = sys.argv 16 | ip_address, port, db_num = parse_uri(argv) 17 | print("ip address: ", ip_address) 18 | print("port: ", port) 19 | print("db: ", db_num) -------------------------------------------------------------------------------- /testdata/pascal2snake_ignore.py.in: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from fitter.cachestore import CacheStore 4 | 5 | 6 | class InMemoryStore(CacheStore): 7 | def __init__(self): 8 | self.KVStore = {} 9 | 10 | def get(self, Key): 11 | return json.loads(self.KVStore[Key]) if Key in self.KVStore else None 12 | 13 | def set(self, Key, Value): 14 | self.KVStore[Key] = json.dumps(Value) -------------------------------------------------------------------------------- /testdata/pascal2snake_ignore.py.out: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from fitter.cachestore import CacheStore 4 | 5 | 6 | class InMemoryStore(CacheStore): 7 | def __init__(self): 8 | self.kv_store = {} 9 | 10 | def get(self, key): 11 | return json.loads(self.kv_store[key]) if key in self.kv_store else None 12 | 13 | def set(self, key, value): 14 | self.kv_store[key] = json.dumps(value) -------------------------------------------------------------------------------- /testdata/snake2camel.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "compress/gzip" 5 | "io" 6 | "os" 7 | ) 8 | 9 | func new_writer(log_type string, log_file_name string) (io.WriteCloser, error) { 10 | switch log_type { 11 | case "stdout": 12 | return os.Stdout, nil 13 | case "log": 14 | log_file, err := os.Create(log_file_name) 15 | if err != nil { 16 | return nil, err 17 | } 18 | return log_file, nil 19 | case "gz": 20 | log_file, err := os.Create(log_file_name) 21 | if err != nil { 22 | return nil, err 23 | } 24 | return gzip.NewWriter(log_file), nil 25 | default: 26 | return nil, nil 27 | } 28 | } -------------------------------------------------------------------------------- /testdata/snake2camel.go.out: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "compress/gzip" 5 | "io" 6 | "os" 7 | ) 8 | 9 | func newWriter(logType string, logFileName string) (io.WriteCloser, error) { 10 | switch logType { 11 | case "stdout": 12 | return os.Stdout, nil 13 | case "log": 14 | logFile, err := os.Create(logFileName) 15 | if err != nil { 16 | return nil, err 17 | } 18 | return logFile, nil 19 | case "gz": 20 | logFile, err := os.Create(logFileName) 21 | if err != nil { 22 | return nil, err 23 | } 24 | return gzip.NewWriter(logFile), nil 25 | default: 26 | return nil, nil 27 | } 28 | } -------------------------------------------------------------------------------- /testdata/snake2camel_ignore.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | func new_log(format string, delta time.Duration) string { 8 | switch format { 9 | case "apache_common": 10 | return new_apache_common_log(delta) 11 | case "apache_combined": 12 | return new_apache_combined_log(delta) 13 | case "apache_error": 14 | return new_apache_error_log(delta) 15 | default: 16 | return "" 17 | } 18 | } -------------------------------------------------------------------------------- /testdata/snake2camel_ignore.go.out: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | func newLog(format string, delta time.Duration) string { 8 | switch format { 9 | case "apache_common": 10 | return newApacheCommonLog(delta) 11 | case "apache_combined": 12 | return newApacheCombinedLog(delta) 13 | case "apache_error": 14 | return newApacheErrorLog(delta) 15 | default: 16 | return "" 17 | } 18 | } -------------------------------------------------------------------------------- /testdata/snake2pascal_lines_ignore.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | func new_log(format string, delta time.Duration) string { 8 | switch format { 9 | case "apache_common": 10 | return new_apache_common_log(delta) 11 | case "apache_combined": 12 | return new_apache_combined_log(delta) 13 | case "apache_error": 14 | return new_apache_error_log(delta) 15 | default: 16 | return "" 17 | } 18 | } -------------------------------------------------------------------------------- /testdata/snake2pascal_lines_ignore.go.out: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | func new_log(format string, delta time.Duration) string { 8 | switch format { 9 | case "ApacheCommon": 10 | return NewApacheCommonLog(delta) 11 | case "ApacheCombined": 12 | return NewApacheCombinedLog(delta) 13 | case "ApacheError": 14 | return NewApacheErrorLog(delta) 15 | default: 16 | return "" 17 | } 18 | } --------------------------------------------------------------------------------