Skip to content

Instantly share code, notes, and snippets.

@nf
Created November 2, 2012 13:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nf/4001362 to your computer and use it in GitHub Desktop.
Save nf/4001362 to your computer and use it in GitHub Desktop.
script to convert go tour html to present file format
package main
import (
"bytes"
"exp/html"
"fmt"
"io/ioutil"
"log"
"os"
"regexp"
"strings"
)
func main() {
root, err := html.Parse(os.Stdin)
if err != nil {
log.Fatal(err)
}
f, err := os.Create("tour.article")
if err != nil {
log.Fatal(err)
}
defer f.Close()
fmt.Fprintln(f, header)
for n, s := range findAll(root, hasClass("slide")) {
title := text(find(s, isTag("h2")))
fmt.Fprintf(f, "* %v\n\n", title)
fmt.Fprint(f, slideText(s))
source := text(find(s, hasClass("source")))
if source != "" {
fn := "tour/" + filename(n, title)
ioutil.WriteFile(fn, []byte(source), 0666)
fmt.Fprintf(f, ".play %s\n\n", fn)
}
}
}
const header = `
A Tour of Go
The Go Authors
http://golang.org
`
var nonSafe = regexp.MustCompile(`[^a-z ]`)
func filename(n int, title string) string {
title = strings.ToLower(title)
title = nonSafe.ReplaceAllString(title, "")
title = strings.TrimSpace(title)
title = strings.Replace(title, " ", "-", -1)
return fmt.Sprintf("%03d-%s.go", n, title)
}
func slideText(s *html.Node) string {
var buf bytes.Buffer
walk(s, func(n *html.Node) bool {
switch {
case isTag("p")(n):
buf.WriteString(wrap(text(n)))
case isTag("pre")(n) && !hasClass("source")(n):
buf.WriteString(indent(text(n)))
buf.WriteByte('\n')
default:
return true
}
return false
})
return buf.String()
}
func indent(s string) string {
var buf bytes.Buffer
for _, l := range strings.Split(s, "\n") {
buf.WriteByte('\t')
buf.WriteString(l)
buf.WriteByte('\n')
}
return buf.String()
}
func wrap(s string) string {
var buf bytes.Buffer
var cont bool
for _, l := range strings.Split(s, "\n") {
l = strings.TrimSpace(l)
if len(l) == 0 {
if cont {
buf.WriteByte('\n')
buf.WriteByte('\n')
}
cont = false
} else {
if cont {
buf.WriteByte(' ')
}
buf.WriteString(l)
cont = true
}
}
return buf.String()
}
func text(n *html.Node) string {
var buf bytes.Buffer
walk(n, func(n *html.Node) bool {
if hasClass("appengineMode")(n) {
return false
}
if n.Type == html.TextNode {
buf.WriteString(n.Data)
}
return true
})
return buf.String()
}
type selector func(*html.Node) bool
func isTag(name string) selector {
return func(n *html.Node) bool {
return n.DataAtom.String() == name
}
}
func hasClass(name string) selector {
return func(n *html.Node) bool {
for _, a := range n.Attr {
if a.Key == "class" {
for _, c := range strings.Fields(a.Val) {
if c == name {
return true
}
}
}
}
return false
}
}
func findAll(node *html.Node, fn selector) (nodes []*html.Node) {
walk(node, func(n *html.Node) bool {
if fn(n) {
nodes = append(nodes, n)
}
return true
})
return
}
func find(n *html.Node, fn selector) *html.Node {
var result *html.Node
walk(n, func(n *html.Node) bool {
if result != nil {
return false
}
if fn(n) {
result = n
return false
}
return true
})
return result
}
func walk(n *html.Node, fn selector) {
var w func(*html.Node, bool)
w = func(n *html.Node, first bool) {
if n == nil {
return
}
if fn(n) {
w(n.FirstChild, false)
}
if !first {
w(n.NextSibling, false)
}
return
}
w(n, true)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment