Skip to content
This repository has been archived by the owner on Dec 15, 2019. It is now read-only.

Commit

Permalink
Merge pull request #16 from aybabtme/readmap-with-arrays
Browse files Browse the repository at this point in the history
Implements case where a map in ReadMap contains arrays.
  • Loading branch information
benbjohnson committed May 23, 2014
2 parents 25706cc + 050ac8f commit 6966f50
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 2 deletions.
68 changes: 66 additions & 2 deletions scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Scanner interface {
ReadFloat64(target *float64) error
ReadBool(target *bool) error
ReadMap(target *map[string]interface{}) error
ReadArray(target *[]interface{}) error
}

type scanner struct {
Expand Down Expand Up @@ -581,8 +582,12 @@ func (s *scanner) ReadMap(target *map[string]interface{}) error {
}
v[key] = m
case TLBRACKET:
// TODO: Read arrays.
panic("Not supported yet")
s.Unscan(tok, b)
var arr []interface{}
if err := s.ReadArray(&arr); err != nil {
return err
}
v[key] = arr
default:
return fmt.Errorf("Unexpected %s at %d: %s", TokenName(tok), s.Pos(), string(b))
}
Expand All @@ -592,3 +597,62 @@ func (s *scanner) ReadMap(target *map[string]interface{}) error {

return nil
}

func (s *scanner) ReadArray(target *[]interface{}) error {
if tok, b, err := s.Scan(); err != nil {
return err
} else if tok != TLBRACKET {
return fmt.Errorf("Unexpected %s at %d: %s; expected '['", TokenName(tok), s.Pos(), string(b))
}

index := 0
for {
tok, b, err := s.Scan()
if err != nil {
return err
} else if tok == TRBRACKET {
return nil
} else if tok == TCOMMA {
if index == 0 {
return fmt.Errorf("Unexpected comma in array at %d", s.Pos())
}
if tok, b, err = s.Scan(); err != nil {
return err
}
}

var v interface{}
switch tok {
case TSTRING:
v = string(b)
case TNUMBER:
v, _ = strconv.ParseFloat(string(b), 64)
case TTRUE:
v = true
case TFALSE:
v = false
case TNULL:
v = nil
case TLBRACE:
s.Unscan(tok, b)
m := make(map[string]interface{})
if err := s.ReadMap(&m); err != nil {
return err
}
v = m
case TLBRACKET:
s.Unscan(tok, b)
var arr []interface{}
if err := s.ReadArray(&arr); err != nil {
return err
}
v = arr
default:
return fmt.Errorf("Unexpected %s at %d: %s", TokenName(tok), s.Pos(), string(b))
}
*target = append(*target, v)

index++
}
return nil
}
11 changes: 11 additions & 0 deletions scanner/scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,17 @@ func TestReadMap(t *testing.T) {
assert.Equal(t, nested["xxx"], "yyy")
}

// Ensures that a map with arrays can be read into a field.
func TestReadMapWithArray(t *testing.T) {
var v map[string]interface{}
err := NewScanner(strings.NewReader(`{"foo":["bar", 42]}`)).ReadMap(&v)
assert.NoError(t, err)
arr := v["foo"].([]interface{})
t.Logf("got=%#v", v)
assert.Equal(t, "bar", arr[0].(string))
assert.Equal(t, 42.0, arr[1].(float64))
}

func BenchmarkScanNumber(b *testing.B) {
withBuffer(b, "100", func(buf []byte) {
s := NewScanner(bytes.NewBuffer(buf))
Expand Down

0 comments on commit 6966f50

Please sign in to comment.