From add4e167e3e32ca050a1986a877924d14e52fdc7 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Wed, 26 Jan 2011 14:56:52 +1000 Subject: [PATCH] doc/codelab/wiki: update to work with template changes, add to run.bash Fixes #1444. R=rsc, r CC=golang-dev https://golang.org/cl/3979045 --- doc/codelab/wiki/edit.html | 6 +- doc/codelab/wiki/final-noclosure.go | 22 ++--- doc/codelab/wiki/final-noerror.go | 18 ++-- doc/codelab/wiki/final-parsetemplate.go | 22 ++--- doc/codelab/wiki/final-template.go | 22 ++--- doc/codelab/wiki/final.go | 22 ++--- doc/codelab/wiki/htmlify.go | 2 +- doc/codelab/wiki/index.html | 117 ++++++++++++------------ doc/codelab/wiki/notemplate.go | 22 ++--- doc/codelab/wiki/part1-noerror.go | 20 ++-- doc/codelab/wiki/part1.go | 20 ++-- doc/codelab/wiki/part2.go | 18 ++-- doc/codelab/wiki/srcextract.go | 6 +- doc/codelab/wiki/test_edit.good | 2 +- doc/codelab/wiki/view.html | 6 +- doc/codelab/wiki/wiki.html | 56 ++++++------ src/run.bash | 3 + 17 files changed, 194 insertions(+), 190 deletions(-) diff --git a/doc/codelab/wiki/edit.html b/doc/codelab/wiki/edit.html index 71a919496f7..66dfeb511eb 100644 --- a/doc/codelab/wiki/edit.html +++ b/doc/codelab/wiki/edit.html @@ -1,6 +1,6 @@ -

Editing {title}

+

Editing {Title}

