add: reflection decoder

This commit is contained in:
Inanc Gumus
2019-09-03 12:41:45 +03:00
parent 5f7b9eabed
commit fc349bd51d
10 changed files with 337 additions and 0 deletions

View File

@ -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)
}

View File

@ -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
}
}
]

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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)
// }
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}