From 758ff64c69e34965f8af5b2d6ffd65e8d7ab2150 Mon Sep 17 00:00:00 2001 From: Ondřej Surý Date: Mon, 14 Feb 2011 13:23:51 +0100 Subject: Imported Upstream version 2011-02-01.1 --- doc/codelab/wiki/index.html | 117 ++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 59 deletions(-) (limited to 'doc/codelab/wiki/index.html') diff --git a/doc/codelab/wiki/index.html b/doc/codelab/wiki/index.html index c494a3ced..fe99c32d1 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)
-- 
cgit v1.2.3