From add4e167e3e32ca050a1986a877924d14e52fdc7 Mon Sep 17 00:00:00 2001
From: Andrew Gerrand
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 Editing {title}
+Editing {Title}
-
diff --git a/doc/codelab/wiki/final-noclosure.go b/doc/codelab/wiki/final-noclosure.go
index 2f48565ca2..99121f298b 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 cf48522654..0f18912d2e 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 f02d116b2a..ea89776015 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 0bb133d3a1..4d6a2cfaba 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 0c0206bc0c..8ecd97d748 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 4a52e077f2..456d06fd52 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 c494a3cedc..e4273de7a6 100644
--- a/doc/codelab/wiki/index.html
+++ b/doc/codelab/wiki/index.html
@@ -71,14 +71,14 @@ declaration.
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).
-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.
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.
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
>).
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", - 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 39e8331e39..14cfc321a7 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 f3678baa51..4b0654f8b1 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 8d4454a74a..d57c3a01f1 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, "http.Redirectfunction adds an HTTP status code of header to the HTTP response. -Saving pages
+Saving Pages
The function
saveHandlerwill handle the form submission. @@ -599,7 +599,7 @@ The functionsaveHandlerwill 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, -
@@ -615,7 +615,7 @@ and the client is redirected to thebody, are stored in a newpage. +Body, are stored in a newPage. Thesave()method is then called to write the data to a file, and the client is redirected to the/view/page./view/page.The value returned by
@@ -634,7 +634,7 @@ First, let's handle the errors inFormValueis of typestring. We must convert that value to[]bytebefore it will fit into -thepagestruct. We use[]byte(body)to perform +thePagestruct. We use[]byte(body)to perform the conversion.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 upsaveHandler: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 @@ theExecutemethod on the appropriateTemplatefromtemplates:-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
Compilereturns anNow, let's write a function that extracts the title string from the request -URL, and tests it against our
titleValidatorexpression: +URL, and tests it against ourTitleValidatorexpression:@@ -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 bymakeHandleris a function that takes anhttp.ResponseWriterandhttp.Request(in other words, anhttp.HandlerFunc). The closure extracts thetitlefrom the request path, and -validates it with thetitleValidatorregexp. If the +validates it with theTitleValidatorregexp. If thetitleis invalid, an error will be written to theResponseWriterusing thehttp.NotFoundfunction. If thetitleis 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 c1f952c838..9cbe9ad768 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
"+ "
[edit]
+[edit]
-
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 aThis method's signature reads: "This is a method named
savethat -takes as its receiverp, a pointer topage. It takes +takes as its receiverp, a pointer toPage. It takes no parameters, and returns a value of typeos.Error."-This method will save the
page'sbodyto a text -file. For simplicity, we will use thetitleas the file name. +This method will save thePage'sBodyto a text +file. For simplicity, we will use theTitleas the file name.@@ -114,7 +114,7 @@ The
@@ -136,8 +136,8 @@ We will want to load pages, too:savemethod returns anos.Errorvalue because that is the return type ofWriteFile(a standard library function that writes a byte slice to a file). Thesavemethod 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 returnnil(the zero-value for pointers, interfaces, and some other types).The function
loadPageconstructs the file name from -title, reads the file's contents into a new -page, and returns a pointer to that newpage. +Title, reads the file's contents into a new +Page, and returns a pointer to that newpage.@@ -151,7 +151,7 @@ error return value (in essence, assigning the value to nothing).
But what happens if
ReadFileencounters an error? For example, the file might not exist. We should not ignore such errors. Let's modify the -function to return*pageandos.Error. +function to return*Pageandos.Error.@@ -160,7 +160,7 @@ function to return*pageandos.Error.Callers of this function can now check the second parameter; if it is -
nilthen it has successfully loaded a page. If not, it will be an +nilthen it has successfully loaded a Page. If not, it will be anos.Errorthat 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
@@ -334,7 +334,7 @@ href="http://localhost:8080/view/test">http://localhost:8080/view/test -TestPage.txtwould be created, containing the contents ofp1. The file would -then be read into the structp2, and itsbodyelement +then be read into the structp2, and itsBodyelement printed to the screen.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
@@ -413,15 +413,15 @@ The functioneditHandlerloads the page -(or, if it doesn't exist, create an emptypagestruct), +(or, if it doesn't exist, create an emptyPagestruct), and displays an HTML form.template.ParseFilewill read the contents ofThe method
t.Executereplaces all occurrences of -{title}and{body}with the values of -p.titleandp.body, and writes the resultant +{Title}and{Body}with the values of +p.Titleandp.Body, and writes the resultant HTML to thehttp.ResponseWriter.-Note that we've used
{body|html}in the above template. +Note that we've used{Body|html}in the above template. The|htmlpart asks the template engine to pass the value -bodythrough thehtmlformatter before outputting it, +Bodythrough thehtmlformatter before outputting it, which escapes HTML characters (such as replacing>with>). 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 @@ Thehttp.Redirectfunction adds an HTTP status code of header to the HTTP response. -Saving pages
+Saving Pages
The function
saveHandlerwill handle the form submission. @@ -498,7 +498,7 @@ The functionsaveHandlerwill handle the form submission.The page title (provided in the URL) and the form's only field, -
@@ -506,7 +506,7 @@ and the client is redirected to thebody, are stored in a newpage. +Body, are stored in a newPage. Thesave()method is then called to write the data to a file, and the client is redirected to the/view/page./view/page.The value returned by
@@ -610,7 +610,7 @@ Then we can create a global variable to store our validation regexp:FormValueis of typestring. We must convert that value to[]bytebefore it will fit into -thepagestruct. We use[]byte(body)to perform +thePagestruct. We use[]byte(body)to perform the conversion.-!./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
Compilereturns anNow, let's write a function that extracts the title string from the request -URL, and tests it against our
titleValidatorexpression: +URL, and tests it against ourTitleValidatorexpression:@@ -708,7 +708,7 @@ The closure returned bymakeHandleris a function that takes anhttp.ResponseWriterandhttp.Request(in other words, anhttp.HandlerFunc). The closure extracts thetitlefrom the request path, and -validates it with thetitleValidatorregexp. If the +validates it with theTitleValidatorregexp. If thetitleis invalid, an error will be written to theResponseWriterusing thehttp.NotFoundfunction. If thetitleis valid, the enclosed handler function diff --git a/src/run.bash b/src/run.bash index 0cd129253c..9d7b02f9f9 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 -- 2.52.0