From 9d1b2b2df58741f32885bc733e4cf5defccfdf36 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Tue, 21 Apr 2015 23:21:15 -0400 Subject: [PATCH] new subcommand: eval --- cmd/moon/main.go | 28 +++++++++++++++++++++++++--- lib/doc.go | 19 +++++++++++++++++++ lib/emit.go | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/cmd/moon/main.go b/cmd/moon/main.go index 506d630..875aaec 100644 --- a/cmd/moon/main.go +++ b/cmd/moon/main.go @@ -43,7 +43,9 @@ func to() { } func to_json(n int) { - doc, err := moon.Read(input(n)) + in := input(n) + defer in.Close() + doc, err := moon.Read(in) if err != nil { bail(1, "input error: %s", err) } @@ -56,7 +58,10 @@ func to_json(n int) { func get() { docpath := flag.Arg(1) - doc, err := moon.Read(input(2)) + in := input(2) + defer in.Close() + + doc, err := moon.Read(in) if err != nil { bail(1, "input error: %s", err) } @@ -71,6 +76,21 @@ func get() { os.Stdout.Write(b) } +func eval() { + in := input(1) + defer in.Close() + + doc, err := moon.Read(in) + if err != nil { + bail(1, "input error: %s", err) + } + b, err := moon.Encode(doc) + if err != nil { + bail(1, "output error: %s", err) + } + os.Stdout.Write(b) +} + func bail(status int, t string, args ...interface{}) { var w io.Writer if status == 0 { @@ -91,8 +111,10 @@ func main() { to() case "get": get() + case "eval": + eval() case "": - bail(1, "must specify an action.\nvalid actions: check to get") + bail(1, "must specify an action.\nvalid actions: check to get eval") default: bail(1, "no such action:%s", flag.Arg(0)) } diff --git a/lib/doc.go b/lib/doc.go index 21def1b..33ea28f 100644 --- a/lib/doc.go +++ b/lib/doc.go @@ -1,6 +1,7 @@ package moon import ( + "bytes" "encoding/json" "fmt" "reflect" @@ -16,6 +17,24 @@ func (d *Doc) MarshalJSON() ([]byte, error) { return json.Marshal(d.items) } +func (d *Doc) MarshalMoon() ([]byte, error) { + var buf bytes.Buffer + for k, v := range d.items { + buf.WriteString(k) + buf.WriteByte(':') + buf.WriteByte(' ') + b, err := Encode(v) + if err != nil { + return nil, err + } + if _, err := buf.Write(b); err != nil { + return nil, err + } + buf.WriteByte('\n') + } + return buf.Bytes(), nil +} + 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) diff --git a/lib/emit.go b/lib/emit.go index 5438e2f..397d78d 100644 --- a/lib/emit.go +++ b/lib/emit.go @@ -9,6 +9,10 @@ import ( "strconv" ) +type Marshaler interface { + MarshalMoon() ([]byte, error) +} + func Encode(v interface{}) ([]byte, error) { e := &encoder{} if err := e.encode(v); err != nil { @@ -52,7 +56,15 @@ func valueEncoder(v reflect.Value) encodeFn { return typeEncoder(v.Type()) } +var ( + marshalerType = reflect.TypeOf(new(Marshaler)).Elem() +) + func typeEncoder(t reflect.Type) encodeFn { + if t.Implements(marshalerType) { + return marshalerEncoder + } + switch t.Kind() { case reflect.Bool: return encodeBool @@ -70,6 +82,8 @@ func typeEncoder(t reflect.Type) encodeFn { return encodeSlice case reflect.Interface: return encodeInterface + case reflect.Ptr: + return encodePointer case reflect.Map: return encodeMap default: @@ -187,3 +201,24 @@ func encodeMap(e *encoder, v reflect.Value) { } e.WriteByte('}') } + +func encodePointer(e *encoder, v reflect.Value) { + if v.IsNil() { + e.WriteString("null") + return + } + e.encodeValue(v.Elem()) +} + +func marshalerEncoder(e *encoder, v reflect.Value) { + if v.Kind() == reflect.Ptr && v.IsNil() { + e.WriteString("null") + return + } + m := v.Interface().(Marshaler) + b, err := m.MarshalMoon() + if err != nil { + panic(err) + } + e.Write(b) +}