From ef9360c8523d6ba4cdbeaf8ddae5def2ada7fbce Mon Sep 17 00:00:00 2001 From: Inanc Gumus Date: Wed, 4 Sep 2019 16:52:53 +0300 Subject: [PATCH] move decoding into the list (reflection interfaces) --- interfaces/11-reflection-decoder/_decoder.go | 60 -------------- .../11-reflection-decoder/_decoder_reader.go | 23 +++--- .../11-reflection-decoder/_main_reader.go | 2 +- interfaces/11-reflection-decoder/decoder.go | 77 ------------------ interfaces/11-reflection-decoder/list.go | 80 +++++++++++++++++-- interfaces/11-reflection-decoder/main.go | 7 +- 6 files changed, 90 insertions(+), 159 deletions(-) delete mode 100644 interfaces/11-reflection-decoder/_decoder.go delete mode 100644 interfaces/11-reflection-decoder/decoder.go diff --git a/interfaces/11-reflection-decoder/_decoder.go b/interfaces/11-reflection-decoder/_decoder.go deleted file mode 100644 index 75f7669..0000000 --- a/interfaces/11-reflection-decoder/_decoder.go +++ /dev/null @@ -1,60 +0,0 @@ -// For more tutorials: https://blog.learngoprogramming.com -// -// Copyright © 2018 Inanc Gumus -// Learn Go Programming Course -// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ -// - -package main - -import ( - "encoding/json" - "reflect" -) - -type decoder map[string]interface{} - -type schema struct { - Category string - Item json.RawMessage -} - -func (d decoder) decode(data []byte) (list, error) { - var schemas []schema - - if err := json.Unmarshal(data, &schemas); err != nil { - return nil, err - } - - return d.products(schemas) -} - -func (d decoder) products(ss []schema) (list, error) { - var store list - - for _, s := range ss { - prod, err := d.product(s.Category, s.Item) - - if err != nil { - return nil, err - } - - store = append(store, prod) - } - - return store, nil -} - -func (d decoder) product(kind string, data []byte) (item, error) { - p := d.newProduct(kind) - - err := json.Unmarshal(data, p) - - return p, err -} - -func (d decoder) newProduct(kind string) item { - t := reflect.TypeOf(d[kind]) - v := reflect.New(t) - return v.Interface().(item) -} diff --git a/interfaces/11-reflection-decoder/_decoder_reader.go b/interfaces/11-reflection-decoder/_decoder_reader.go index b9104f1..a3f656f 100644 --- a/interfaces/11-reflection-decoder/_decoder_reader.go +++ b/interfaces/11-reflection-decoder/_decoder_reader.go @@ -13,24 +13,21 @@ import ( "os" ) -func (d decoder) fromFile(path string) (list, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - - return d.readFile(f) +func fromFile(f *os.File) (list, error) { + return fromReader(f) } -func (d decoder) readFile(f *os.File) (list, error) { - return d.read(f) -} - -func (d decoder) read(r io.Reader) (list, error) { +func fromReader(r io.Reader) (list, error) { data, err := ioutil.ReadAll(r) if err != nil { return nil, err } - return d.decode(data) + var store list + + if err := json.Unmarshal(data, &store); err != nil { + return nil, err + } + + return store, nil } diff --git a/interfaces/11-reflection-decoder/_main_reader.go b/interfaces/11-reflection-decoder/_main_reader.go index 9dc25be..977248d 100644 --- a/interfaces/11-reflection-decoder/_main_reader.go +++ b/interfaces/11-reflection-decoder/_main_reader.go @@ -21,7 +21,7 @@ func main() { "toy": toy{}, } - store, err := dec.read(os.Stdin) + store, err := fromReader(os.Stdin) if err != nil { log.Fatalln(err) } diff --git a/interfaces/11-reflection-decoder/decoder.go b/interfaces/11-reflection-decoder/decoder.go deleted file mode 100644 index feb7fe4..0000000 --- a/interfaces/11-reflection-decoder/decoder.go +++ /dev/null @@ -1,77 +0,0 @@ -// For more tutorials: https://blog.learngoprogramming.com -// -// Copyright © 2018 Inanc Gumus -// Learn Go Programming Course -// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ -// - -package main - -import "encoding/json" - -type decoderSchema struct { - Category string - - // json.RawMessage is a special type of the json package. - // It prevents the json package functions encode/decode - // the specific parts of the json data. - Item json.RawMessage -} - -func decode(data []byte) (list, error) { - var schemas []decoderSchema - - if err := json.Unmarshal(data, &schemas); err != nil { - return nil, err - } - - return toStore(schemas) -} - -func toStore(schemas []decoderSchema) (store list, err error) { - for _, s := range schemas { - p := newProduct(s.Category) - - if json.Unmarshal(s.Item, &p); err != nil { - return nil, err - } - - store = append(store, p) - } - return store, nil -} - -func newProduct(category string) item { - // for each product you need to open this code - // and add a new case. - // - // dependency injection should be the responsibility - // of the user of this function. - switch category { - case "book": - // var b book - // return &b - return new(book) - case "game": - return new(game) - case "puzzle": - return new(puzzle) - case "toy": - return new(toy) - } - return nil -} - -// func (d decoder) newProduct(category string) item { -// t := reflect.TypeOf(d[category]) -// v := reflect.New(t) -// return v.Interface().(item) -// } - -// func toProduct(kind string, data []byte) (item, error) { -// p := newProduct(kind) - -// err := json.Unmarshal(data, p) - -// return p, err -// } diff --git a/interfaces/11-reflection-decoder/list.go b/interfaces/11-reflection-decoder/list.go index 3d644a3..3fa08f9 100644 --- a/interfaces/11-reflection-decoder/list.go +++ b/interfaces/11-reflection-decoder/list.go @@ -19,9 +19,9 @@ type item interface { fmt.Stringer } -// schema adds an additional category field +// itemEncode adds an additional category field // to the product types. -type schema struct { +type itemEncode struct { // Category is the product category field. Category string @@ -30,22 +30,92 @@ type schema struct { Item item } +// itemDecode is used to decode the product types from json. +type itemDecode struct { + // Category is the product category field. + Category string + + // json.RawMessage is a special type of the json package. + // It prevents the json package functions encode/decode + // the specific parts of the json data. + Item json.RawMessage +} + type list []item func (l list) MarshalJSON() ([]byte, error) { - var schemas []schema + var eitems []itemEncode for _, it := range l { // TypeOf -> finds the dynamic type of "it" // Elem -> returns the element type of the pointer // Name -> returns the type name as string cat := reflect.TypeOf(it).Elem().Name() - schemas = append(schemas, schema{cat, it}) + eitems = append(eitems, itemEncode{cat, it}) } - return json.Marshal(schemas) + return json.Marshal(eitems) } +func (l *list) UnmarshalJSON(data []byte) error { + var ditems []itemDecode + + if err := json.Unmarshal(data, &ditems); err != nil { + return err + } + + items, err := decode(ditems) + if err != nil { + return err + } + + *l = items + return nil +} + +// decode and return items as a list. +func decode(data []itemDecode) (items list, err error) { + for _, d := range data { + item := newItem(d.Category) + + if json.Unmarshal(d.Item, &item); err != nil { + return nil, err + } + + items = append(items, item) + } + return items, nil +} + +// newItem creates and returns an item depending on category. +func newItem(category string) item { + // for each product you need to open this code + // and add a new case. + // + // dependency injection should be the responsibility + // of the user of this function. + switch category { + case "book": + // var b book + // return &b + return new(book) + case "game": + return new(game) + case "puzzle": + return new(puzzle) + case "toy": + return new(toy) + } + return nil +} + +// type decoder map[string]interface{} +// func (d decoder) newItem(kind string) item { +// t := reflect.TypeOf(d[kind]) +// v := reflect.New(t) +// return v.Interface().(item) +// } + func (l list) String() string { if len(l) == 0 { return "Sorry. We're waiting for delivery 🚚." diff --git a/interfaces/11-reflection-decoder/main.go b/interfaces/11-reflection-decoder/main.go index fefd0a1..98d3312 100644 --- a/interfaces/11-reflection-decoder/main.go +++ b/interfaces/11-reflection-decoder/main.go @@ -8,6 +8,7 @@ package main import ( + "encoding/json" "fmt" "io/ioutil" "log" @@ -30,14 +31,14 @@ func main() { // } // fmt.Println(string(out)) - + //--- data, err := ioutil.ReadFile("database.json") if err != nil { log.Fatalln(err) } - store, err := decode(data) - if err != nil { + var store list + if err = json.Unmarshal(data, &store); err != nil { log.Fatalln(err) }