Move parseValue to yqlib/value_parser.go

This commit is contained in:
Conor Nosal 2019-12-02 23:50:32 -05:00 committed by Mike Farah
parent 64d1e58f97
commit 95fec2984e
5 changed files with 69 additions and 46 deletions

View File

@ -4,17 +4,17 @@ type PathParser interface {
ParsePath(path string) []string ParsePath(path string) []string
} }
type parser struct{} type pathParser struct{}
func NewPathParser() PathParser { func NewPathParser() PathParser {
return &parser{} return &pathParser{}
} }
func (p *parser) ParsePath(path string) []string { func (p *pathParser) ParsePath(path string) []string {
return p.parsePathAccum([]string{}, path) return p.parsePathAccum([]string{}, path)
} }
func (p *parser) parsePathAccum(paths []string, remaining string) []string { func (p *pathParser) parsePathAccum(paths []string, remaining string) []string {
head, tail := p.nextYamlPath(remaining) head, tail := p.nextYamlPath(remaining)
if tail == "" { if tail == "" {
return append(paths, head) return append(paths, head)
@ -22,7 +22,7 @@ func (p *parser) parsePathAccum(paths []string, remaining string) []string {
return p.parsePathAccum(append(paths, head), tail) return p.parsePathAccum(append(paths, head), tail)
} }
func (p *parser) nextYamlPath(path string) (pathElement string, remaining string) { func (p *pathParser) nextYamlPath(path string) (pathElement string, remaining string) {
switch path[0] { switch path[0] {
case '[': case '[':
// e.g [0].blah.cat -> we need to return "0" and "blah.cat" // e.g [0].blah.cat -> we need to return "0" and "blah.cat"
@ -36,7 +36,7 @@ func (p *parser) nextYamlPath(path string) (pathElement string, remaining string
} }
} }
func (p *parser) search(path string, matchingChars []uint8, skipNext bool) (pathElement string, remaining string) { func (p *pathParser) search(path string, matchingChars []uint8, skipNext bool) (pathElement string, remaining string) {
for i := 0; i < len(path); i++ { for i := 0; i < len(path); i++ {
var char = path[i] var char = path[i]
if p.contains(matchingChars, char) { if p.contains(matchingChars, char) {
@ -55,7 +55,7 @@ func (p *parser) search(path string, matchingChars []uint8, skipNext bool) (path
return path, "" return path, ""
} }
func (p *parser) contains(matchingChars []uint8, candidate uint8) bool { func (p *pathParser) contains(matchingChars []uint8, candidate uint8) bool {
for _, a := range matchingChars { for _, a := range matchingChars {
if a == candidate { if a == candidate {
return true return true

35
pkg/yqlib/value_parser.go Normal file
View File

@ -0,0 +1,35 @@
package yqlib
import (
"strconv"
)
type ValueParser interface {
ParseValue(argument string) interface{}
}
type valueParser struct{}
func NewValueParser() ValueParser {
return &valueParser{}
}
func (v *valueParser) ParseValue(argument string) interface{} {
var value, err interface{}
var inQuotes = len(argument) > 0 && argument[0] == '"'
if !inQuotes {
value, err = strconv.ParseFloat(argument, 64)
if err == nil {
return value
}
value, err = strconv.ParseBool(argument)
if err == nil {
return value
}
if argument == "[]" {
return make([]interface{}, 0)
}
return argument
}
return argument[1 : len(argument)-1]
}

View File

@ -0,0 +1,25 @@
package yqlib
import (
"testing"
"github.com/mikefarah/yq/test"
)
var parseValueTests = []struct {
argument string
expectedResult interface{}
testDescription string
}{
{"true", true, "boolean"},
{"\"true\"", "true", "boolean as string"},
{"3.4", 3.4, "number"},
{"\"3.4\"", "3.4", "number as string"},
{"", "", "empty string"},
}
func TestParseValue(t *testing.T) {
for _, tt := range parseValueTests {
test.AssertResultWithContext(t, tt.expectedResult, NewValueParser().ParseValue(tt.argument), tt.testDescription)
}
}

23
yq.go
View File

@ -34,6 +34,7 @@ var log = logging.MustGetLogger("yq")
var lib = yqlib.NewYqLib(log) var lib = yqlib.NewYqLib(log)
var jsonConverter = marshal.NewJsonConverter() var jsonConverter = marshal.NewJsonConverter()
var yamlConverter = marshal.NewYamlConverter() var yamlConverter = marshal.NewYamlConverter()
var valueParser = yqlib.NewValueParser()
func main() { func main() {
cmd := newCommandCLI() cmd := newCommandCLI()
@ -557,31 +558,11 @@ func readWriteCommands(args []string, expectedArgs int, badArgsMessage string) (
return nil, errors.New(badArgsMessage) return nil, errors.New(badArgsMessage)
} else { } else {
writeCommands = make(yaml.MapSlice, 1) writeCommands = make(yaml.MapSlice, 1)
writeCommands[0] = yaml.MapItem{Key: args[expectedArgs-2], Value: parseValue(args[expectedArgs-1])} writeCommands[0] = yaml.MapItem{Key: args[expectedArgs-2], Value: valueParser.ParseValue(args[expectedArgs-1])}
} }
return writeCommands, nil return writeCommands, nil
} }
func parseValue(argument string) interface{} {
var value, err interface{}
var inQuotes = len(argument) > 0 && argument[0] == '"'
if !inQuotes {
value, err = strconv.ParseFloat(argument, 64)
if err == nil {
return value
}
value, err = strconv.ParseBool(argument)
if err == nil {
return value
}
if argument == "[]" {
return make([]interface{}, 0)
}
return argument
}
return argument[1 : len(argument)-1]
}
func toString(context interface{}) (string, error) { func toString(context interface{}) (string, error) {
if outputToJSON { if outputToJSON {
return jsonConverter.JsonToString(context) return jsonConverter.JsonToString(context)

View File

@ -9,24 +9,6 @@ import (
"github.com/mikefarah/yq/test" "github.com/mikefarah/yq/test"
) )
var parseValueTests = []struct {
argument string
expectedResult interface{}
testDescription string
}{
{"true", true, "boolean"},
{"\"true\"", "true", "boolean as string"},
{"3.4", 3.4, "number"},
{"\"3.4\"", "3.4", "number as string"},
{"", "", "empty string"},
}
func TestParseValue(t *testing.T) {
for _, tt := range parseValueTests {
test.AssertResultWithContext(t, tt.expectedResult, parseValue(tt.argument), tt.testDescription)
}
}
func TestMultilineString(t *testing.T) { func TestMultilineString(t *testing.T) {
testString := ` testString := `
abcd abcd