-
-
+ +
diff --git a/doc/codelab/wiki/final-noclosure.go b/doc/codelab/wiki/final-noclosure.go index 2f48565ca2b..99121f298b8 100644 --- a/doc/codelab/wiki/final-noclosure.go +++ b/doc/codelab/wiki/final-noclosure.go @@ -8,23 +8,23 @@ import ( "template" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } func viewHandler(w http.ResponseWriter, r *http.Request) { @@ -47,7 +47,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) { } p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } renderTemplate(w, "edit", p) } @@ -58,7 +58,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request) { return } body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} err = p.save() if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) @@ -67,7 +67,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/view/"+title, http.StatusFound) } -func renderTemplate(w http.ResponseWriter, tmpl string, p *page) { +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { t, err := template.ParseFile(tmpl+".html", nil) if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) diff --git a/doc/codelab/wiki/final-noerror.go b/doc/codelab/wiki/final-noerror.go index cf485226541..0f18912d2e6 100644 --- a/doc/codelab/wiki/final-noerror.go +++ b/doc/codelab/wiki/final-noerror.go @@ -7,23 +7,23 @@ import ( "template" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } const lenPath = len("/view/") @@ -32,7 +32,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } t, _ := template.ParseFile("edit.html", nil) t.Execute(p, w) diff --git a/doc/codelab/wiki/final-parsetemplate.go b/doc/codelab/wiki/final-parsetemplate.go index f02d116b2af..ea897760159 100644 --- a/doc/codelab/wiki/final-parsetemplate.go +++ b/doc/codelab/wiki/final-parsetemplate.go @@ -8,23 +8,23 @@ import ( "template" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } func viewHandler(w http.ResponseWriter, r *http.Request, title string) { @@ -39,14 +39,14 @@ func viewHandler(w http.ResponseWriter, r *http.Request, title string) { func editHandler(w http.ResponseWriter, r *http.Request, title string) { p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } renderTemplate(w, "edit", p) } func saveHandler(w http.ResponseWriter, r *http.Request, title string) { body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} err := p.save() if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) @@ -55,7 +55,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request, title string) { http.Redirect(w, r, "/view/"+title, http.StatusFound) } -func renderTemplate(w http.ResponseWriter, tmpl string, p *page) { +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { t, err := template.ParseFile(tmpl+".html", nil) if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) diff --git a/doc/codelab/wiki/final-template.go b/doc/codelab/wiki/final-template.go index 0bb133d3a15..4d6a2cfaba3 100644 --- a/doc/codelab/wiki/final-template.go +++ b/doc/codelab/wiki/final-template.go @@ -7,23 +7,23 @@ import ( "template" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } const lenPath = len("/view/") @@ -32,7 +32,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } renderTemplate(w, "edit", p) } @@ -46,12 +46,12 @@ func viewHandler(w http.ResponseWriter, r *http.Request) { func saveHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} p.save() http.Redirect(w, r, "/view/"+title, http.StatusFound) } -func renderTemplate(w http.ResponseWriter, tmpl string, p *page) { +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { t, _ := template.ParseFile(tmpl+".html", nil) t.Execute(p, w) } diff --git a/doc/codelab/wiki/final.go b/doc/codelab/wiki/final.go index 0c0206bc0c2..8ecd97d7484 100644 --- a/doc/codelab/wiki/final.go +++ b/doc/codelab/wiki/final.go @@ -8,23 +8,23 @@ import ( "template" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } func viewHandler(w http.ResponseWriter, r *http.Request, title string) { @@ -39,14 +39,14 @@ func viewHandler(w http.ResponseWriter, r *http.Request, title string) { func editHandler(w http.ResponseWriter, r *http.Request, title string) { p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } renderTemplate(w, "edit", p) } func saveHandler(w http.ResponseWriter, r *http.Request, title string) { body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} err := p.save() if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) @@ -63,7 +63,7 @@ func init() { } } -func renderTemplate(w http.ResponseWriter, tmpl string, p *page) { +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { err := templates[tmpl].Execute(p, w) if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) diff --git a/doc/codelab/wiki/htmlify.go b/doc/codelab/wiki/htmlify.go index 4a52e077f28..456d06fd525 100644 --- a/doc/codelab/wiki/htmlify.go +++ b/doc/codelab/wiki/htmlify.go @@ -8,5 +8,5 @@ import ( func main() { b, _ := ioutil.ReadAll(os.Stdin) - template.HTMLFormatter(os.Stdout, b, "") + template.HTMLFormatter(os.Stdout, "", b) } diff --git a/doc/codelab/wiki/index.html b/doc/codelab/wiki/index.html index c494a3cedcd..e4273de7a65 100644 --- a/doc/codelab/wiki/index.html +++ b/doc/codelab/wiki/index.html @@ -71,14 +71,14 @@ declaration.

Let's start by defining the data structures. A wiki consists of a series of interconnected pages, each of which has a title and a body (the page content). -Here, we define page as a struct with two fields representing +Here, we define Page as a struct with two fields representing the title and body.

