diff --git a/interfaces/11-decode-toiface/book.go b/interfaces/11-decode-toiface/book.go new file mode 100644 index 0000000..c36372f --- /dev/null +++ b/interfaces/11-decode-toiface/book.go @@ -0,0 +1,21 @@ +// 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 book struct { + product + Published timestamp +} + +func (b *book) String() string { + return fmt.Sprintf("%s - (%s)", &b.product, b.Published) +} diff --git a/interfaces/11-decode-toiface/database.go b/interfaces/11-decode-toiface/database.go new file mode 100644 index 0000000..f09209e --- /dev/null +++ b/interfaces/11-decode-toiface/database.go @@ -0,0 +1,56 @@ +// 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" + "log" +) + +type database struct { + list *list +} + +func (db *database) UnmarshalJSON(data []byte) error { + var decodables []struct { + Type string + Item json.RawMessage + } + + if err := json.Unmarshal(data, &decodables); err != nil { + log.Fatalln(err) + } + + for _, d := range decodables { + it, err := db.newItem(d.Item, d.Type) + if err != nil { + return err + } + + *db.list = append(*db.list, it) + } + + return nil +} + +func (db *database) newItem(data []byte, itemType string) (it item, _ error) { + switch itemType { + default: + return nil, fmt.Errorf("newItem: type (%q) does not exist", itemType) + case "book": + it = new(book) + case "puzzle": + it = new(puzzle) + case "game": + it = new(game) + case "toy": + it = new(toy) + } + return it, json.Unmarshal(data, &it) +} diff --git a/interfaces/11-decode-toiface/database.json b/interfaces/11-decode-toiface/database.json new file mode 100644 index 0000000..cccab62 --- /dev/null +++ b/interfaces/11-decode-toiface/database.json @@ -0,0 +1,54 @@ +[ + { + "Type": "book", + "Item": { + "Title": "moby dick", + "Price": 10, + "Published": 118281600 + } + }, + { + "Type": "book", + "Item": { + "Title": "odyssey", + "Price": 15, + "Published": 733622400 + } + }, + { + "Type": "book", + "Item": { + "Title": "hobbit", + "Price": 25, + "Published": -62135596800 + } + }, + { + "Type": "puzzle", + "Item": { + "Title": "rubik's cube", + "Price": 5 + } + }, + { + "Type": "game", + "Item": { + "Title": "minecraft", + "Price": 20 + } + }, + { + "Type": "game", + "Item": { + "Title": "tetris", + "Price": 5 + } + }, + { + "Type": "toy", + "Item": { + "Title": "yoda", + "Price": 150 + } + } +] diff --git a/interfaces/11-decode-toiface/game.go b/interfaces/11-decode-toiface/game.go new file mode 100644 index 0000000..3604b15 --- /dev/null +++ b/interfaces/11-decode-toiface/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-decode-toiface/list.go b/interfaces/11-decode-toiface/list.go new file mode 100644 index 0000000..69da963 --- /dev/null +++ b/interfaces/11-decode-toiface/list.go @@ -0,0 +1,40 @@ +// 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" + "strings" +) + +type item interface { + discount(float64) + fmt.Stringer +} + +type list []item + +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-decode-toiface/main.go b/interfaces/11-decode-toiface/main.go new file mode 100644 index 0000000..5aae9cc --- /dev/null +++ b/interfaces/11-decode-toiface/main.go @@ -0,0 +1,54 @@ +// 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" + "io/ioutil" + "log" +) + +func main() { + data, err := ioutil.ReadFile("database.json") + if err != nil { + log.Fatalln(err) + } + + var store list + + db := database{list: &store} + + if err := json.Unmarshal(data, &db); err != nil { + log.Fatalln(err) + } + + fmt.Print(store) + + /* + store := list{ + &book{product{"moby dick", 10}, toTimestamp(118281600)}, + &book{product{"odyssey", 15}, toTimestamp("733622400")}, + &book{product{"hobbit", 25}, unknown}, + &puzzle{product{"rubik's cube", 5}}, + &game{product{"minecraft", 20}}, + &game{product{"tetris", 5}}, + &toy{product{"yoda", 150}}, + } + + out, err := json.MarshalIndent(store, "", "\t") + if err != nil { + log.Fatalln(err) + } + + fmt.Println(string(out)) + + // store.discount(.5) + // fmt.Print(store) + */ +} diff --git a/interfaces/11-decode-toiface/money.go b/interfaces/11-decode-toiface/money.go new file mode 100644 index 0000000..095a039 --- /dev/null +++ b/interfaces/11-decode-toiface/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-decode-toiface/product.go b/interfaces/11-decode-toiface/product.go new file mode 100644 index 0000000..f93cb84 --- /dev/null +++ b/interfaces/11-decode-toiface/product.go @@ -0,0 +1,23 @@ +// 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-decode-toiface/puzzle.go b/interfaces/11-decode-toiface/puzzle.go new file mode 100644 index 0000000..acbaa47 --- /dev/null +++ b/interfaces/11-decode-toiface/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-decode-toiface/timestamp.go b/interfaces/11-decode-toiface/timestamp.go new file mode 100644 index 0000000..28629d8 --- /dev/null +++ b/interfaces/11-decode-toiface/timestamp.go @@ -0,0 +1,77 @@ +// 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 ( + "strconv" + "time" +) + +// Mon Jan 2 15:04:05 -0700 MST 2006 +const layout = "2006/01" + +// unknown is the zero value of a timestamp. +var unknown = timestamp(time.Time{}) + +// timestamp prints timestamps, it's a stringer. +// It is useful even if it's zero. +type timestamp time.Time + +// MarshalJSON from timestamp. +func (ts timestamp) MarshalJSON() (out []byte, err error) { + u := time.Time(ts).Unix() + return strconv.AppendInt(out, u, 10), nil +} + +// UnmarshalJSON data to timestamp. +func (ts *timestamp) UnmarshalJSON(data []byte) error { + s := string(data) + + // Let the ParseInt parse quoted strings. + us, err := strconv.Unquote(s) + if err == nil { + s = us + } + + // Always overwrite the timestamp when decoding. + *ts = unknown + + // Handle the numeric case. + if n, err := strconv.ParseInt(s, 10, 64); err == nil { + *ts = timestamp(time.Unix(n, 0)) + } + + return nil +} + +// String representation of the timestamp. +func (ts timestamp) String() string { + t := time.Time(ts) + + if t.IsZero() { + return "unknown" + } + + return t.Format(layout) +} + +// toTimestamp from an unknown value. +func toTimestamp(v interface{}) timestamp { + var t int + + switch v := v.(type) { + case int: + t = v + case string: + t, _ = strconv.Atoi(v) + default: + return unknown + } + + return timestamp(time.Unix(int64(t), 0)) +} diff --git a/interfaces/11-decode-toiface/toy.go b/interfaces/11-decode-toiface/toy.go new file mode 100644 index 0000000..ab5613d --- /dev/null +++ b/interfaces/11-decode-toiface/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 +}