From fc349bd51d813f0ca592cd7d9ed14d1fcb95da49 Mon Sep 17 00:00:00 2001 From: Inanc Gumus Date: Tue, 3 Sep 2019 12:41:45 +0300 Subject: [PATCH] add: reflection decoder --- interfaces/11-reflection-decoder/book.go | 53 ++++++++++++++++ .../11-reflection-decoder/database.json | 54 ++++++++++++++++ interfaces/11-reflection-decoder/decoder.go | 63 +++++++++++++++++++ interfaces/11-reflection-decoder/game.go | 12 ++++ interfaces/11-reflection-decoder/list.go | 59 +++++++++++++++++ interfaces/11-reflection-decoder/main.go | 31 +++++++++ interfaces/11-reflection-decoder/money.go | 16 +++++ interfaces/11-reflection-decoder/product.go | 25 ++++++++ interfaces/11-reflection-decoder/puzzle.go | 12 ++++ interfaces/11-reflection-decoder/toy.go | 12 ++++ 10 files changed, 337 insertions(+) create mode 100644 interfaces/11-reflection-decoder/book.go create mode 100644 interfaces/11-reflection-decoder/database.json create mode 100644 interfaces/11-reflection-decoder/decoder.go create mode 100644 interfaces/11-reflection-decoder/game.go create mode 100644 interfaces/11-reflection-decoder/list.go create mode 100644 interfaces/11-reflection-decoder/main.go create mode 100644 interfaces/11-reflection-decoder/money.go create mode 100644 interfaces/11-reflection-decoder/product.go create mode 100644 interfaces/11-reflection-decoder/puzzle.go create mode 100644 interfaces/11-reflection-decoder/toy.go diff --git a/interfaces/11-reflection-decoder/book.go b/interfaces/11-reflection-decoder/book.go new file mode 100644 index 0000000..3e24559 --- /dev/null +++ b/interfaces/11-reflection-decoder/book.go @@ -0,0 +1,53 @@ +// 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" + "fmt" + "strconv" + "time" +) + +type book struct { + product + Published interface{} +} + +func (b book) String() string { + p := format(b.Published) + return fmt.Sprintf("%s - (%v)", &b.product, p) +} + +func (b *book) MarshalJSON() ([]byte, error) { + type jbook book + + jb := (*jbook)(b) + jb.Published = format(b.Published) + + return json.Marshal(jb) +} + +func format(v interface{}) string { + var t int + + switch v := v.(type) { + case int: + t = v + case string: + t, _ = strconv.Atoi(v) + default: + return "unknown" + } + + // Mon Jan 2 15:04:05 -0700 MST 2006 + const layout = "2006/01" + + u := time.Unix(int64(t), 0) + return u.Format(layout) +} diff --git a/interfaces/11-reflection-decoder/database.json b/interfaces/11-reflection-decoder/database.json new file mode 100644 index 0000000..92e780c --- /dev/null +++ b/interfaces/11-reflection-decoder/database.json @@ -0,0 +1,54 @@ +[ + { + "Category": "book", + "Item": { + "Title": "moby dick", + "Price": 10, + "Published": "1973/10" + } + }, + { + "Category": "book", + "Item": { + "Title": "odyssey", + "Price": 15, + "Published": "1993/04" + } + }, + { + "Category": "book", + "Item": { + "Title": "hobbit", + "Price": 25, + "Published": "unknown" + } + }, + { + "Category": "puzzle", + "Item": { + "Title": "rubik's cube", + "Price": 5 + } + }, + { + "Category": "game", + "Item": { + "Title": "minecraft", + "Price": 20 + } + }, + { + "Category": "game", + "Item": { + "Title": "tetris", + "Price": 5 + } + }, + { + "Category": "toy", + "Item": { + "Title": "yoda", + "Price": 150 + } + } +] diff --git a/interfaces/11-reflection-decoder/decoder.go b/interfaces/11-reflection-decoder/decoder.go new file mode 100644 index 0000000..c1ea908 --- /dev/null +++ b/interfaces/11-reflection-decoder/decoder.go @@ -0,0 +1,63 @@ +// 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 +} diff --git a/interfaces/11-reflection-decoder/game.go b/interfaces/11-reflection-decoder/game.go new file mode 100644 index 0000000..3604b15 --- /dev/null +++ b/interfaces/11-reflection-decoder/game.go @@ -0,0 +1,12 @@ +// 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 + +type game struct { + product +} diff --git a/interfaces/11-reflection-decoder/list.go b/interfaces/11-reflection-decoder/list.go new file mode 100644 index 0000000..0a7dede --- /dev/null +++ b/interfaces/11-reflection-decoder/list.go @@ -0,0 +1,59 @@ +// 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" + "fmt" + "reflect" + "strings" +) + +type item interface { + discount(float64) + fmt.Stringer +} + +type schema struct { + Category string + Item item +} + +type list []item + +func (l list) MarshalJSON() ([]byte, error) { + var schemas []schema + + for _, it := range l { + cat := reflect.TypeOf(it).Elem().Name() + schemas = append(schemas, schema{cat, it}) + } + + return json.Marshal(schemas) +} + +func (l list) String() string { + if len(l) == 0 { + return "Sorry. We're waiting for delivery 🚚." + } + + var str strings.Builder + + for _, it := range l { + str.WriteString(it.String()) + str.WriteRune('\n') + } + + return str.String() +} + +func (l list) discount(ratio float64) { + for _, it := range l { + it.discount(ratio) + } +} diff --git a/interfaces/11-reflection-decoder/main.go b/interfaces/11-reflection-decoder/main.go new file mode 100644 index 0000000..30b76f4 --- /dev/null +++ b/interfaces/11-reflection-decoder/main.go @@ -0,0 +1,31 @@ +// 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 ( + "fmt" + "io/ioutil" + "log" +) + +func main() { + data, err := ioutil.ReadFile("database.json") + if err != nil { + log.Fatalln(err) + } + + store, err := decode(data) + if err != nil { + log.Fatalln(err) + } + + fmt.Print(store) + // for _, p := range store { + // fmt.Printf("%#v\n", p) + // } +} diff --git a/interfaces/11-reflection-decoder/money.go b/interfaces/11-reflection-decoder/money.go new file mode 100644 index 0000000..095a039 --- /dev/null +++ b/interfaces/11-reflection-decoder/money.go @@ -0,0 +1,16 @@ +// 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 "fmt" + +type money float64 + +func (m money) String() string { + return fmt.Sprintf("$%.2f", m) +} diff --git a/interfaces/11-reflection-decoder/product.go b/interfaces/11-reflection-decoder/product.go new file mode 100644 index 0000000..2fd584d --- /dev/null +++ b/interfaces/11-reflection-decoder/product.go @@ -0,0 +1,25 @@ +// 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 ( + "fmt" +) + +type product struct { + Title string + Price money +} + +func (p *product) String() string { + return fmt.Sprintf("%-15s: %s", p.Title, p.Price) +} + +func (p *product) discount(ratio float64) { + p.Price *= money(1 - ratio) +} diff --git a/interfaces/11-reflection-decoder/puzzle.go b/interfaces/11-reflection-decoder/puzzle.go new file mode 100644 index 0000000..acbaa47 --- /dev/null +++ b/interfaces/11-reflection-decoder/puzzle.go @@ -0,0 +1,12 @@ +// 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 + +type puzzle struct { + product +} diff --git a/interfaces/11-reflection-decoder/toy.go b/interfaces/11-reflection-decoder/toy.go new file mode 100644 index 0000000..ab5613d --- /dev/null +++ b/interfaces/11-reflection-decoder/toy.go @@ -0,0 +1,12 @@ +// 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 + +type toy struct { + product +}