-type page struct {
-	title	string
-	body	[]byte
+type Page struct {
+	Title	string
+	Body	[]byte
 }
 
@@ -86,33 +86,33 @@ type page struct { The type []byte means "a byte slice". (See Effective Go for more on slices.) -The body element is a []byte rather than +The Body element is a []byte rather than string because that is the type expected by the io libraries we will use, as you'll see below.

-The page struct describes how page data will be stored in memory. +The Page struct describes how page data will be stored in memory. But what about persistent storage? We can address that by creating a -save method on page: +save method on Page:

-func (p *page) save() os.Error {
-	filename := p.title + ".txt"
-	return ioutil.WriteFile(filename, p.body, 0600)
+func (p *Page) save() os.Error {
+	filename := p.Title + ".txt"
+	return ioutil.WriteFile(filename, p.Body, 0600)
 }
 

This method's signature reads: "This is a method named save that -takes as its receiver p, a pointer to page . It takes +takes as its receiver p, a pointer to Page . It takes no parameters, and returns a value of type os.Error."

-This method will save the page's body to a text -file. For simplicity, we will use the title as the file name. +This method will save the Page's Body to a text +file. For simplicity, we will use the Title as the file name.

@@ -120,7 +120,7 @@ The save method returns an os.Error value because that is the return type of WriteFile (a standard library function that writes a byte slice to a file). The save method returns the error value, to let the application handle it should anything go wrong while -writing the file. If all goes well, page.save() will return +writing the file. If all goes well, Page.save() will return nil (the zero-value for pointers, interfaces, and some other types).

@@ -137,17 +137,17 @@ We will want to load pages, too:

-func loadPage(title string) *page {
+func loadPage(title string) *Page {
 	filename := title + ".txt"
 	body, _ := ioutil.ReadFile(filename)
-	return &page{title: title, body: body}
+	return &Page{Title: title, Body: body}
 }
 

The function loadPage constructs the file name from -title, reads the file's contents into a new -page, and returns a pointer to that new page. +Title, reads the file's contents into a new +Page, and returns a pointer to that new page.

@@ -161,23 +161,23 @@ error return value (in essence, assigning the value to nothing).

But what happens if ReadFile encounters an error? For example, the file might not exist. We should not ignore such errors. Let's modify the -function to return *page and os.Error. +function to return *Page and os.Error.

-func loadPage(title string) (*page, os.Error) {
+func loadPage(title string) (*Page, os.Error) {
 	filename := title + ".txt"
 	body, err := ioutil.ReadFile(filename)
 	if err != nil {
 		return nil, err
 	}
-	return &page{title: title, body: body}, nil
+	return &Page{Title: title, Body: body}, nil
 }
 

Callers of this function can now check the second parameter; if it is -nil then it has successfully loaded a page. If not, it will be an +nil then it has successfully loaded a Page. If not, it will be an os.Error that can be handled by the caller (see the os package documentation for details). @@ -191,17 +191,17 @@ written:

 func main() {
-	p1 := &page{title: "TestPage", body: []byte("This is a sample page.")}
+	p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")}
 	p1.save()
 	p2, _ := loadPage("TestPage")
-	fmt.Println(string(p2.body))
+	fmt.Println(string(p2.Body))
 }
 

After compiling and executing this code, a file named TestPage.txt would be created, containing the contents of p1. The file would -then be read into the struct p2, and its body element +then be read into the struct p2, and its Body element printed to the screen.

@@ -317,7 +317,7 @@ const lenPath = len("/view/") func viewHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, _ := loadPage(title) - fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.title, p.body) + fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body) } @@ -377,7 +377,7 @@ href="http://localhost:8080/view/test">http://localhost:8080/view/test -

Editing pages

+

Editing Pages

A wiki is not a wiki without the ability to edit pages. Let's create two new @@ -401,7 +401,7 @@ func main() {

The function editHandler loads the page -(or, if it doesn't exist, create an empty page struct), +(or, if it doesn't exist, create an empty Page struct), and displays an HTML form.

@@ -410,14 +410,14 @@ func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } fmt.Fprintf(w, "<h1>Editing %s</h1>"+ "<form action=\"/save/%s\" method=\"POST\">"+ "<textarea name=\"body\">%s</textarea><br>"+ "<input type=\"submit\" value=\"Save\">"+ "</form>", - p.title, p.title, p.body) + p.Title, p.Title, p.Body) } @@ -454,10 +454,10 @@ Open a new file named edit.html, and add the following lines:

-<h1>Editing {title}</h1>
+<h1>Editing {Title}</h1>
 
-<form action="/save/{title}" method="POST">
-<div><textarea name="body" rows="20" cols="80">{body|html}</textarea></div>
+<form action="/save/{Title}" method="POST">
+<div><textarea name="Body" rows="20" cols="80">{Body|html}</textarea></div>
 <div><input type="submit" value="Save"></div>
 </form>
 
@@ -472,7 +472,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } t, _ := template.ParseFile("edit.html", nil) t.Execute(p, w) @@ -486,15 +486,15 @@ The function template.ParseFile will read the contents of

The method t.Execute replaces all occurrences of -{title} and {body} with the values of -p.title and p.body, and writes the resultant +{Title} and {Body} with the values of +p.Title and p.Body, and writes the resultant HTML to the http.ResponseWriter.

-Note that we've used {body|html} in the above template. +Note that we've used {Body|html} in the above template. The |html part asks the template engine to pass the value -body through the html formatter before outputting it, +Body through the html formatter before outputting it, which escapes HTML characters (such as replacing > with &gt;). This will prevent user data from corrupting the form HTML. @@ -511,11 +511,11 @@ While we're working with templates, let's create a template for our

