Skip to content

Commit

Permalink
- Add 'lines' option
Browse files Browse the repository at this point in the history
- Parse and validate the options
  • Loading branch information
mingrammer committed Dec 12, 2018
1 parent 1ddd7c5 commit 4a0e083
Show file tree
Hide file tree
Showing 7 changed files with 435 additions and 92 deletions.
98 changes: 47 additions & 51 deletions cmd/casec.go
Original file line number Diff line number Diff line change
@@ -1,85 +1,81 @@
package main

import (
"errors"
"io/ioutil"
"regexp"
"strings"
"unicode"

"github.com/mingrammer/casec"
"github.com/mingrammer/cfmt"
)

func isCaseSeparator(r rune) bool {
return r == casec.SnakeDelimiter || r == casec.KebabDelimiter
}

func convertWord(word, from, to string) (string, error) {
if from != "" {
is, err := casec.IsCaseOf(from, word)
if err != nil {
return "", err
}
if !is {
return word, nil
func convertWord(word, src, tgt string) string {
if src != "" {
if is, _ := casec.IsCaseOf(src, word); is {
word, _ = casec.ToCaseFor(tgt, word)
}
}
return casec.ToCaseFor(to, word)
return word
}

func convertText(text, from, to string, ignore []string) (string, error) {
reExpr := "^$"
if len(ignore) > 0 {
reExpr = strings.Join(ignore, "|")
func convertText(text, src, tgt string, start, end int, ignoreRe *regexp.Regexp) string {
var convLines []string
lines := strings.Split(text, "\n")
if start <= 0 {
start = 1
}
re, err := regexp.Compile(reExpr)
if err != nil {
return "", errors.New(cfmt.Serrorf("%s is not valid patten", reExpr))
if end <= 0 {
end = len(lines)
}
out := strings.Builder{}
chunk := strings.Builder{}
size := len(text)
lastLetter := false
for i, r := range text {
if unicode.IsLetter(r) || isCaseSeparator(r) {
chunk.WriteRune(r)
if i < size-1 {
continue
}
lastLetter = true
}
if chunk.Len() > 0 {
word := chunk.String()
if !re.MatchString(word) {
word, err = convertWord(word, from, to)
if err != nil {
return "", err
for i, line := range lines {
if i >= start-1 && i <= end-1 {
conv := strings.Builder{}
chunk := strings.Builder{}
size := len(line)
lastLetter := false
for j, r := range line {
if unicode.IsLetter(r) || isCaseSeparator(r) {
chunk.WriteRune(r)
if j < size-1 {
continue
}
lastLetter = true
}
if chunk.Len() > 0 {
word := chunk.String()
if !ignoreRe.MatchString(word) {
word = convertWord(word, src, tgt)
}
conv.WriteString(word)
if lastLetter {
break
}
chunk.Reset()
}
conv.WriteRune(r)
}
out.WriteString(word)
if lastLetter {
break
}
chunk.Reset()
line = conv.String()
}
out.WriteRune(r)
convLines = append(convLines, line)
}
return out.String(), nil
out := strings.Join(convLines, "\n")
return out
}

func convertFromText(text, from, to string, ignore []string) (string, string, error) {
converted, err := convertText(text, from, to, ignore)
if err != nil {
return "", "", err
}
return text, converted, nil
func convertFromText(text, src, tgt string, start, end int, ignoreRe *regexp.Regexp) (string, string) {
conv := convertText(text, src, tgt, start, end, ignoreRe)
return text, conv
}

func convertFromFile(fileName, from, to string, ignore []string) (string, string, error) {
func convertFromFile(fileName, src, tgt string, start, end int, ignoreRe *regexp.Regexp) (string, string, error) {
b, err := ioutil.ReadFile(fileName)
if err != nil {
return "", "", err
}
return convertFromText(string(b), from, to, ignore)
text, conv := convertFromText(string(b), src, tgt, start, end, ignoreRe)
return text, conv, nil
}
59 changes: 34 additions & 25 deletions cmd/casec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,77 +2,86 @@ package main

import (
"io/ioutil"
"regexp"
"testing"
)

func TestConvertText_Pascal2Snake(t *testing.T) {
original, err := ioutil.ReadFile("../testdata/pascal2snake.py.in")
orig, err := ioutil.ReadFile("../testdata/pascal2snake.py.in")
if err != nil {
t.Error(err.Error())
}
expected, err := ioutil.ReadFile("../testdata/pascal2snake.py.out")
if err != nil {
t.Error(err.Error())
}
converted, err := convertText(string(original), "pascal", "snake", []string{})
if err != nil {
t.Error(err.Error())
}
if converted != string(expected) {
t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), converted)
re := regexp.MustCompile("^$")
conv := convertText(string(orig), "pascal", "snake", 0, 0, re)
if conv != string(expected) {
t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), conv)
}
}

func TestConvertText_Pascal2Snake_Ignore(t *testing.T) {
original, err := ioutil.ReadFile("../testdata/pascal2snake_ignore.py.in")
orig, err := ioutil.ReadFile("../testdata/pascal2snake_ignore.py.in")
if err != nil {
t.Error(err.Error())
}
expected, err := ioutil.ReadFile("../testdata/pascal2snake_ignore.py.out")
if err != nil {
t.Error(err.Error())
}
converted, err := convertText(string(original), "pascal", "snake", []string{"None", "CacheStore", "InMemoryStore"})
if err != nil {
t.Error(err.Error())
}
if converted != string(expected) {
t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), converted)
re := regexp.MustCompile("^(None|CacheStore|InMemoryStore)$")
conv := convertText(string(orig), "pascal", "snake", 0, 0, re)
if conv != string(expected) {
t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), conv)
}
}

func TestConvertText_Snake2Camel(t *testing.T) {
original, err := ioutil.ReadFile("../testdata/snake2camel.go.in")
orig, err := ioutil.ReadFile("../testdata/snake2camel.go.in")
if err != nil {
t.Error(err.Error())
}
expected, err := ioutil.ReadFile("../testdata/snake2camel.go.out")
if err != nil {
t.Error(err.Error())
}
converted, err := convertText(string(original), "snake", "camel", []string{})
if err != nil {
t.Error(err.Error())
}
if converted != string(expected) {
t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), converted)
re := regexp.MustCompile("^$")
conv := convertText(string(orig), "snake", "camel", 0, 0, re)
if conv != string(expected) {
t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), conv)
}
}

func TestConvertText_Snake2Camel_Ignore(t *testing.T) {
original, err := ioutil.ReadFile("../testdata/snake2camel_ignore.go.in")
orig, err := ioutil.ReadFile("../testdata/snake2camel_ignore.go.in")
if err != nil {
t.Error(err.Error())
}
expected, err := ioutil.ReadFile("../testdata/snake2camel_ignore.go.out")
if err != nil {
t.Error(err.Error())
}
converted, err := convertText(string(original), "snake", "camel", []string{"^apache_common$", "^apache_combined$", "^apache_error$"})
re := regexp.MustCompile("^(apache_common$|apache_combined|apache_error)$")
conv := convertText(string(orig), "snake", "camel", 0, 0, re)
if conv != string(expected) {
t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), conv)
}
}

func TestConvertText_Snake2Pascal_Lines_Ignore(t *testing.T) {
orig, err := ioutil.ReadFile("../testdata/snake2pascal_lines_ignore.go.in")
if err != nil {
t.Error(err.Error())
}
expected, err := ioutil.ReadFile("../testdata/snake2pascal_lines_ignore.go.out")
if err != nil {
t.Error(err.Error())
}
if converted != string(expected) {
t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), converted)
re := regexp.MustCompile("^(switch|case|default|return|format|delta)$")
conv := convertText(string(orig), "snake", "pascal", 8, 17, re)
if conv != string(expected) {
t.Errorf("\nExpecting:\n%s\n\nGot:\n%s", string(expected), conv)
}
}
48 changes: 32 additions & 16 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package main

