add doc.get and get subcommand

master
Jordan Orelli 10 years ago
parent bc33c4936e
commit 268bf0eea2

@ -54,6 +54,19 @@ func to_json(n int) {
os.Stdout.Write(b) os.Stdout.Write(b)
} }
func get() {
docpath := flag.Arg(1)
doc, err := moon.Read(input(2))
if err != nil {
bail(1, "input error: %s", err)
}
var v interface{}
if err := doc.Get(docpath, &v); err != nil {
bail(1, "error reading value at path %s: %s", docpath, err)
}
fmt.Println(v)
}
func bail(status int, t string, args ...interface{}) { func bail(status int, t string, args ...interface{}) {
var w io.Writer var w io.Writer
if status == 0 { if status == 0 {
@ -72,8 +85,10 @@ func main() {
check() check()
case "to": case "to":
to() to()
case "get":
get()
case "": case "":
bail(1, "must specify an action.\nvalid actions: check lex parse to") bail(1, "must specify an action.\nvalid actions: check to get")
default: default:
bail(1, "no such action:%s", flag.Arg(0)) bail(1, "no such action:%s", flag.Arg(0))
} }

@ -2,6 +2,8 @@ package moon
import ( import (
"encoding/json" "encoding/json"
"fmt"
"reflect"
) )
type Doc struct { type Doc struct {
@ -11,3 +13,24 @@ type Doc struct {
func (d *Doc) MarshalJSON() ([]byte, error) { func (d *Doc) MarshalJSON() ([]byte, error) {
return json.Marshal(d.items) return json.Marshal(d.items)
} }
func (d *Doc) Get(path string, dest interface{}) error {
if d.items == nil {
return fmt.Errorf("no item found at path %s (doc is empty)", path)
}
v, ok := d.items[path]
if !ok {
return fmt.Errorf("no item found at path %s", path)
}
dt := reflect.TypeOf(dest)
if dt.Kind() != reflect.Ptr {
return fmt.Errorf("destination is of type %v; a pointer type is required", dt)
}
dv := reflect.ValueOf(dest)
dve := dv.Elem()
dve.Set(reflect.ValueOf(v))
return nil
}

@ -0,0 +1,23 @@
package moon
import (
"testing"
)
func TestDoc(t *testing.T) {
doc, err := ReadString(`
name: "jordan"
`)
if err != nil {
t.Error(err)
return
}
var name string
if err := doc.Get("name", &name); err != nil {
t.Error(err)
return
}
if name != "jordan" {
t.Errorf("unexpected name value, expected 'jordan', saw '%s'", name)
}
}

@ -1,6 +1,7 @@
package moon package moon
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"strings" "strings"
@ -8,6 +9,10 @@ import (
const () const ()
// Reads a moon document from a given io.Reader. The io.Reader is advanced to
// EOF. The reader is not closed after reading, since it's an io.Reader and not
// an io.ReadCloser. In the event of error, the state that the source reader
// will be left in is undefined.
func Read(r io.Reader) (*Doc, error) { func Read(r io.Reader) (*Doc, error) {
tree, err := parse(r) tree, err := parse(r)
if err != nil { if err != nil {
@ -25,6 +30,18 @@ func Read(r io.Reader) (*Doc, error) {
return &Doc{items: ctx}, nil return &Doc{items: ctx}, nil
} }
// Reads a moon document from a string. This is purely a convenience method;
// all it does is create a buffer and call the moon.Read function.
func ReadString(source string) (*Doc, error) {
return Read(strings.NewReader(source))
}
// Reads a moon document from a slice of bytes. This is purely a concenience
// method; like ReadString, it simply creates a buffer and calls moon.Read
func ReadBytes(b []byte) (*Doc, error) {
return Read(bytes.NewBuffer(b))
}
func parse(r io.Reader) (node, error) { func parse(r io.Reader) (node, error) {
p := &parser{ p := &parser{
root: newRootNode(), root: newRootNode(),

Loading…
Cancel
Save