-<h1>{title}</h1>
+<h1>{Title}</h1>
 
-<p>[<a href="/edit/{title}">edit</a>]</p>
+<p>[<a href="/edit/{Title}">edit</a>]</p>
 
-<div>{body}</div>
+<div>{Body}</div>
 

@@ -548,12 +548,12 @@ func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } renderTemplate(w, "edit", p) } -func renderTemplate(w http.ResponseWriter, tmpl string, p *page) { +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { t, _ := template.ParseFile(tmpl+".html", nil) t.Execute(p, w) } @@ -568,8 +568,8 @@ The handlers are now shorter and simpler.

What if you visit /view/APageThatDoesntExist? The program will crash. This is because it ignores the error return value from -loadPage. Instead, if the requested page doesn't exist, it should -redirect the client to the edit page so the content may be created: +loadPage. Instead, if the requested Page doesn't exist, it should +redirect the client to the edit Page so the content may be created:

@@ -589,7 +589,7 @@ The http.Redirect function adds an HTTP status code of
 header to the HTTP response.
 

-

Saving pages

+

Saving Pages

The function saveHandler will handle the form submission. @@ -599,7 +599,7 @@ The function saveHandler will handle the form submission. func saveHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} p.save() http.Redirect(w, r, "/view/"+title, http.StatusFound) } @@ -607,7 +607,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request) {

The page title (provided in the URL) and the form's only field, -body, are stored in a new page. +Body, are stored in a new Page. The save() method is then called to write the data to a file, and the client is redirected to the /view/ page.

@@ -615,7 +615,7 @@ and the client is redirected to the /view/ page.

The value returned by FormValue is of type string. We must convert that value to []byte before it will fit into -the page struct. We use []byte(body) to perform +the Page struct. We use []byte(body) to perform the conversion.

@@ -634,7 +634,7 @@ First, let's handle the errors in renderTemplate:

-func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
+func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
 	t, err := template.ParseFile(tmpl+".html", nil)
 	if err != nil {
 		http.Error(w, err.String(), http.StatusInternalServerError)
@@ -660,7 +660,7 @@ Now let's fix up saveHandler:
 
 func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
 	body := r.FormValue("body")
-	p := &page{title: title, body: []byte(body)}
+	p := &Page{Title: title, Body: []byte(body)}
 	err := p.save()
 	if err != nil {
 		http.Error(w, err.String(), http.StatusInternalServerError)
@@ -725,7 +725,7 @@ the Execute method on the appropriate Template from
 templates:
 
 
-func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
+func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
 	err := templates[tmpl].Execute(p, w)
 	if err != nil {
 		http.Error(w, err.String(), http.StatusInternalServerError)
@@ -747,7 +747,6 @@ Then we can create a global variable to store our validation regexp:
 

-var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
 

@@ -761,7 +760,7 @@ the expression compilation fails, while Compile returns an

Now, let's write a function that extracts the title string from the request -URL, and tests it against our titleValidator expression: +URL, and tests it against our TitleValidator expression:

@@ -807,7 +806,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) {
 	}
 	p, err := loadPage(title)
 	if err != nil {
-		p = &page{title: title}
+		p = &Page{Title: title}
 	}
 	renderTemplate(w, "edit", p)
 }
@@ -818,7 +817,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	body := r.FormValue("body")
-	p := &page{title: title, body: []byte(body)}
+	p := &Page{Title: title, Body: []byte(body)}
 	err = p.save()
 	if err != nil {
 		http.Error(w, err.String(), http.StatusInternalServerError)
@@ -895,7 +894,7 @@ The closure returned by makeHandler is a function that takes
 an http.ResponseWriter and http.Request (in other
 words, an http.HandlerFunc). 
 The closure extracts the title from the request path, and
-validates it with the titleValidator regexp. If the
+validates it with the TitleValidator regexp. If the
 title is invalid, an error will be written to the
 ResponseWriter using the http.NotFound function. 
 If the title is valid, the enclosed handler function
@@ -936,14 +935,14 @@ func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
 func editHandler(w http.ResponseWriter, r *http.Request, title string) {
 	p, err := loadPage(title)
 	if err != nil {
-		p = &page{title: title}
+		p = &Page{Title: title}
 	}
 	renderTemplate(w, "edit", p)
 }
 
 func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
 	body := r.FormValue("body")
-	p := &page{title: title, body: []byte(body)}
+	p := &Page{Title: title, Body: []byte(body)}
 	err := p.save()
 	if err != nil {
 		http.Error(w, err.String(), http.StatusInternalServerError)
diff --git a/doc/codelab/wiki/notemplate.go b/doc/codelab/wiki/notemplate.go
index c1f952c8382..9cbe9ad768e 100644
--- a/doc/codelab/wiki/notemplate.go
+++ b/doc/codelab/wiki/notemplate.go
@@ -7,23 +7,23 @@ import (
 	"os"
 )
 
-type page struct {
-	title string
-	body  []byte
+type Page struct {
+	Title string
+	Body  []byte
 }
 
-func (p *page) save() os.Error {
-	filename := p.title + ".txt"
-	return ioutil.WriteFile(filename, p.body, 0600)
+func (p *Page) save() os.Error {
+	filename := p.Title + ".txt"
+	return ioutil.WriteFile(filename, p.Body, 0600)
 }
 
-func loadPage(title string) (*page, os.Error) {
+func loadPage(title string) (*Page, os.Error) {
 	filename := title + ".txt"
 	body, err := ioutil.ReadFile(filename)
 	if err != nil {
 		return nil, err
 	}
-	return &page{title: title, body: body}, nil
+	return &Page{Title: title, Body: body}, nil
 }
 
 const lenPath = len("/view/")
@@ -31,21 +31,21 @@ const lenPath = len("/view/")
 func viewHandler(w http.ResponseWriter, r *http.Request) {
 	title := r.URL.Path[lenPath:]
 	p, _ := loadPage(title)
-	fmt.Fprintf(w, "

%s

%s
", p.title, p.body) + fmt.Fprintf(w, "

%s

%s
", p.Title, p.Body) } func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } fmt.Fprintf(w, "

Editing %s

"+ "
"+ "
"+ ""+ "
", - p.title, p.title, p.body) + p.Title, p.Title, p.Body) } func main() { diff --git a/doc/codelab/wiki/part1-noerror.go b/doc/codelab/wiki/part1-noerror.go index 39e8331e393..14cfc321a78 100644 --- a/doc/codelab/wiki/part1-noerror.go +++ b/doc/codelab/wiki/part1-noerror.go @@ -6,25 +6,25 @@ import ( "os" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) *page { +func loadPage(title string) *Page { filename := title + ".txt" body, _ := ioutil.ReadFile(filename) - return &page{title: title, body: body} + return &Page{Title: title, Body: body} } func main() { - p1 := &page{title: "TestPage", body: []byte("This is a sample page.")} + p1 := &Page{Title: "TestPage", Body: []byte("This is a sample page.")} p1.save() p2 := loadPage("TestPage") - fmt.Println(string(p2.body)) + fmt.Println(string(p2.Body)) } diff --git a/doc/codelab/wiki/part1.go b/doc/codelab/wiki/part1.go index f3678baa51f..4b0654f8b12 100644 --- a/doc/codelab/wiki/part1.go +++ b/doc/codelab/wiki/part1.go @@ -6,28 +6,28 @@ import ( "os" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } func main() { - p1 := &page{title: "TestPage", body: []byte("This is a sample page.")} + p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")} p1.save() p2, _ := loadPage("TestPage") - fmt.Println(string(p2.body)) + fmt.Println(string(p2.Body)) } diff --git a/doc/codelab/wiki/part2.go b/doc/codelab/wiki/part2.go index 8d4454a74ab..d57c3a01f1b 100644 --- a/doc/codelab/wiki/part2.go +++ b/doc/codelab/wiki/part2.go @@ -7,23 +7,23 @@ import ( "os" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } const lenPath = len("/view/") @@ -31,7 +31,7 @@ const lenPath = len("/view/") func viewHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, _ := loadPage(title) - fmt.Fprintf(w, "

%s

%s
", p.title, p.body) + fmt.Fprintf(w, "

%s

%s
", p.Title, p.Body) } func main() { diff --git a/doc/codelab/wiki/srcextract.go b/doc/codelab/wiki/srcextract.go index 0addc61c4e7..fdb7a5e1fcd 100644 --- a/doc/codelab/wiki/srcextract.go +++ b/doc/codelab/wiki/srcextract.go @@ -6,6 +6,7 @@ import ( "go/parser" "go/printer" "go/ast" + "go/token" "log" "os" ) @@ -25,7 +26,8 @@ func main() { os.Exit(2) } // load file - file, err := parser.ParseFile(*srcFn, nil, 0) + fs := token.NewFileSet() + file, err := parser.ParseFile(fs, *srcFn, nil, 0) if err != nil { log.Exit(err) } @@ -47,7 +49,7 @@ func main() { os.Exit(1) } b := new(bytes.Buffer) - p.Fprint(b, file) + p.Fprint(b, fs, file) // drop package declaration if !*showPkg { for { diff --git a/doc/codelab/wiki/test_edit.good b/doc/codelab/wiki/test_edit.good index 36c6dbb7322..e4edf8cb237 100644 --- a/doc/codelab/wiki/test_edit.good +++ b/doc/codelab/wiki/test_edit.good @@ -1,6 +1,6 @@

Editing Test

-
+
diff --git a/doc/codelab/wiki/view.html b/doc/codelab/wiki/view.html index a46622d01f4..ca2ffc20b64 100644 --- a/doc/codelab/wiki/view.html +++ b/doc/codelab/wiki/view.html @@ -1,5 +1,5 @@ -

{title}

+

{Title}

-

[edit]

+

[edit]

-
{body}
+
{Body}
diff --git a/doc/codelab/wiki/wiki.html b/doc/codelab/wiki/wiki.html index 919385edf35..ff2c3088b01 100644 --- a/doc/codelab/wiki/wiki.html +++ b/doc/codelab/wiki/wiki.html @@ -71,27 +71,27 @@ declaration.

Let's start by defining the data structures. A wiki consists of a series of interconnected pages, each of which has a title and a body (the page content). -Here, we define page as a struct with two fields representing +Here, we define Page as a struct with two fields representing the title and body.

-!./srcextract.bin -src=part1.go -name=page
+!./srcextract.bin -src=part1.go -name=Page
 

The type []byte means "a byte slice". (See Effective Go for more on slices.) -The body element is a []byte rather than +The Body element is a []byte rather than string because that is the type expected by the io libraries we will use, as you'll see below.

-The page struct describes how page data will be stored in memory. +The Page struct describes how page data will be stored in memory. But what about persistent storage? We can address that by creating a -save method on page: +save method on Page:

@@ -100,13 +100,13 @@ But what about persistent storage? We can address that by creating a
 
 

This method's signature reads: "This is a method named save that -takes as its receiver p, a pointer to page . It takes +takes as its receiver p, a pointer to Page . It takes no parameters, and returns a value of type os.Error."

-This method will save the page's body to a text -file. For simplicity, we will use the title as the file name. +This method will save the Page's Body to a text +file. For simplicity, we will use the Title as the file name.

@@ -114,7 +114,7 @@ The save method returns an os.Error value because that is the return type of WriteFile (a standard library function that writes a byte slice to a file). The save method returns the error value, to let the application handle it should anything go wrong while -writing the file. If all goes well, page.save() will return +writing the file. If all goes well, Page.save() will return nil (the zero-value for pointers, interfaces, and some other types).

@@ -136,8 +136,8 @@ We will want to load pages, too:

The function loadPage constructs the file name from -title, reads the file's contents into a new -page, and returns a pointer to that new page. +Title, reads the file's contents into a new +Page, and returns a pointer to that new page.

@@ -151,7 +151,7 @@ error return value (in essence, assigning the value to nothing).

But what happens if ReadFile encounters an error? For example, the file might not exist. We should not ignore such errors. Let's modify the -function to return *page and os.Error. +function to return *Page and os.Error.

@@ -160,7 +160,7 @@ function to return *page and os.Error.
 
 

Callers of this function can now check the second parameter; if it is -nil then it has successfully loaded a page. If not, it will be an +nil then it has successfully loaded a Page. If not, it will be an os.Error that can be handled by the caller (see the os package documentation for details). @@ -179,7 +179,7 @@ written:

After compiling and executing this code, a file named TestPage.txt would be created, containing the contents of p1. The file would -then be read into the struct p2, and its body element +then be read into the struct p2, and its Body element printed to the screen.

@@ -334,7 +334,7 @@ href="http://localhost:8080/view/test">http://localhost:8080/view/test -

Editing pages

+

Editing Pages

A wiki is not a wiki without the ability to edit pages. Let's create two new @@ -353,7 +353,7 @@ First, we add them to main():

The function editHandler loads the page -(or, if it doesn't exist, create an empty page struct), +(or, if it doesn't exist, create an empty Page struct), and displays an HTML form.

@@ -413,15 +413,15 @@ The function template.ParseFile will read the contents of

The method t.Execute replaces all occurrences of -{title} and {body} with the values of -p.title and p.body, and writes the resultant +{Title} and {Body} with the values of +p.Title and p.Body, and writes the resultant HTML to the http.ResponseWriter.

-Note that we've used {body|html} in the above template. +Note that we've used {Body|html} in the above template. The |html part asks the template engine to pass the value -body through the html formatter before outputting it, +Body through the html formatter before outputting it, which escapes HTML characters (such as replacing > with &gt;). This will prevent user data from corrupting the form HTML. @@ -472,8 +472,8 @@ The handlers are now shorter and simpler.

What if you visit /view/APageThatDoesntExist? The program will crash. This is because it ignores the error return value from -loadPage. Instead, if the requested page doesn't exist, it should -redirect the client to the edit page so the content may be created: +loadPage. Instead, if the requested Page doesn't exist, it should +redirect the client to the edit Page so the content may be created:

@@ -486,7 +486,7 @@ The http.Redirect function adds an HTTP status code of
 header to the HTTP response.
 

-

Saving pages

+

Saving Pages

The function saveHandler will handle the form submission. @@ -498,7 +498,7 @@ The function saveHandler will handle the form submission.

The page title (provided in the URL) and the form's only field, -body, are stored in a new page. +Body, are stored in a new Page. The save() method is then called to write the data to a file, and the client is redirected to the /view/ page.

@@ -506,7 +506,7 @@ and the client is redirected to the /view/ page.

The value returned by FormValue is of type string. We must convert that value to []byte before it will fit into -the page struct. We use []byte(body) to perform +the Page struct. We use []byte(body) to perform the conversion.

@@ -610,7 +610,7 @@ Then we can create a global variable to store our validation regexp:

-!./srcextract.bin -src=final-noclosure.go -name=titleValidator
+!./srcextract.bin -src=final-noclosure.go -name=TitleValidator
 

@@ -624,7 +624,7 @@ the expression compilation fails, while Compile returns an

Now, let's write a function that extracts the title string from the request -URL, and tests it against our titleValidator expression: +URL, and tests it against our TitleValidator expression:

@@ -708,7 +708,7 @@ The closure returned by makeHandler is a function that takes
 an http.ResponseWriter and http.Request (in other
 words, an http.HandlerFunc). 
 The closure extracts the title from the request path, and
-validates it with the titleValidator regexp. If the
+validates it with the TitleValidator regexp. If the
 title is invalid, an error will be written to the
 ResponseWriter using the http.NotFound function. 
 If the title is valid, the enclosed handler function
diff --git a/src/run.bash b/src/run.bash
index 0cd129253c2..9d7b02f9f95 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -103,6 +103,9 @@ if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then
 fi
 ) || exit $?
 
+(xcd ../doc/codelab/wiki
+gomake test) || exit $?
+
 for i in ../misc/dashboard/builder ../misc/goplay
 do
 	(xcd $i