go.talks/pkg/present: access files through new Context type
R=adg
CC=golang-dev
https://golang.org/cl/7312072
diff --git a/pkg/present/code.go b/pkg/present/code.go
index e27c42b..6ab60ae 100644
--- a/pkg/present/code.go
+++ b/pkg/present/code.go
@@ -7,7 +7,6 @@
import (
"fmt"
"html/template"
- "io/ioutil"
"log"
"path/filepath"
"regexp"
@@ -42,7 +41,7 @@
var highlightRE = regexp.MustCompile(`\s+HL([a-zA-Z0-9_]+)?$`)
var codeRE = regexp.MustCompile(`\.(code|play)\s+([^\s]+)(\s+)?(.*)?$`)
-func parseCode(sourceFile string, sourceLine int, cmd string) (Elem, error) {
+func parseCode(ctx *Context, sourceFile string, sourceLine int, cmd string) (Elem, error) {
cmd = strings.TrimSpace(cmd)
// Pull off the HL, if any, from the end of the input line.
@@ -68,7 +67,7 @@
// Read in code file and (optionally) match address.
filename := filepath.Join(filepath.Dir(sourceFile), file)
- textBytes, err := ioutil.ReadFile(filename)
+ textBytes, err := ctx.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("%s:%d: %v", sourceFile, sourceLine, err)
}
@@ -168,8 +167,8 @@
}
// oneLine returns the single line generated by a two-argument code invocation.
-func oneLine(file, text string, arg interface{}) (line, before, after string, err error) {
- contentBytes, err := ioutil.ReadFile(file)
+func oneLine(ctx *Context, file, text string, arg interface{}) (line, before, after string, err error) {
+ contentBytes, err := ctx.ReadFile(file)
if err != nil {
return "", "", "", err
}
@@ -192,8 +191,8 @@
}
// multipleLines returns the text generated by a three-argument code invocation.
-func multipleLines(file string, arg1, arg2 interface{}) (line, before, after string, err error) {
- contentBytes, err := ioutil.ReadFile(file)
+func multipleLines(ctx *Context, file string, arg1, arg2 interface{}) (line, before, after string, err error) {
+ contentBytes, err := ctx.ReadFile(file)
lines := strings.SplitAfter(string(contentBytes), "\n")
if err != nil {
return "", "", "", err
diff --git a/pkg/present/html.go b/pkg/present/html.go
index 9fce270..cca90ef 100644
--- a/pkg/present/html.go
+++ b/pkg/present/html.go
@@ -3,7 +3,6 @@
import (
"errors"
"html/template"
- "io/ioutil"
"path/filepath"
"strings"
)
@@ -12,13 +11,13 @@
Register("html", parseHTML)
}
-func parseHTML(fileName string, lineno int, text string) (Elem, error) {
+func parseHTML(ctx *Context, fileName string, lineno int, text string) (Elem, error) {
p := strings.Fields(text)
if len(p) != 2 {
return nil, errors.New("invalid .html args")
}
name := filepath.Join(filepath.Dir(fileName), p[1])
- b, err := ioutil.ReadFile(name)
+ b, err := ctx.ReadFile(name)
if err != nil {
return nil, err
}
diff --git a/pkg/present/iframe.go b/pkg/present/iframe.go
index b9f0e78..2f3c5e5 100644
--- a/pkg/present/iframe.go
+++ b/pkg/present/iframe.go
@@ -21,7 +21,7 @@
func (i Iframe) TemplateName() string { return "iframe" }
-func parseIframe(fileName string, lineno int, text string) (Elem, error) {
+func parseIframe(ctx *Context, fileName string, lineno int, text string) (Elem, error) {
args := strings.Fields(text)
i := Iframe{URL: args[1]}
a, err := parseArgs(fileName, lineno, args[2:])
diff --git a/pkg/present/image.go b/pkg/present/image.go
index ec859ce..2bab429 100644
--- a/pkg/present/image.go
+++ b/pkg/present/image.go
@@ -21,7 +21,7 @@
func (i Image) TemplateName() string { return "image" }
-func parseImage(fileName string, lineno int, text string) (Elem, error) {
+func parseImage(ctx *Context, fileName string, lineno int, text string) (Elem, error) {
args := strings.Fields(text)
img := Image{URL: args[1]}
a, err := parseArgs(fileName, lineno, args[2:])
diff --git a/pkg/present/link.go b/pkg/present/link.go
index 1e00ef1..d683f02 100644
--- a/pkg/present/link.go
+++ b/pkg/present/link.go
@@ -21,7 +21,7 @@
func (l Link) TemplateName() string { return "link" }
-func parseLink(fileName string, lineno int, text string) (Elem, error) {
+func parseLink(ctx *Context, fileName string, lineno int, text string) (Elem, error) {
args := strings.Fields(text)
url, err := url.Parse(args[1])
if err != nil {
diff --git a/pkg/present/parse.go b/pkg/present/parse.go
index 80ed34f..05091a7 100644
--- a/pkg/present/parse.go
+++ b/pkg/present/parse.go
@@ -21,7 +21,7 @@
)
var (
- parsers = make(map[string]func(string, int, string) (Elem, error))
+ parsers = make(map[string]ParseFunc)
funcs = template.FuncMap{}
)
@@ -40,7 +40,7 @@
return t.ExecuteTemplate(w, "root", data)
}
-type ParseFunc func(fileName string, lineNumber int, inputLine string) (Elem, error)
+type ParseFunc func(ctx *Context, fileName string, lineNumber int, inputLine string) (Elem, error)
// Register binds the named action, which does not begin with a period, to the
// specified parser to be invoked when the name, with a period, appears in the
@@ -212,6 +212,12 @@
return
}
+// A Context specifies the supporting context for parsing a presentation.
+type Context struct {
+ // ReadFile reads the file named by filename and returns the contents.
+ ReadFile func(filename string) ([]byte, error)
+}
+
// ParseMode represents flags for the Parse function.
type ParseMode int
@@ -220,8 +226,8 @@
TitlesOnly ParseMode = 1
)
-// Parse parses the document in the file specified by name.
-func Parse(r io.Reader, name string, mode ParseMode) (*Doc, error) {
+// Parse parses a document from r.
+func (ctx *Context) Parse(r io.Reader, name string, mode ParseMode) (*Doc, error) {
doc := new(Doc)
lines, err := readLines(r)
if err != nil {
@@ -239,12 +245,19 @@
return nil, err
}
// Sections
- if doc.Sections, err = parseSections(name, lines, []int{}, doc); err != nil {
+ if doc.Sections, err = parseSections(ctx, name, lines, []int{}, doc); err != nil {
return nil, err
}
return doc, nil
}
+// Parse parses a document from r. Parse reads assets used by the presentation
+// from the file system using ioutil.ReadFile.
+func Parse(r io.Reader, name string, mode ParseMode) (*Doc, error) {
+ ctx := Context{ReadFile: ioutil.ReadFile}
+ return ctx.Parse(r, name, mode)
+}
+
// isHeading matches any section heading.
var isHeading = regexp.MustCompile(`^\*+ `)
@@ -256,7 +269,7 @@
// parseSections parses Sections from lines for the section level indicated by
// number (a nil number indicates the top level).
-func parseSections(name string, lines *Lines, number []int, doc *Doc) ([]Section, error) {
+func parseSections(ctx *Context, name string, lines *Lines, number []int, doc *Doc) ([]Section, error) {
var sections []Section
for i := 1; ; i++ {
// Next non-empty line is title.
@@ -312,7 +325,7 @@
e = List{Bullet: b}
case strings.HasPrefix(text, prefix+"* "):
lines.back()
- subsecs, err := parseSections(name, lines, section.Number, doc)
+ subsecs, err := parseSections(ctx, name, lines, section.Number, doc)
if err != nil {
return nil, err
}
@@ -325,7 +338,7 @@
if parser == nil {
return nil, fmt.Errorf("%s:%d: unknown command %q\n", name, lines.line, text)
}
- t, err := parser(name, lines.line, text)
+ t, err := parser(ctx, name, lines.line, text)
if err != nil {
return nil, err
}