import (
"errors"
"fmt"
"io"
"log"
"os"
"regexp"

"github.com/mingrammer/cfmt"
"github.com/sergi/go-diff/diffmatchpatch"
Expand Down Expand Up @@ -47,6 +49,10 @@ func main() {
Name: "to, t",
Usage: "target `CASE` in {upper,lower,title,camel,pascal,snake,kebab,lisp}",
},
cli.StringFlag{
Name: "lines, l",
Usage: "set lines `M:N` to be converted. empty means first or last line",
},
cli.StringSliceFlag{
Name: "ignore, i",
Usage: "ignore the text that matches the `PATTERNS`",
Expand All @@ -61,40 +67,50 @@ func main() {
},
}
app.Action = func(ctx *cli.Context) error {
var original string
var converted string
var err error
var orig string
var conv string
var writer io.WriteCloser

var src string
var tgt string
var start int
var end int
var ignoreRe *regexp.Regexp
if len(ctx.Args()) == 0 {
return cli.NewExitError(cfmt.Serror("There are no arguments"), errNoArguments)
return errors.New(cfmt.Serror("There are no arguments"))
}
if src, err = parseSource(ctx.String("from")); err != nil {
return err
}
if tgt, err = parseTarget(ctx.String("to")); err != nil {
return err
}
if ctx.String("to") == "" {
return cli.NewExitError(cfmt.Serror("You must specify target case"), errInvalidOptions)
if start, end, err = parseLines(ctx.String("lines")); err != nil {
return err
}
if ignoreRe, err = parseIgnore(ctx.StringSlice("ignore")); err != nil {
return err
}
input := ctx.Args().Get(0)

from := ctx.String("from")
to := ctx.String("to")
ignore := ctx.StringSlice("ignore")

if ctx.Bool("text") {
original, converted, err = convertFromText(input, from, to, ignore)
orig, conv = convertFromText(input, src, tgt, start, end, ignoreRe)
writer = os.Stdout
} else {
original, converted, err = convertFromFile(input, from, to, ignore)
orig, conv, err = convertFromFile(input, src, tgt, start, end, ignoreRe)
if err != nil {
return err
}
writer, _ = os.OpenFile(input, os.O_RDWR, 0644)
}
if err != nil {
return err
}

if ctx.Bool("dry-run") {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(original, converted, false)
diffs := dmp.DiffMain(orig, conv, false)
fmt.Println(dmp.DiffPrettyText(diffs))
} else {
writer.Write([]byte(converted))
writer.Write([]byte(conv))
writer.Close()
}
return nil
Expand Down
Loading

0 comments on commit 4a0e083

Please sign in to comment.