Slightly redesigned types

This commit is contained in:
Brandon Dyck 2019-03-21 12:40:54 -06:00
parent b402a3b581
commit 8e2910490f

View File

@ -1,4 +1,4 @@
package main package hatmill
import "fmt" import "fmt"
import "io" import "io"
@ -8,34 +8,15 @@ import "strings"
// Html is either Element or Text // Html is either Element or Text
type Html interface { type Html interface {
io.WriterTo io.WriterTo
// isHtml is a non-functional marker to differentiate Html from interface{}
// isHtml is a no-op method to prevent external Html implementations, because
// Go doesn't have sum types.
isHtml() isHtml()
} }
func Reader() io.Reader { // writeStringsTo attempts to write the strings in ss to w, incrementing n by the
// TODO in-order traversal of HTML tree to spit out bytes
return nil
}
func String() string {
panic("this could be trivially implemented with a Reader and a bytes.Buffer")
}
type Attrib struct {
Key string
Value string
}
type element struct {
tagName string
attribs []Attrib
empty bool
children []Html
}
// writeTo attempts to write the strings in ss to w, incrementing n by the
// number of bytes written. // number of bytes written.
func writeTo(w io.Writer, n *int64, ss ...string) error { func writeStringsTo(w io.Writer, n *int64, ss ...string) error {
for _, s := range ss { for _, s := range ss {
nCurr, err := io.WriteString(w, s) nCurr, err := io.WriteString(w, s)
*n += int64(nCurr) *n += int64(nCurr)
@ -46,25 +27,37 @@ func writeTo(w io.Writer, n *int64, ss ...string) error {
return nil return nil
} }
type Attrib struct {
Key string
Value string
}
func (a Attrib) WriteTo(w io.Writer) (n int64, err error) { func (a Attrib) WriteTo(w io.Writer) (n int64, err error) {
err = writeTo(w, &n, a.Key) err = writeStringsTo(w, &n, a.Key)
if err != nil { if err != nil {
return return
} }
if a.Value != "" { if a.Value != "" {
err = writeTo(w, &n, "='", a.Value, "'") err = writeStringsTo(w, &n, "='", a.Value, "'")
} }
return return
} }
func (e *element) WriteTo(w io.Writer) (n int64, err error) { type EmptyElement struct {
err = writeTo(w, &n, "<", e.tagName) TagName string
Attribs []Attrib
}
func (EmptyElement) isHtml() {}
func (e EmptyElement) WriteTo(w io.Writer) (n int64, err error) {
err = writeStringsTo(w, &n, "<", e.TagName)
if err != nil { if err != nil {
return return
} }
for _, attrib := range e.attribs { for _, attrib := range e.Attribs {
err = writeTo(w, &n, " ") err = writeStringsTo(w, &n, " ")
if err != nil { if err != nil {
return return
} }
@ -77,13 +70,24 @@ func (e *element) WriteTo(w io.Writer) (n int64, err error) {
} }
} }
err = writeTo(w, &n, ">") err = writeStringsTo(w, &n, ">")
return
}
type ParentElement struct {
EmptyElement
Children []Html
}
func (e *ParentElement) isHtml() {}
func (e *ParentElement) WriteTo(w io.Writer) (n int64, err error) {
n, err = e.EmptyElement.WriteTo(w)
if err != nil { if err != nil {
return return
} }
if !e.empty { for _, child := range e.Children {
for _, child := range e.children {
var nCurr int64 var nCurr int64
nCurr, err = child.WriteTo(w) nCurr, err = child.WriteTo(w)
n += int64(nCurr) n += int64(nCurr)
@ -92,67 +96,48 @@ func (e *element) WriteTo(w io.Writer) (n int64, err error) {
} }
} }
err = writeTo(w, &n, "</", e.tagName, ">") err = writeStringsTo(w, &n, "</", e.TagName, ">")
}
return return
} }
func (*element) isHtml() {} type Text string
func emptyElement(tagName string, attribs []Attrib) Html { func (Text) isHtml() {}
return &element{
tagName: tagName,
attribs: attribs,
empty: true,
}
}
func elementFunc(tagName string, attribs []Attrib) func(...Html) Html { func (t Text) WriteTo(w io.Writer) (n int64, err error) {
return func(children ...Html) Html { err = writeStringsTo(w, &n, string(t))
return &element{
tagName: tagName,
attribs: attribs,
children: children,
empty: false,
}
}
}
type text string
func Text(s string) Html {
return text(s)
}
func (text) isHtml() {}
func (t text) WriteTo(w io.Writer) (n int64, err error) {
err = writeTo(w, &n, string(t))
return return
} }
type rText struct { type RText struct {
io.Reader io.Reader
} }
func RText(r io.Reader) Html { func (RText) isHtml() {}
return rText{Reader: r}
}
func (rText) isHtml() {} func (rt RText) WriteTo(w io.Writer) (n int64, err error) {
func (rt rText) WriteTo(w io.Writer) (n int64, err error) {
return io.Copy(w, rt.Reader) return io.Copy(w, rt.Reader)
} }
// Html5 functions // Html5 functions
func Div(attribs ...Attrib) func(children ...Html) Html { func Div(attribs ...Attrib) func(children ...Html) *ParentElement {
return elementFunc("div", attribs) return func(children ...Html) *ParentElement {
return &ParentElement{
EmptyElement: EmptyElement{
TagName: "div",
Attribs: attribs,
},
Children: children,
}
}
} }
func Img(attribs ...Attrib) Html { func Img(attribs ...Attrib) EmptyElement {
return emptyElement("img", attribs) return EmptyElement{
TagName: "img",
Attribs: attribs,
}
} }
func Id(id string) Attrib { func Id(id string) Attrib {
@ -168,16 +153,32 @@ func Disabled() Attrib {
} }
} }
func main() { // WriteDocument writes an HTML5 doctype declaration, followed by root.
// root should probably be an <html> element.
func WriteDocument(w io.Writer, root *ParentElement) (n int64, err error) {
err = writeStringsTo(w, &n, "<!DOCTYPE html>")
if err != nil {
return
}
var nroot int64
nroot, err = root.WriteTo(w)
n += nroot
return
}
func Main() {
var page = Div(Disabled(), Id("container"))( var page = Div(Disabled(), Id("container"))(
Img(Id("profile-photo")), Img(Id("profile-photo")),
Text("hello"), Text("hello"),
Img(Disabled()), Img(Disabled()),
RText(strings.NewReader("goodbye!")), RText{strings.NewReader("goodbye!")},
) )
n, err := page.WriteTo(os.Stdout) n, err := WriteDocument(os.Stdout, page)
fmt.Println() fmt.Println()
fmt.Println(n) fmt.Println(n)
if err != nil {
fmt.Println(err) fmt.Println(err)
} }
}