From 012557b3769f9286b9488fbfd4bddfeee66b6a55 Mon Sep 17 00:00:00 2001 From: Martin Möhrmann Date: Sun, 10 Apr 2016 08:48:55 +0200 Subject: all: replace magic 0x80 with named constant utf8.RuneSelf Change-Id: Id1c2e8e9d60588de866e8b6ca59cc83dd28f848f Reviewed-on: https://go-review.googlesource.com/21756 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/html/template/css.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/html') diff --git a/src/html/template/css.go b/src/html/template/css.go index 4c27cce85a..9154d8636d 100644 --- a/src/html/template/css.go +++ b/src/html/template/css.go @@ -243,7 +243,7 @@ func cssValueFilter(args ...interface{}) string { return filterFailsafe } default: - if c < 0x80 && isCSSNmchar(rune(c)) { + if c < utf8.RuneSelf && isCSSNmchar(rune(c)) { id = append(id, c) } } -- cgit v1.3 From a44c4256ae958b0aacecd5fd0b0e7f1156f8bcf4 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 10 Apr 2016 14:51:07 +0000 Subject: html: fix typo in UnescapeString string docs Fixes #15221 Change-Id: I9e927a2f604213338b4572f1a32d0247c58bdc60 Reviewed-on: https://go-review.googlesource.com/21798 Reviewed-by: Ian Lance Taylor --- src/html/escape.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/html') diff --git a/src/html/escape.go b/src/html/escape.go index 71906ac586..8dd1f4ad2f 100644 --- a/src/html/escape.go +++ b/src/html/escape.go @@ -181,7 +181,7 @@ func EscapeString(s string) string { // UnescapeString unescapes entities like "<" to become "<". It unescapes a // larger range of entities than EscapeString escapes. For example, "á" -// unescapes to "á", as does "á" and "&xE1;". +// unescapes to "á", as does "á" and "á". // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't // always true. func UnescapeString(s string) string { -- cgit v1.3 From 683917a72154e3409e1ab5ef5b26030388312d0b Mon Sep 17 00:00:00 2001 From: Dominik Honnef Date: Fri, 1 Apr 2016 07:34:18 +0200 Subject: all: use bytes.Equal, bytes.Contains and strings.Contains, again The previous cleanup was done with a buggy tool, missing some potential rewrites. Change-Id: I333467036e355f999a6a493e8de87e084f374e26 Reviewed-on: https://go-review.googlesource.com/21378 Reviewed-by: Brad Fitzpatrick --- src/cmd/go/go_test.go | 4 ++-- src/html/template/url.go | 2 +- src/net/http/serve_test.go | 2 +- src/path/filepath/path_test.go | 2 +- src/runtime/gcinfo_test.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/html') diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 411fd1e322..42efa9f312 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -1466,7 +1466,7 @@ func TestGoTestWithPackageListedMultipleTimes(t *testing.T) { defer tg.cleanup() tg.parallel() tg.run("test", "errors", "errors", "errors", "errors", "errors") - if strings.Index(strings.TrimSpace(tg.getStdout()), "\n") != -1 { + if strings.Contains(strings.TrimSpace(tg.getStdout()), "\n") { t.Error("go test errors errors errors errors errors tested the same package multiple times") } } @@ -1495,7 +1495,7 @@ func TestGoListCmdOnlyShowsCommands(t *testing.T) { tg.run("list", "cmd") out := strings.TrimSpace(tg.getStdout()) for _, line := range strings.Split(out, "\n") { - if strings.Index(line, "cmd/") == -1 { + if !strings.Contains(line, "cmd/") { t.Error("go list cmd shows non-commands") break } diff --git a/src/html/template/url.go b/src/html/template/url.go index 2ca76bf389..246bfd32cd 100644 --- a/src/html/template/url.go +++ b/src/html/template/url.go @@ -17,7 +17,7 @@ func urlFilter(args ...interface{}) string { if t == contentTypeURL { return s } - if i := strings.IndexRune(s, ':'); i >= 0 && strings.IndexRune(s[:i], '/') < 0 { + if i := strings.IndexRune(s, ':'); i >= 0 && !strings.ContainsRune(s[:i], '/') { protocol := strings.ToLower(s[:i]) if protocol != "http" && protocol != "https" && protocol != "mailto" { return "#" + filterFailsafe diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index 4cd6ed077f..e0094234de 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -4267,7 +4267,7 @@ func BenchmarkClient(b *testing.B) { if err != nil { b.Fatalf("ReadAll: %v", err) } - if bytes.Compare(body, data) != 0 { + if !bytes.Equal(body, data) { b.Fatalf("Got body: %q", body) } } diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go index 3622f9178e..1a4a9d2a1a 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -1015,7 +1015,7 @@ func TestAbs(t *testing.T) { vol := filepath.VolumeName(root) var extra []string for _, path := range absTests { - if strings.Index(path, "$") != -1 { + if strings.Contains(path, "$") { continue } path = vol + path diff --git a/src/runtime/gcinfo_test.go b/src/runtime/gcinfo_test.go index c1c2354bf9..9a61b4f2b2 100644 --- a/src/runtime/gcinfo_test.go +++ b/src/runtime/gcinfo_test.go @@ -59,7 +59,7 @@ func TestGCInfo(t *testing.T) { func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) { mask := runtime.GCMask(p) - if bytes.Compare(mask, mask0) != 0 { + if !bytes.Equal(mask, mask0) { t.Errorf("bad GC program for %v:\nwant %+v\ngot %+v", name, mask0, mask) return } -- cgit v1.3 From 3f66d8c84b4b3d685db1031954d3343a7a8c9d0f Mon Sep 17 00:00:00 2001 From: Emmanuel Odeke Date: Tue, 12 Apr 2016 01:55:14 -0700 Subject: html/template: add examples of loading templates from files Adds examples showing loading templates from files and executing them. Shows examples: - Using ParseGlob. - Using ParseFiles. - Using helper functions to share and use templates in different contexts by adding them to an existing bundle of templates. - Using a group of driver templates with distinct sets of helper templates. Almost all of the code was directly copied from text/template. Fixes #8500 Change-Id: Ic3d91d5232afc5a1cd2d8cd3d9a5f3b754c64225 Reviewed-on: https://go-review.googlesource.com/21854 Reviewed-by: Andrew Gerrand --- src/html/template/examplefiles_test.go | 226 +++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 src/html/template/examplefiles_test.go (limited to 'src/html') diff --git a/src/html/template/examplefiles_test.go b/src/html/template/examplefiles_test.go new file mode 100644 index 0000000000..60518aee9e --- /dev/null +++ b/src/html/template/examplefiles_test.go @@ -0,0 +1,226 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package template_test + +import ( + "io" + "io/ioutil" + "log" + "os" + "path/filepath" + "text/template" +) + +// templateFile defines the contents of a template to be stored in a file, for testing. +type templateFile struct { + name string + contents string +} + +func createTestDir(files []templateFile) string { + dir, err := ioutil.TempDir("", "template") + if err != nil { + log.Fatal(err) + } + for _, file := range files { + f, err := os.Create(filepath.Join(dir, file.name)) + if err != nil { + log.Fatal(err) + } + defer f.Close() + _, err = io.WriteString(f, file.contents) + if err != nil { + log.Fatal(err) + } + } + return dir +} + +// The following example is duplicated in text/template; keep them in sync. + +// Here we demonstrate loading a set of templates from a directory. +func ExampleTemplate_glob() { + // Here we create a temporary directory and populate it with our sample + // template definition files; usually the template files would already + // exist in some location known to the program. + dir := createTestDir([]templateFile{ + // T0.tmpl is a plain template file that just invokes T1. + {"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`}, + // T1.tmpl defines a template, T1 that invokes T2. + {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, + // T2.tmpl defines a template T2. + {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, + }) + // Clean up after the test; another quirk of running as an example. + defer os.RemoveAll(dir) + + // pattern is the glob pattern used to find all the template files. + pattern := filepath.Join(dir, "*.tmpl") + + // Here starts the example proper. + // T0.tmpl is the first name matched, so it becomes the starting template, + // the value returned by ParseGlob. + tmpl := template.Must(template.ParseGlob(pattern)) + + err := tmpl.Execute(os.Stdout, nil) + if err != nil { + log.Fatalf("template execution: %s", err) + } + // Output: + // T0 invokes T1: (T1 invokes T2: (This is T2)) +} + +// Here we demonstrate loading a set of templates from files in different directories +func ExampleTemplate_parsefiles() { + // Here we create different temporary directories and populate them with our sample + // template definition files; usually the template files would already + // exist in some location known to the program. + dir1 := createTestDir([]templateFile{ + // T1.tmpl is a plain template file that just invokes T2. + {"T1.tmpl", `T1 invokes T2: ({{template "T2"}})`}, + }) + + dir2 := createTestDir([]templateFile{ + // T2.tmpl defines a template T2. + {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, + }) + + // Clean up after the test; another quirk of running as an example. + defer func(dirs ...string) { + for _, dir := range dirs { + os.RemoveAll(dir) + } + }(dir1, dir2) + + // Here starts the example proper. + // Let's just parse only dir1/T0 and dir2/T2 + paths := []string{ + filepath.Join(dir1, "T1.tmpl"), + filepath.Join(dir2, "T2.tmpl"), + } + tmpl := template.Must(template.ParseFiles(paths...)) + + err := tmpl.Execute(os.Stdout, nil) + if err != nil { + log.Fatalf("template execution: %s", err) + } + // Output: + // T1 invokes T2: (This is T2) +} + +// The following example is duplicated in text/template; keep them in sync. + +// This example demonstrates one way to share some templates +// and use them in different contexts. In this variant we add multiple driver +// templates by hand to an existing bundle of templates. +func ExampleTemplate_helpers() { + // Here we create a temporary directory and populate it with our sample + // template definition files; usually the template files would already + // exist in some location known to the program. + dir := createTestDir([]templateFile{ + // T1.tmpl defines a template, T1 that invokes T2. + {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, + // T2.tmpl defines a template T2. + {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, + }) + // Clean up after the test; another quirk of running as an example. + defer os.RemoveAll(dir) + + // pattern is the glob pattern used to find all the template files. + pattern := filepath.Join(dir, "*.tmpl") + + // Here starts the example proper. + // Load the helpers. + templates := template.Must(template.ParseGlob(pattern)) + // Add one driver template to the bunch; we do this with an explicit template definition. + _, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}") + if err != nil { + log.Fatal("parsing driver1: ", err) + } + // Add another driver template. + _, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}") + if err != nil { + log.Fatal("parsing driver2: ", err) + } + // We load all the templates before execution. This package does not require + // that behavior but html/template's escaping does, so it's a good habit. + err = templates.ExecuteTemplate(os.Stdout, "driver1", nil) + if err != nil { + log.Fatalf("driver1 execution: %s", err) + } + err = templates.ExecuteTemplate(os.Stdout, "driver2", nil) + if err != nil { + log.Fatalf("driver2 execution: %s", err) + } + // Output: + // Driver 1 calls T1: (T1 invokes T2: (This is T2)) + // Driver 2 calls T2: (This is T2) +} + +// The following example is duplicated in text/template; keep them in sync. + +// This example demonstrates how to use one group of driver +// templates with distinct sets of helper templates. +func ExampleTemplate_share() { + // Here we create a temporary directory and populate it with our sample + // template definition files; usually the template files would already + // exist in some location known to the program. + dir := createTestDir([]templateFile{ + // T0.tmpl is a plain template file that just invokes T1. + {"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"}, + // T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined + {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, + }) + // Clean up after the test; another quirk of running as an example. + defer os.RemoveAll(dir) + + // pattern is the glob pattern used to find all the template files. + pattern := filepath.Join(dir, "*.tmpl") + + // Here starts the example proper. + // Load the drivers. + drivers := template.Must(template.ParseGlob(pattern)) + + // We must define an implementation of the T2 template. First we clone + // the drivers, then add a definition of T2 to the template name space. + + // 1. Clone the helper set to create a new name space from which to run them. + first, err := drivers.Clone() + if err != nil { + log.Fatal("cloning helpers: ", err) + } + // 2. Define T2, version A, and parse it. + _, err = first.Parse("{{define `T2`}}T2, version A{{end}}") + if err != nil { + log.Fatal("parsing T2: ", err) + } + + // Now repeat the whole thing, using a different version of T2. + // 1. Clone the drivers. + second, err := drivers.Clone() + if err != nil { + log.Fatal("cloning drivers: ", err) + } + // 2. Define T2, version B, and parse it. + _, err = second.Parse("{{define `T2`}}T2, version B{{end}}") + if err != nil { + log.Fatal("parsing T2: ", err) + } + + // Execute the templates in the reverse order to verify the + // first is unaffected by the second. + err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second") + if err != nil { + log.Fatalf("second execution: %s", err) + } + err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first") + if err != nil { + log.Fatalf("first: execution: %s", err) + } + + // Output: + // T0 (second version) invokes T1: (T1 invokes T2: (T2, version B)) + // T0 (first version) invokes T1: (T1 invokes T2: (T2, version A)) +} -- cgit v1.3 From 7085fb31dfb1a6b447a139064a4a692677284132 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Mon, 11 Apr 2016 11:14:53 +1000 Subject: html/template, text/template: clarify Parse{Files,Glob} semantics Document the subtle property that files with equivalent base names will overwrite extant templates with those same names. Fixes golang/go#14320 Change-Id: Ie9ace1b08e6896ea599836e31582123169aa7a25 Reviewed-on: https://go-review.googlesource.com/21824 Reviewed-by: Rob Pike --- src/html/template/template.go | 14 ++++++++++++++ src/text/template/helper.go | 14 ++++++++++++++ 2 files changed, 28 insertions(+) (limited to 'src/html') diff --git a/src/html/template/template.go b/src/html/template/template.go index 96ab268a7f..063e46d6bf 100644 --- a/src/html/template/template.go +++ b/src/html/template/template.go @@ -346,6 +346,11 @@ func Must(t *Template, err error) *Template { // the named files. The returned template's name will have the (base) name and // (parsed) contents of the first file. There must be at least one file. // If an error occurs, parsing stops and the returned *Template is nil. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. +// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template +// named "foo", while "a/foo" is unavailable. func ParseFiles(filenames ...string) (*Template, error) { return parseFiles(nil, filenames...) } @@ -353,6 +358,9 @@ func ParseFiles(filenames ...string) (*Template, error) { // ParseFiles parses the named files and associates the resulting templates with // t. If an error occurs, parsing stops and the returned template is nil; // otherwise it is t. There must be at least one file. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. func (t *Template) ParseFiles(filenames ...string) (*Template, error) { return parseFiles(t, filenames...) } @@ -399,6 +407,9 @@ func parseFiles(t *Template, filenames ...string) (*Template, error) { // returned template will have the (base) name and (parsed) contents of the // first file matched by the pattern. ParseGlob is equivalent to calling // ParseFiles with the list of files matched by the pattern. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. func ParseGlob(pattern string) (*Template, error) { return parseGlob(nil, pattern) } @@ -408,6 +419,9 @@ func ParseGlob(pattern string) (*Template, error) { // processed by filepath.Glob and must match at least one file. ParseGlob is // equivalent to calling t.ParseFiles with the list of files matched by the // pattern. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. func (t *Template) ParseGlob(pattern string) (*Template, error) { return parseGlob(t, pattern) } diff --git a/src/text/template/helper.go b/src/text/template/helper.go index 787ca62e5f..9e0200c352 100644 --- a/src/text/template/helper.go +++ b/src/text/template/helper.go @@ -29,6 +29,11 @@ func Must(t *Template, err error) *Template { // the named files. The returned template's name will have the base name and // parsed contents of the first file. There must be at least one file. // If an error occurs, parsing stops and the returned *Template is nil. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. +// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template +// named "foo", while "a/foo" is unavailable. func ParseFiles(filenames ...string) (*Template, error) { return parseFiles(nil, filenames...) } @@ -41,6 +46,9 @@ func ParseFiles(filenames ...string) (*Template, error) { // of the (base) names of the files. If it does not, depending on t's // contents before calling ParseFiles, t.Execute may fail. In that // case use t.ExecuteTemplate to execute a valid template. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. func (t *Template) ParseFiles(filenames ...string) (*Template, error) { t.init() return parseFiles(t, filenames...) @@ -88,6 +96,9 @@ func parseFiles(t *Template, filenames ...string) (*Template, error) { // returned template will have the (base) name and (parsed) contents of the // first file matched by the pattern. ParseGlob is equivalent to calling // ParseFiles with the list of files matched by the pattern. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. func ParseGlob(pattern string) (*Template, error) { return parseGlob(nil, pattern) } @@ -97,6 +108,9 @@ func ParseGlob(pattern string) (*Template, error) { // processed by filepath.Glob and must match at least one file. ParseGlob is // equivalent to calling t.ParseFiles with the list of files matched by the // pattern. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. func (t *Template) ParseGlob(pattern string) (*Template, error) { t.init() return parseGlob(t, pattern) -- cgit v1.3