Skip to content

Instantly share code, notes, and snippets.

@saml
Last active April 19, 2016 15:09
Show Gist options
  • Select an option

  • Save saml/e42a12812dc94168f4ed75da63db2916 to your computer and use it in GitHub Desktop.

Select an option

Save saml/e42a12812dc94168f4ed75da63db2916 to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"encoding/json"
"fmt"
"html/template"
)
type WebPage struct {
Title string `json:"title"`
Components []Component `json:"components"`
}
type Component interface {
HTML() template.HTML
Type() string
}
type webPage struct {
Title string `json:"title"`
Components []*component `json:"components"`
}
type component struct {
Type string `json:"_type"`
Args json.RawMessage `json:"_args"`
}
func (p *WebPage) UnmarshalJSON(d []byte) error {
var w webPage
err := json.Unmarshal(d, &w)
if err != nil {
return err
}
p.Title = w.Title
p.Components = make([]Component, 0)
var component interface{}
for _, c := range w.Components {
switch c.Type {
case "Image":
component = new(Image)
case "Author":
component = new(Author)
case "Paragraph":
component = new(Paragraph)
}
err = json.Unmarshal(c.Args, component)
if err != nil {
panic(err)
}
p.Components = append(p.Components, component.(Component))
}
return nil
}
func (p *WebPage) MarshalJSON() ([]byte, error) {
var w webPage
w.Title = p.Title
w.Components = make([]*component, 0, len(p.Components))
for _, c := range p.Components {
b, err := json.Marshal(c)
if err != nil {
panic(err)
}
w.Components = append(w.Components, &component{
Type: c.Type(),
Args: b,
})
}
b, err := json.Marshal(w)
if err != nil {
panic(err)
}
return b, nil
}
type Image struct {
URL string `json:"url"`
Width int `json:"width"`
}
func (i *Image) Type() string {
return "Image"
}
func (i *Image) HTML() template.HTML {
return template.HTML(fmt.Sprintf(`<img src="%s" width="%d">`, i.URL, i.Width))
}
type Author struct {
URL string `json:"url"`
Name string `json:"name"`
}
func (a *Author) Type() string {
return "Author"
}
func (a *Author) HTML() template.HTML {
return template.HTML(fmt.Sprintf(`<a rel="author" href="%s">%s</a>`, a.URL, a.Name))
}
type Paragraph struct {
Text string `json:"text"`
}
func (p *Paragraph) Type() string {
return "Paragraph"
}
func (p *Paragraph) HTML() template.HTML {
return template.HTML(fmt.Sprintf(`<p>%s</p>`, p.Text))
}
func JSON(x interface{}) string {
b, err := json.Marshal(x)
if err != nil {
panic(err)
}
return string(b)
}
func (p *WebPage) HTML() string {
tmpl := `<!doctype html>
<meta charset="utf-8">
<title>{{.Title}}</title>
{{range .Components}}{{.HTML}}{{end}}
`
var b bytes.Buffer
t, _ := template.New("web").Parse(tmpl)
t.Execute(&b, p)
return b.String()
}
func (p *WebPage) Type() string {
return "WebPage"
}
func main() {
payload := []byte(`
{"components":[
{"_type": "Image", "_args": {"url": "/a.jpg", "width": 100}},
{"_type": "Author", "_args": {"name": "Foo Bar", "url": "/authors/1/"}},
{"_type": "Paragraph", "_args": {"text": "foo bar yolo"}}],
"componentsLength": 3,
"title": "a web page. react.js wow"
}
`)
var webPage WebPage
err := json.Unmarshal(payload, &webPage)
if err != nil {
panic(err)
}
fmt.Println(JSON(&webPage))
fmt.Println(webPage.HTML())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment