From 4006ceaa79608517a8acc5717d95ddd869be1d25 Mon Sep 17 00:00:00 2001 From: Inanc Gumus Date: Tue, 3 Sep 2019 23:07:25 +0300 Subject: [PATCH] update: marshaler interface --- interfaces/10-marshaler/book.go | 4 +- interfaces/10-marshaler/list.go | 30 --------- interfaces/10-marshaler/main.go | 98 +++++++--------------------- interfaces/10-marshaler/product.go | 4 +- interfaces/10-marshaler/timestamp.go | 77 ++++++++++++++++++++++ 5 files changed, 105 insertions(+), 108 deletions(-) create mode 100644 interfaces/10-marshaler/timestamp.go diff --git a/interfaces/10-marshaler/book.go b/interfaces/10-marshaler/book.go index 66de72e..9634a16 100644 --- a/interfaces/10-marshaler/book.go +++ b/interfaces/10-marshaler/book.go @@ -13,9 +13,11 @@ import ( type book struct { product + + // Published (timestamp) knows how to print, encode and decode itself. Published timestamp } -func (b book) String() string { +func (b *book) String() string { return fmt.Sprintf("%s - (%s)", &b.product, b.Published) } diff --git a/interfaces/10-marshaler/list.go b/interfaces/10-marshaler/list.go index a7289ae..69da963 100644 --- a/interfaces/10-marshaler/list.go +++ b/interfaces/10-marshaler/list.go @@ -8,9 +8,7 @@ package main import ( - "encoding/json" "fmt" - "reflect" "strings" ) @@ -19,42 +17,14 @@ type item interface { fmt.Stringer } -// schema adds an additional category field -// to the product types. -type schema struct { - // Category is the product category field. - Category string - - // Item is an interface value. - // Here, we are embedding an interface value. - Item item -} - type list []item -// MarshalJSON is an implementation of the json.Marshaler interface. -// json.Marshal and Decode call this method. -func (l list) MarshalJSON() ([]byte, error) { - var schemas []schema - - 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}) - } - - 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') diff --git a/interfaces/10-marshaler/main.go b/interfaces/10-marshaler/main.go index ea827a3..b9afe64 100644 --- a/interfaces/10-marshaler/main.go +++ b/interfaces/10-marshaler/main.go @@ -14,85 +14,35 @@ import ( ) func main() { - // store := list{ - // &book{product{"moby dick", 10}, 118281600}, - // &book{product{"odyssey", 15}, "733622400"}, - // &book{product{"hobbit", 25}, nil}, - // &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) - - encode() -} - -func encode() { - - books := []*book{ - {product{"moby dick", 10}, toTime(118281600)}, - {product{"odyssey", 15}, toTime("733622400")}, - {product{"hobbit", 25}, zeroTimestamp}, + 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}}, } - for _, b := range books { - fmt.Println(b) - } - - out, err := json.MarshalIndent(books, "", "\t") + out, err := json.MarshalIndent(store, "", "\t") if err != nil { log.Fatalln(err) } fmt.Println(string(out)) -} - -func decode() { - // books = nil - out := []byte(`[ - { - "Title": "moby dick", - "Price": 10, - "Published": "118281600" - }, - { - "Title": "odyssey", - "Price": 15, - "Published": 733622400 - }, - { - "Title": "hobbit", - "Price": 25, - "Published": -62135596800 - }, - { - "Title": "poka", - "Price": 25, - "Published": "1983/03" - }, - { - "Title": "fuka", - "Price": 25 - } -]`) - - var books []*book - - err := json.Unmarshal(out, &books) - if err != nil { - log.Fatalln(err) - } - - for _, b := range books { - fmt.Println(b) - } + + // store.discount(.5) + // fmt.Print(store) + + // ---- + + // var ts timestamp + // json.Unmarshal([]byte(`118281600`), &ts) + // fmt.Println(ts) + + // json.Unmarshal([]byte(`"18281600"`), &ts) + // fmt.Println(ts) + + // json.Unmarshal([]byte(`"incorrect"`), &ts) + // fmt.Println(ts) } diff --git a/interfaces/10-marshaler/product.go b/interfaces/10-marshaler/product.go index 2fd584d..f93cb84 100644 --- a/interfaces/10-marshaler/product.go +++ b/interfaces/10-marshaler/product.go @@ -7,9 +7,7 @@ package main -import ( - "fmt" -) +import "fmt" type product struct { Title string diff --git a/interfaces/10-marshaler/timestamp.go b/interfaces/10-marshaler/timestamp.go new file mode 100644 index 0000000..dad84a2 --- /dev/null +++ b/interfaces/10-marshaler/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 is an implementation of the json.Marshaler interface. +// json.Marshal and json.Encode call this method. +func (ts timestamp) MarshalJSON() (out []byte, err error) { + u := time.Time(ts).Unix() + return strconv.AppendInt(out, u, 10), nil +} + +// UnmarshalJSON is an implementation of the json.Unmarshaler interface. +// json.Unmarshal and json.Decode call this method. +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 +} + +func (ts timestamp) String() string { + t := time.Time(ts) + + if t.IsZero() { + return "unknown" + } + + return t.Format(layout) +} + +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)) +}