Commit d1a3edae authored by Rob Pike's avatar Rob Pike

effective_go: convert to use tmpltohtml.

Also update the big example to the new template system.
There are a number of other examples that should be
extracted; this CL serves as an introduction to the
approach.

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/4923043
parent 1446ffc2
...@@ -8,4 +8,11 @@ TARG=tmpltohtml ...@@ -8,4 +8,11 @@ TARG=tmpltohtml
GOFILES=\ GOFILES=\
tmpltohtml.go\ tmpltohtml.go\
go_tutorial.html: go_tutorial.tmpl tmpltohtml
makehtml go_tutorial.tmpl
effective_go.html: effective_go.tmpl tmpltohtml
makehtml effective_go.tmpl
include ../src/Make.cmd include ../src/Make.cmd
...@@ -793,7 +793,7 @@ func ReadFull(r Reader, buf []byte) (n int, err os.Error) { ...@@ -793,7 +793,7 @@ func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
var nr int var nr int
nr, err = r.Read(buf) nr, err = r.Read(buf)
n += nr n += nr
buf = buf[nr:len(buf)] buf = buf[nr:]
} }
return return
} }
...@@ -954,8 +954,9 @@ In Go terminology, it returns a pointer to a newly allocated zero value of type ...@@ -954,8 +954,9 @@ In Go terminology, it returns a pointer to a newly allocated zero value of type
</p> </p>
<p> <p>
Since the memory returned by <code>new</code> is zeroed, it's helpful to arrange that the Since the memory returned by <code>new</code> is zeroed, it's helpful to arrange
zeroed object can be used without further initialization. This means a user of when designing your data structures that the
zero value of each type can be used without further initialization. This means a user of
the data structure can create one with <code>new</code> and get right to the data structure can create one with <code>new</code> and get right to
work. work.
For example, the documentation for <code>bytes.Buffer</code> states that For example, the documentation for <code>bytes.Buffer</code> states that
...@@ -1075,8 +1076,9 @@ m := map[int]string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"} ...@@ -1075,8 +1076,9 @@ m := map[int]string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"}
Back to allocation. Back to allocation.
The built-in function <code>make(T, </code><i>args</i><code>)</code> serves The built-in function <code>make(T, </code><i>args</i><code>)</code> serves
a purpose different from <code>new(T)</code>. a purpose different from <code>new(T)</code>.
It creates slices, maps, and channels only, and it returns an initialized (not zero) It creates slices, maps, and channels only, and it returns an <em>initialized</em>
value of type <code>T</code>, not <code>*T</code>. (not <em>zeroed</em>)
value of type <code>T</code> (not <code>*T</code>).
The reason for the distinction The reason for the distinction
is that these three types are, under the covers, references to data structures that is that these three types are, under the covers, references to data structures that
must be initialized before use. must be initialized before use.
...@@ -2917,66 +2919,55 @@ for instance, a URL, saving you typing the URL into the phone's tiny keyboard. ...@@ -2917,66 +2919,55 @@ for instance, a URL, saving you typing the URL into the phone's tiny keyboard.
Here's the complete program. Here's the complete program.
An explanation follows. An explanation follows.
</p> </p>
<pre><!--{{code "progs/eff_qr.go"}}
<pre> -->package main
package main
import ( import (
"flag" &#34;flag&#34;
"http" &#34;http&#34;
"io" &#34;log&#34;
"log" &#34;template&#34;
"old/template" // New template package coming soon...
) )
var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18 var addr = flag.String(&#34;addr&#34;, &#34;:1718&#34;, &#34;http service address&#34;) // Q=17, R=18
var fmap = template.FormatterMap{
"html": template.HTMLFormatter, var templ = template.Must(template.New(&#34;qr&#34;).Parse(templateStr))
"url+html": UrlHtmlFormatter,
}
var templ = template.MustParse(templateStr, fmap)
func main() { func main() {
flag.Parse() flag.Parse()
http.Handle("/", http.HandlerFunc(QR)) http.Handle(&#34;/&#34;, http.HandlerFunc(QR))
err := http.ListenAndServe(*addr, nil) err := http.ListenAndServe(*addr, nil)
if err != nil { if err != nil {
log.Fatal("ListenAndServe:", err) log.Fatal(&#34;ListenAndServe:&#34;, err)
} }
} }
func QR(w http.ResponseWriter, req *http.Request) { func QR(w http.ResponseWriter, req *http.Request) {
templ.Execute(w, req.FormValue("s")) templ.Execute(w, req.FormValue(&#34;s&#34;))
} }
func UrlHtmlFormatter(w io.Writer, fmt string, v ...interface{}) {
template.HTMLEscape(w, []byte(http.URLEscape(v[0].(string))))
}
const templateStr = ` const templateStr = `
&lt;html&gt; &lt;html&gt;
&lt;head&gt; &lt;head&gt;
&lt;title&gt;QR Link Generator&lt;/title&gt; &lt;title&gt;QR Link Generator&lt;/title&gt;
&lt;/head&gt; &lt;/head&gt;
&lt;body&gt; &lt;body&gt;
{.section @} {{if .}}
&lt;img src="http://chart.apis.google.com/chart?chs=300x300&amp;cht=qr&amp;choe=UTF-8&amp;chl={@|url+html}" &lt;img src=&#34;http://chart.apis.google.com/chart?chs=300x300&amp;amp;cht=qr&amp;amp;choe=UTF-8&amp;amp;chl={{urlquery .}}&#34;
/&gt; /&gt;
&lt;br&gt; &lt;br&gt;
{@|html} {{html .}}
&lt;br&gt; &lt;br&gt;
&lt;br&gt; &lt;br&gt;
{.end} {{end}}
&lt;form action="/" name=f method="GET"&gt;&lt;input maxLength=1024 size=70 &lt;form action=&#34;/&#34; name=f method=&#34;GET&#34;&gt;&lt;input maxLength=1024 size=70
name=s value="" title="Text to QR Encode"&gt;&lt;input type=submit name=s value=&#34;&#34; title=&#34;Text to QR Encode&#34;&gt;&lt;input type=submit
value="Show QR" name=qr&gt; value=&#34;Show QR&#34; name=qr&gt;
&lt;/form&gt; &lt;/form&gt;
&lt;/body&gt; &lt;/body&gt;
&lt;/html&gt; &lt;/html&gt;
` `
</pre> </pre>
<p> <p>
The pieces up to <code>main</code> should be easy to follow. The pieces up to <code>main</code> should be easy to follow.
The one flag sets a default HTTP port for our server. The template The one flag sets a default HTTP port for our server. The template
...@@ -2995,25 +2986,20 @@ server; it blocks while the server runs. ...@@ -2995,25 +2986,20 @@ server; it blocks while the server runs.
executes the template on the data in the form value named <code>s</code>. executes the template on the data in the form value named <code>s</code>.
</p> </p>
<p> <p>
The template package, inspired by <a The template package is powerful;
href="http://code.google.com/p/json-template">json-template</a>, is
powerful;
this program just touches on its capabilities. this program just touches on its capabilities.
In essence, it rewrites a piece of text on the fly by substituting elements derived In essence, it rewrites a piece of text on the fly by substituting elements derived
from data items passed to <code>templ.Execute</code>, in this case the from data items passed to <code>templ.Execute</code>, in this case the
form value. form value.
Within the template text (<code>templateStr</code>), Within the template text (<code>templateStr</code>),
brace-delimited pieces denote template actions. double-brace-delimited pieces denote template actions.
The piece from the <code>{.section @}</code> The piece from the <code></code> executes only if the value of the current data item, called <code>.</code>,
to <code>{.end}</code> executes with the value of the data item <code>@</code>, is non-empty.
which is a shorthand for &ldquo;the current item&rdquo;, which is the form value. That is, when the string is empty, this piece of the template is suppressed.
(When the string is empty, this piece of the template is suppressed.)
</p> </p>
<p> <p>
The snippet <code>{@|url+html}</code> says to run the data through the formatter The snippet <code>0</code> says to process the data with the function
installed in the formatter map (<code>fmap</code>) <code>urlquery</code>, which sanitizes the query string
under the name <code>"url+html"</code>.
That is the function <code>UrlHtmlFormatter</code>, which sanitizes the string
for safe display on the web page. for safe display on the web page.
</p> </p>
<p> <p>
......
This diff is collapsed.
...@@ -14,4 +14,4 @@ then ...@@ -14,4 +14,4 @@ then
exit 1 exit 1
fi fi
make && ./tmpltohtml $TMPL > $HTML make tmpltohtml && ./tmpltohtml $TMPL > $HTML
package main
import (
"flag"
"http"
"log"
"template"
)
var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
var templ = template.Must(template.New("qr").Parse(templateStr))
func main() {
flag.Parse()
http.Handle("/", http.HandlerFunc(QR))
err := http.ListenAndServe(*addr, nil)
if err != nil {
log.Fatal("ListenAndServe:", err)
}
}
func QR(w http.ResponseWriter, req *http.Request) {
templ.Execute(w, req.FormValue("s"))
}
const templateStr = `
<html>
<head>
<title>QR Link Generator</title>
</head>
<body>
{{if .}}
<img src="http://chart.apis.google.com/chart?chs=300x300&amp;cht=qr&amp;choe=UTF-8&amp;chl={{urlquery .}}"
/>
<br>
{{html .}}
<br>
<br>
{{end}}
<form action="/" name=f method="GET"><input maxLength=1024 size=70
name=s value="" title="Text to QR Encode"><input type=submit
value="Show QR" name=qr>
</form>
</body>
</html>
`
...@@ -35,6 +35,7 @@ for i in \ ...@@ -35,6 +35,7 @@ for i in \
sieve1.go \ sieve1.go \
server1.go \ server1.go \
strings.go \ strings.go \
eff_qr.go \
; do ; do
$GC $i $GC $i
done done
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment