Slightly redesigned types
This commit is contained in:
parent
b402a3b581
commit
8e2910490f
161
hatmill.go
161
hatmill.go
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package hatmill
|
||||
|
||||
import "fmt"
|
||||
import "io"
|
||||
@ -8,34 +8,15 @@ import "strings"
|
||||
// Html is either Element or Text
|
||||
type Html interface {
|
||||
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()
|
||||
}
|
||||
|
||||
func Reader() io.Reader {
|
||||
// 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
|
||||
// writeStringsTo attempts to write the strings in ss to w, incrementing n by the
|
||||
// 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 {
|
||||
nCurr, err := io.WriteString(w, s)
|
||||
*n += int64(nCurr)
|
||||
@ -46,25 +27,37 @@ func writeTo(w io.Writer, n *int64, ss ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type Attrib struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
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 {
|
||||
return
|
||||
}
|
||||
if a.Value != "" {
|
||||
err = writeTo(w, &n, "='", a.Value, "'")
|
||||
err = writeStringsTo(w, &n, "='", a.Value, "'")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (e *element) WriteTo(w io.Writer) (n int64, err error) {
|
||||
err = writeTo(w, &n, "<", e.tagName)
|
||||
type EmptyElement struct {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, attrib := range e.attribs {
|
||||
err = writeTo(w, &n, " ")
|
||||
for _, attrib := range e.Attribs {
|
||||
err = writeStringsTo(w, &n, " ")
|
||||
if err != nil {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
if !e.empty {
|
||||
for _, child := range e.children {
|
||||
for _, child := range e.Children {
|
||||
var nCurr int64
|
||||
nCurr, err = child.WriteTo(w)
|
||||
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
|
||||
}
|
||||
|
||||
func (*element) isHtml() {}
|
||||
type Text string
|
||||
|
||||
func emptyElement(tagName string, attribs []Attrib) Html {
|
||||
return &element{
|
||||
tagName: tagName,
|
||||
attribs: attribs,
|
||||
empty: true,
|
||||
}
|
||||
}
|
||||
func (Text) isHtml() {}
|
||||
|
||||
func elementFunc(tagName string, attribs []Attrib) func(...Html) Html {
|
||||
return func(children ...Html) Html {
|
||||
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))
|
||||
func (t Text) WriteTo(w io.Writer) (n int64, err error) {
|
||||
err = writeStringsTo(w, &n, string(t))
|
||||
return
|
||||
}
|
||||
|
||||
type rText struct {
|
||||
type RText struct {
|
||||
io.Reader
|
||||
}
|
||||
|
||||
func RText(r io.Reader) Html {
|
||||
return rText{Reader: r}
|
||||
}
|
||||
func (RText) isHtml() {}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// Html5 functions
|
||||
|
||||
func Div(attribs ...Attrib) func(children ...Html) Html {
|
||||
return elementFunc("div", attribs)
|
||||
func Div(attribs ...Attrib) func(children ...Html) *ParentElement {
|
||||
return func(children ...Html) *ParentElement {
|
||||
return &ParentElement{
|
||||
EmptyElement: EmptyElement{
|
||||
TagName: "div",
|
||||
Attribs: attribs,
|
||||
},
|
||||
Children: children,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Img(attribs ...Attrib) Html {
|
||||
return emptyElement("img", attribs)
|
||||
func Img(attribs ...Attrib) EmptyElement {
|
||||
return EmptyElement{
|
||||
TagName: "img",
|
||||
Attribs: attribs,
|
||||
}
|
||||
}
|
||||
|
||||
func Id(id string) Attrib {
|
||||
@ -163,21 +148,37 @@ func Id(id string) Attrib {
|
||||
}
|
||||
|
||||
func Disabled() Attrib {
|
||||
return Attrib {
|
||||
return Attrib{
|
||||
Key: "disabled",
|
||||
}
|
||||
}
|
||||
|
||||
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"))(
|
||||
Img(Id("profile-photo")),
|
||||
Text("hello"),
|
||||
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(n)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user