Here is an example of an example:
- // The output of this example function.
func ExamplePrintln() {
Println("The output of this example function.")
+ // Output: The output of this example function.
}
The entire test file is presented as the example when it contains a single
case isTest(name, "Benchmark"):
t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
*seen = true
- case isTest(name, "Example"):
- output := n.Doc.Text()
- if output == "" {
- // Don't run examples with no output.
- continue
- }
- t.Examples = append(t.Examples, testFunc{pkg, name, output})
- *seen = true
}
}
-
+ for _, e := range ast.Examples(f) {
+ if e.Output == "" {
+ // Don't run examples with no output.
+ continue
+ }
+ t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output})
+ *seen = true
+ }
return nil
}
return unicode.IsUpper(r)
}
-func example_htmlFunc(funcName string, examples []*doc.Example, fset *token.FileSet) string {
+var exampleOutputRx = regexp.MustCompile(`(?i)//[[:space:]]*output:`)
+
+func example_htmlFunc(funcName string, examples []*ast.Example, fset *token.FileSet) string {
var buf bytes.Buffer
for _, eg := range examples {
name := eg.Name
}
// print code
- code := node_htmlFunc(eg.Body, fset)
+ cnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments}
+ code := node_htmlFunc(cnode, fset)
+ out := eg.Output
+
+ // additional formatting if this is a function body
if len(code) > 0 && code[0] == '{' {
- // unindent and remove surrounding braces
+ // unindent
code = strings.Replace(code, "\n ", "\n", -1)
+ // remove surrounding braces
code = code[2 : len(code)-2]
+ // remove output comment
+ if loc := exampleOutputRx.FindStringIndex(code); loc != nil {
+ code = strings.TrimSpace(code[:loc[0]])
+ }
+ } else {
+ // drop output, as the output comment will appear in the code
+ out = ""
}
err := exampleHTML.Execute(&buf, struct {
Name, Code, Output string
- }{eg.Name, code, eg.Output})
+ }{eg.Name, code, out})
if err != nil {
log.Print(err)
}
func example_suffixFunc(name string) string {
_, suffix := splitExampleName(name)
return suffix
-
}
func splitExampleName(s string) (name, suffix string) {
FSet *token.FileSet // corresponding file set
PAst *ast.File // nil if no single AST with package exports
PDoc *doc.Package // nil if no single package documentation
- Examples []*doc.Example // nil if no example code
+ Examples []*ast.Example // nil if no example code
Dirs *DirList // nil if no directory information
DirTime time.Time // directory time stamp
DirFlat bool // if set, show directory in a flat (non-indented) manner
}
// get examples from *_test.go files
- var examples []*doc.Example
+ var examples []*ast.Example
filter = func(d os.FileInfo) bool {
return isGoFile(d) && strings.HasSuffix(d.Name(), "_test.go")
}
log.Println("parsing test files:", err)
} else {
for _, testpkg := range testpkgs {
- examples = append(examples, doc.Examples(testpkg)...)
+ var files []*ast.File
+ for _, f := range testpkg.Files {
+ files = append(files, f)
+ }
+ examples = append(examples, ast.Examples(files...)...)
}
}
"os"
)
-// Hello world!
func ExampleBuffer() {
var b Buffer // A Buffer needs no initialization.
b.Write([]byte("Hello "))
b.Write([]byte("world!"))
b.WriteTo(os.Stdout)
+ // Output: Hello world!
}
-// Gophers rule!
func ExampleBuffer_reader() {
// A Buffer can turn a string or a []byte into an io.Reader.
buf := NewBufferString("R29waGVycyBydWxlIQ==")
dec := base64.NewDecoder(base64.StdEncoding, buf)
io.Copy(os.Stdout, dec)
+ // Output: Gophers rule!
}
return item
}
-// 99:seven 88:five 77:zero 66:nine 55:three 44:two 33:six 22:one 11:four 00:eight
+// update is not used by the example but shows how to take the top item from
+// the queue, update its priority and value, and put it back.
+func (pq *PriorityQueue) update(value string, priority int) {
+ item := heap.Pop(pq).(*Item)
+ item.value = value
+ item.priority = priority
+ heap.Push(pq, item)
+}
+
+// changePriority is not used by the example but shows how to change the
+// priority of an arbitrary item.
+func (pq *PriorityQueue) changePriority(item *Item, priority int) {
+ heap.Remove(pq, item.index)
+ item.priority = priority
+ heap.Push(pq, item)
+}
+
+// This example pushes 10 items into a PriorityQueue and takes them out in
+// order of priority.
func Example() {
const nItem = 10
// Random priorities for the items (a permutation of 0..9, times 11)).
item := heap.Pop(&pq).(*Item)
fmt.Printf("%.2d:%s ", item.priority, item.value)
}
-}
-
-// update is not used by the example but shows how to take the top item from the queue,
-// update its priority and value, and put it back.
-func (pq *PriorityQueue) update(value string, priority int) {
- item := heap.Pop(pq).(*Item)
- item.value = value
- item.priority = priority
- heap.Push(pq, item)
-}
-
-// changePriority is not used by the example but shows how to change the priority of an arbitrary
-// item.
-func (pq *PriorityQueue) changePriority(item *Item, priority int) {
- heap.Remove(pq, item.index)
- item.priority = priority
- heap.Push(pq, item)
+ // Output:
+ // 99:seven 88:five 77:zero 66:nine 55:three 44:two 33:six 22:one 11:four 00:eight
}
"math"
)
-// 18 2d 44 54 fb 21 09 40
func ExampleWrite() {
buf := new(bytes.Buffer)
var pi float64 = math.Pi
fmt.Println("binary.Write failed:", err)
}
fmt.Printf("% x", buf.Bytes())
+ // Output: 18 2d 44 54 fb 21 09 40
}
-// cafebabe
func ExampleWrite_multi() {
buf := new(bytes.Buffer)
var data = []interface{}{
}
}
fmt.Printf("%x", buf.Bytes())
+ // Output: cafebabe
}
-// 3.141592653589793
func ExampleRead() {
var pi float64
b := []byte{0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40}
fmt.Println("binary.Read failed:", err)
}
fmt.Print(pi)
+ // Output: 3.141592653589793
}
"os"
)
-// {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
func ExampleMarshal() {
type ColorGroup struct {
ID int
fmt.Println("error:", err)
}
os.Stdout.Write(b)
+ // Output:
+ // {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
}
-// [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
func ExampleUnmarshal() {
var jsonBlob = []byte(`[
{"Name": "Platypus", "Order": "Monotremata"},
fmt.Println("error:", err)
}
fmt.Printf("%+v", animals)
+ // Output:
+ // [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Extract example functions from package ASTs.
+// Extract example functions from file ASTs.
-package doc
+package ast
import (
- "go/ast"
- "go/printer"
"go/token"
+ "regexp"
"strings"
"unicode"
"unicode/utf8"
)
type Example struct {
- Name string // name of the item being demonstrated
- Body *printer.CommentedNode // code
- Output string // expected output
+ Name string // name of the item being exemplified
+ Code Node
+ Comments []*CommentGroup
+ Output string // expected output
}
-func Examples(pkg *ast.Package) []*Example {
+func Examples(files ...*File) []*Example {
var list []*Example
- for _, file := range pkg.Files {
+ for _, file := range files {
hasTests := false // file contains tests or benchmarks
numDecl := 0 // number of non-import declarations in the file
var flist []*Example
for _, decl := range file.Decls {
- if g, ok := decl.(*ast.GenDecl); ok && g.Tok != token.IMPORT {
+ if g, ok := decl.(*GenDecl); ok && g.Tok != token.IMPORT {
numDecl++
continue
}
- f, ok := decl.(*ast.FuncDecl)
+ f, ok := decl.(*FuncDecl)
if !ok {
continue
}
continue
}
flist = append(flist, &Example{
- Name: name[len("Example"):],
- Body: &printer.CommentedNode{
- Node: f.Body,
- Comments: file.Comments,
- },
- Output: f.Doc.Text(),
+ Name: name[len("Example"):],
+ Code: f.Body,
+ Comments: file.Comments,
+ Output: exampleOutput(f, file.Comments),
})
}
if !hasTests && numDecl > 1 && len(flist) == 1 {
// If this file only has one example function, some
// other top-level declarations, and no tests or
// benchmarks, use the whole file as the example.
- flist[0].Body.Node = file
+ flist[0].Code = file
}
list = append(list, flist...)
}
return list
}
+var outputPrefix = regexp.MustCompile(`(?i)^[[:space:]]*output:`)
+
+func exampleOutput(fun *FuncDecl, comments []*CommentGroup) string {
+ // find the last comment in the function
+ var last *CommentGroup
+ for _, cg := range comments {
+ if cg.Pos() < fun.Pos() {
+ continue
+ }
+ if cg.End() > fun.End() {
+ break
+ }
+ last = cg
+ }
+ if last != nil {
+ // test that it begins with the correct prefix
+ text := last.Text()
+ if loc := outputPrefix.FindStringIndex(text); loc != nil {
+ return strings.TrimSpace(text[loc[1]:])
+ }
+ }
+ return "" // no suitable comment found
+}
+
// isTest tells whether name looks like a test, example, or benchmark.
// It is a Test (say) if there is a character after Test that is not a
// lower-case letter. (We don't want Testiness.)
"math/big"
)
-// 3.142
func ExampleRat_SetString() {
r := new(big.Rat)
r.SetString("355/113")
fmt.Println(r.FloatString(3))
+ // Output: 3.142
}
-// 420
func ExampleInt_SetString() {
i := new(big.Int)
i.SetString("644", 8) // octal
fmt.Println(i)
+ // Output: 420
}
-// 3/2
func ExampleRat_Scan() {
// The Scan function is rarely used directly;
// the fmt package recognizes it as an implementation of fmt.Scanner.
} else {
fmt.Println(r)
}
+ // Output: 3/2
}
-// 18446744073709551617
func ExampleInt_Scan() {
// The Scan function is rarely used directly;
// the fmt package recognizes it as an implementation of fmt.Scanner.
} else {
fmt.Println(i)
}
+ // Output: 18446744073709551617
}
"path"
)
-// b
func ExampleBase() {
fmt.Println(path.Base("/a/b"))
+ // Output: b
}
-// Clean("a/c") = "a/c"
-// Clean("a//c") = "a/c"
-// Clean("a/c/.") = "a/c"
-// Clean("a/c/b/..") = "a/c"
-// Clean("/../a/c") = "/a/c"
-// Clean("/../a/b/../././/c") = "/a/c"
func ExampleClean() {
paths := []string{
"a/c",
for _, p := range paths {
fmt.Printf("Clean(%q) = %q\n", p, path.Clean(p))
}
+
+ // Output:
+ // Clean("a/c") = "a/c"
+ // Clean("a//c") = "a/c"
+ // Clean("a/c/.") = "a/c"
+ // Clean("a/c/b/..") = "a/c"
+ // Clean("/../a/c") = "/a/c"
+ // Clean("/../a/b/../././/c") = "/a/c"
}
-// /a/b
func ExampleDir() {
fmt.Println(path.Dir("/a/b/c"))
+ // Output: /a/b
}
-// .css
func ExampleExt() {
fmt.Println(path.Ext("/a/b/c/bar.css"))
+ // Output: .css
}
-// true
func ExampleIsAbs() {
fmt.Println(path.IsAbs("/dev/null"))
+ // Output: true
}
-// a/b/c
func ExampleJoin() {
fmt.Println(path.Join("a", "b", "c"))
+ // Output: a/b/c
}
-// static/ myfile.css
func ExampleSplit() {
fmt.Println(path.Split("static/myfile.css"))
+ // Output: static/ myfile.css
}
"sort"
)
-// [1 2 3 4 5 6]
func ExampleInts() {
s := []int{5, 2, 6, 3, 1, 4} // unsorted
sort.Ints(s)
fmt.Println(s)
+ // Output: [1 2 3 4 5 6]
}
"strings"
)
-// Fields are: ["foo" "bar" "baz"]
func ExampleFields() {
fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz "))
+ // Output: Fields are: ["foo" "bar" "baz"]
}
-// true
-// false
-// true
-// true
func ExampleContains() {
fmt.Println(strings.Contains("seafood", "foo"))
fmt.Println(strings.Contains("seafood", "bar"))
fmt.Println(strings.Contains("seafood", ""))
fmt.Println(strings.Contains("", ""))
+ // Output:
+ // true
+ // false
+ // true
+ // true
}
-// false
-// true
-// false
-// false
func ExampleContainsAny() {
fmt.Println(strings.ContainsAny("team", "i"))
fmt.Println(strings.ContainsAny("failure", "u & i"))
fmt.Println(strings.ContainsAny("foo", ""))
fmt.Println(strings.ContainsAny("", ""))
-
+ // Output:
+ // false
+ // true
+ // false
+ // false
}
-// 3
-// 5
func ExampleCount() {
fmt.Println(strings.Count("cheese", "e"))
fmt.Println(strings.Count("five", "")) // before & after each rune
+ // Output:
+ // 3
+ // 5
}
-// true
func ExampleEqualFold() {
fmt.Println(strings.EqualFold("Go", "go"))
+ // Output: true
}
-// 4
-// -1
func ExampleIndex() {
fmt.Println(strings.Index("chicken", "ken"))
fmt.Println(strings.Index("chicken", "dmr"))
+ // Output:
+ // 4
+ // -1
}
-// 4
-// -1
func ExampleRune() {
fmt.Println(strings.IndexRune("chicken", 'k'))
fmt.Println(strings.IndexRune("chicken", 'd'))
+ // Output:
+ // 4
+ // -1
}
-// 0
-// 3
-// -1
func ExampleLastIndex() {
fmt.Println(strings.Index("go gopher", "go"))
fmt.Println(strings.LastIndex("go gopher", "go"))
fmt.Println(strings.LastIndex("go gopher", "rodent"))
+ // Output:
+ // 0
+ // 3
+ // -1
}
-// foo, bar, baz
func ExampleJoin() {
s := []string{"foo", "bar", "baz"}
fmt.Println(strings.Join(s, ", "))
+ // Output: foo, bar, baz
}
-// banana
func ExampleRepeat() {
fmt.Println("ba" + strings.Repeat("na", 2))
+ // Output: banana
}
-// oinky oinky oink
-// moo moo moo
func ExampleReplace() {
fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2))
fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1))
+ // Output:
+ // oinky oinky oink
+ // moo moo moo
}
-// ["a" "b" "c"]
-// ["" "man " "plan " "canal panama"]
-// [" " "x" "y" "z" " "]
-// [""]
func ExampleSplit() {
fmt.Printf("%q\n", strings.Split("a,b,c", ","))
fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a "))
fmt.Printf("%q\n", strings.Split(" xyz ", ""))
fmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins"))
+ // Output:
+ // ["a" "b" "c"]
+ // ["" "man " "plan " "canal panama"]
+ // [" " "x" "y" "z" " "]
+ // [""]
}
-// ["a" "b,c"]
-// [] (nil = true)
func ExampleSplitN() {
fmt.Printf("%q\n", strings.SplitN("a,b,c", ",", 2))
z := strings.SplitN("a,b,c", ",", 0)
fmt.Printf("%q (nil = %v)\n", z, z == nil)
+ // Output:
+ // ["a" "b,c"]
+ // [] (nil = true)
}
-// ["a," "b," "c"]
func ExampleSplitAfter() {
fmt.Printf("%q\n", strings.SplitAfter("a,b,c", ","))
+ // Output: ["a," "b," "c"]
}
-// ["a," "b,c"]
func ExampleSplitAfterN() {
fmt.Printf("%q\n", strings.SplitAfterN("a,b,c", ",", 2))
+ // Output: ["a," "b,c"]
}
-// Her Royal Highness
func ExampleTitle() {
fmt.Println(strings.Title("her royal highness"))
+ // Output: Her Royal Highness
}
-// LOUD NOISES
-// ХЛЕБ
func ExampleToTitle() {
fmt.Println(strings.ToTitle("loud noises"))
fmt.Println(strings.ToTitle("хлеб"))
+ // Output:
+ // LOUD NOISES
+ // ХЛЕБ
}
-// [Achtung]
func ExampleTrim() {
- fmt.Printf("[%s]", strings.Trim(" !!! Achtung !!! ", "! "))
+ fmt.Printf("[%q]", strings.Trim(" !!! Achtung !!! ", "! "))
+ // Output: ["Achtung"]
}
-// 'Gjnf oevyyvt naq gur fyvgul tbcure...
func ExampleMap() {
rot13 := func(r rune) rune {
switch {
return r
}
fmt.Println(strings.Map(rot13, "'Twas brillig and the slithy gopher..."))
+ // Output: 'Gjnf oevyyvt naq gur fyvgul tbcure...
}
-// a lone gopher
func ExampleTrimSpace() {
fmt.Println(strings.TrimSpace(" \t\n a lone gopher \n\t\r\n"))
+ // Output: a lone gopher
}
-// This is <b>HTML</b>!
func ExampleNewReplacer() {
r := strings.NewReplacer("<", "<", ">", ">")
fmt.Println(r.Replace("This is <b>HTML</b>!"))
+ // Output: This is <b>HTML</b>!
}
-// GOPHER
func ExampleToUpper() {
fmt.Println(strings.ToUpper("Gopher"))
+ // Output: GOPHER
}
-// gopher
func ExampleToLower() {
fmt.Println(strings.ToLower("Gopher"))
+ // Output: gopher
}
// }
// }
//
-// The package also runs and verifies example code. Example functions
-// include an introductory comment that is compared with the standard output
-// of the function when the tests are run, as in this example of an example:
+// The package also runs and verifies example code. Example functions may
+// include a concluding comment that begins with "Output:" and is compared with
+// the standard output of the function when the tests are run, as in these
+// examples of an example:
//
-// // hello
// func ExampleHello() {
// fmt.Println("hello")
+// // Output: hello
// }
//
-// Example functions without comments are compiled but not executed.
+// func ExampleSalutations() {
+// fmt.Println("hello, and")
+// fmt.Println("goodbye")
+// // Output:
+// // hello, and
+// // goodbye
+// }
+//
+// Example functions without output comments are compiled but not executed.
//
// The naming convention to declare examples for a function F, a type T and
// method M on type T are:
"text/template"
)
-// Dear Aunt Mildred,
-//
-// It was a pleasure to see you at the wedding.
-// Thank you for the lovely bone china tea set.
-//
-// Best wishes,
-// Josie
-//
-// Dear Uncle John,
-//
-// It is a shame you couldn't make it to the wedding.
-// Thank you for the lovely moleskin pants.
-//
-// Best wishes,
-// Josie
-//
-// Dear Cousin Rodney,
-//
-// It is a shame you couldn't make it to the wedding.
-//
-// Best wishes,
-// Josie
func ExampleTemplate() {
// Define a template.
const letter = `
log.Println("executing template:", err)
}
}
+
+ // Output:
+ // Dear Aunt Mildred,
+ //
+ // It was a pleasure to see you at the wedding.
+ // Thank you for the lovely bone china tea set.
+ //
+ // Best wishes,
+ // Josie
+ //
+ // Dear Uncle John,
+ //
+ // It is a shame you couldn't make it to the wedding.
+ // Thank you for the lovely moleskin pants.
+ //
+ // Best wishes,
+ // Josie
+ //
+ // Dear Cousin Rodney,
+ //
+ // It is a shame you couldn't make it to the wedding.
+ //
+ // Best wishes,
+ // Josie
}
}
}
-// Go launched at 2009-11-10 15:00:00 -0800 PST
func ExampleDate() {
t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
fmt.Printf("Go launched at %s\n", t.Local())
+ // Output: Go launched at 2009-11-10 15:00:00 -0800 PST
}