diff --git a/src/047-collection-functions/collection-functions.go b/src/047-collection-functions/collection-functions.go index 662ff19..1db115a 100644 --- a/src/047-collection-functions/collection-functions.go +++ b/src/047-collection-functions/collection-functions.go @@ -5,9 +5,9 @@ package main import "strings" import "fmt" -func Index(elems []string, val string) int { - for i, v := range elems { - if v == val { +func Index(strs []string, s string) int { + for i, str := range strs { + if s == str { return i } } @@ -36,7 +36,7 @@ func All(elems []string, f func(string) bool) bool { return true } -func Filter(elems []string, f func(string) bool) []string { +func Filter(vs []string, f func(string) bool) []string { filtered := []string{} for _, v := range elems { if f(v) { @@ -46,47 +46,47 @@ func Filter(elems []string, f func(string) bool) []string { return filtered } -func Map(elems []string, f func(string) string) []string { - mapped := make([]string, len(elems)) - for i, v := range elems { +func Map(strs []string, f func(string) string) []string { + mapped := make([]string, len(strs)) + for i, v := range strs { mapped[i] = f(v) } return mapped } func main() { - var elems = []string{"peach", "apple", "pear", "banana"} + var strs = []string{"peach", "apple", "pear", "plum"} - fmt.Println(Index(elems, "pear")) - fmt.Println(Index(elems, "grape")) + fmt.Println(Index(strs, "pear")) + fmt.Println(Index(strs, "grape")) fmt.Println() - fmt.Println(Include(elems, "pear")) - fmt.Println(Include(elems, "grape")) + fmt.Println(Include(strs, "pear")) + fmt.Println(Include(strs, "grape")) fmt.Println() - fmt.Println(Any(elems, func(v string) bool { + fmt.Println(Any(strs, func(v string) bool { return strings.HasPrefix(v, "p") })) - fmt.Println(Any(elems, func(v string) bool { + fmt.Println(Any(strs, func(v string) bool { return strings.HasPrefix(v, "g") })) fmt.Println() - fmt.Println(All(elems, func(v string) bool { + fmt.Println(All(strs, func(v string) bool { return strings.Contains(v, "a") })) - fmt.Println(All(elems, func(v string) bool { + fmt.Println(All(strs, func(v string) bool { return strings.Contains(v, "p") })) fmt.Println() - fmt.Println(Filter(elems, func(v string) bool { + fmt.Println(Filter(strs, func(v string) bool { return strings.Contains(v, "p") })) fmt.Println() - fmt.Println(Map(elems, func(s string) string { + fmt.Println(Map(strs, func(s string) string { return strings.ToUpper(s) })) fmt.Println() diff --git a/src/057-number-parsing/number-parsing.go b/src/057-number-parsing/number-parsing.go index bdda3a0..2a219bb 100644 --- a/src/057-number-parsing/number-parsing.go +++ b/src/057-number-parsing/number-parsing.go @@ -20,7 +20,8 @@ func main() { d, _ := strconv.ParseInt("0x1b3e", 0, 64) println(d) - // `Atoi` is a convenienice function for `int` parsing. + // `Atoi` is a convenienice function for `int` + // parsing. k, _ := strconv.Atoi("456") println(k) diff --git a/src/058-urls/urls.go b/src/058-urls/urls.go index 6fde08c..f37b56f 100644 --- a/src/058-urls/urls.go +++ b/src/058-urls/urls.go @@ -7,7 +7,7 @@ import "net/url" import "strings" func main() { - s := "postgres://user:pass@host.com:5432/path?k=v#frag" + s := "postgres://user:pass@host.com:5432/path?k=v#f" u, err := url.Parse(s) if err != nil { panic(err) diff --git a/src/060-base64-encoding/base64-encoding.go b/src/060-base64-encoding/base64-encoding.go index f7f7679..e27a592 100644 --- a/src/060-base64-encoding/base64-encoding.go +++ b/src/060-base64-encoding/base64-encoding.go @@ -1,6 +1,6 @@ package main -import "encoding/base64" +import b64 "encoding/base64" import "fmt" func main() { @@ -10,15 +10,15 @@ func main() { fmt.Println() // Standard base64 encoding/decoding. - sEnc := base64.StdEncoding.EncodeToString([]byte(data)) + sEnc := b64.StdEncoding.EncodeToString([]byte(data)) fmt.Println(sEnc) - sDec, _ := base64.StdEncoding.DecodeString(sEnc) + sDec, _ := b64.StdEncoding.DecodeString(sEnc) fmt.Println(string(sDec)) fmt.Println() // URL base64 encoding/decoding. - uEnc := base64.URLEncoding.EncodeToString([]byte(data)) + uEnc := b64.URLEncoding.EncodeToString([]byte(data)) fmt.Println(uEnc) - uDec, _ := base64.URLEncoding.DecodeString(uEnc) + uDec, _ := b64.URLEncoding.DecodeString(uEnc) fmt.Println(string(uDec)) } diff --git a/src/063-line-filters/line-filters.go b/src/063-line-filters/line-filters.go index 715a9fb..67ebc29 100644 --- a/src/063-line-filters/line-filters.go +++ b/src/063-line-filters/line-filters.go @@ -22,7 +22,8 @@ func main() { out := os.Stdout // If successful, each `ReadLine` returns bytes and a - // boolean indicating if don't have the whole line yet. + // boolean indicating if don't have the whole line + // yet. for { inBytes, pfx, err := in.ReadLine() diff --git a/src/064-command-line-arguments/command-line-arguments.go b/src/064-command-line-arguments/command-line-arguments.go index 0b0acf8..aafef26 100644 --- a/src/064-command-line-arguments/command-line-arguments.go +++ b/src/064-command-line-arguments/command-line-arguments.go @@ -9,7 +9,7 @@ import "fmt" func main() { // `os.Args` includes the program name as the first - // value. + // value. argsWithProg := os.Args argsWithoutProg := os.Args[1:] diff --git a/src/079-request-logging/request-logging.go b/src/079-request-logging/request-logging.go index ebbf5f8..c3ebc8a 100644 --- a/src/079-request-logging/request-logging.go +++ b/src/079-request-logging/request-logging.go @@ -15,21 +15,22 @@ func runLogging(logs chan string) { func wrapLogging(f http.HandlerFunc) http.HandlerFunc { logs := make(chan string, 10000) go runLogging(logs) - return func(rs http.ResponseWriter, rq *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { start := time.Now() - f(rs, rq) - method := req.Method - path := req.URL.Path + f(w, r) + method := r.Method + path := r.URL.Path elapsed := float64(time.Since(start)) / 1000000.0 - logs <- fmt.Sprintf("method=%s path=%s elapsed=%f", + logs <- fmt.Sprintf( + "method=%s path=%s elapsed=%f", method, path, elapsed) } } -func hello(rs http.ResponseWriter, rq *http.Request) { - rs.Header().Set("Content-Type", "text/plain") +func hello(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain") time.Sleep(time.Millisecond * 50) - fmt.Fprintln(rs, "Hello logged world") + fmt.Fprintln(w, "Hello logged world") } func main() { diff --git a/src/081-basic-authentication/basic-authentication.go b/src/081-basic-authentication/basic-authentication.go index e185f72..36af865 100644 --- a/src/081-basic-authentication/basic-authentication.go +++ b/src/081-basic-authentication/basic-authentication.go @@ -10,6 +10,7 @@ import ( ) type Auth func(string, string) bool +type handler http.HandlerFunc func testAuth(r *http.Request, auth Auth) bool { header := r.Header.Get("Authorization") @@ -35,7 +36,7 @@ func requireAuth(w http.ResponseWriter, r *http.Request) { w.Write([]byte("401 Unauthorized\n")) } -func wrapAuth(h http.HandlerFunc, a Auth) http.HandlerFunc { +func wrapAuth(h handler, a Auth) handler { return func(w http.ResponseWriter, r *http.Request) { if testAuth(r, a) { h(w, r) diff --git a/src/084-graceful-shutdown/graceful-shutdown.go b/src/084-graceful-shutdown/graceful-shutdown.go index 769148c..7aa344a 100644 --- a/src/084-graceful-shutdown/graceful-shutdown.go +++ b/src/084-graceful-shutdown/graceful-shutdown.go @@ -49,7 +49,8 @@ func main() { stop := make(chan bool, 1) sig := make(chan os.Signal, 1) - server := &http.Server{Handler: http.HandlerFunc(slow)} + handler := http.HandlerFunc(slow) + server := &http.Server{Handler: handler} fmt.Println("listen at=start") listener, listenErr := net.Listen("tcp", ":5000") if listenErr != nil { @@ -69,7 +70,9 @@ func main() { }() go func() { - signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) + signal.Notify( + sig, syscall.SIGINT, + syscall.SIGTERM) fmt.Println("trap at=start") <-sig stop <- true diff --git a/style/book.css b/style/book.css index 7c54991..9068071 100644 --- a/style/book.css +++ b/style/book.css @@ -1,5 +1,5 @@ /* PDF Formatting */ -@page { margin: 10pt 0pt 10pt 0pt } +@page { margin: 10px 10px 10px 10px } /*--------------------- Layout and Typography ----------------------------*/ body { @@ -30,8 +30,9 @@ hr { #container { position: relative; } -div.chapter { +table { page-break-inside: avoid; + width: 775px; } table td { border: 0; @@ -47,8 +48,8 @@ td.docs { text-align: left; } td.code { - max-width: 450px; - min-width: 450px; + max-width: 400px; + min-width: 400px; padding: 10px 10px 10px 10px; vertical-align: top; background: #f0f0f0; diff --git a/tool/src/build-html.go b/tool/src/build-html.go index 8f0fe17..9408fff 100644 --- a/tool/src/build-html.go +++ b/tool/src/build-html.go @@ -64,6 +64,12 @@ func readLines(path string) []string { return strings.Split(string(srcBytes), "\n") } +func mustGlob(glob string) []string { + paths, err := filepath.Glob(glob) + check(err) + return paths +} + func whichLexer(path string) string { if strings.HasSuffix(path, ".go") { return "go" @@ -88,102 +94,106 @@ type seg struct { docs, code, docsRendered, codeRendered string } -func main() { - ensureCache() - - sourcePaths, err := filepath.Glob("./src/0*/*") - check(err) - - fmt.Print(` - - - - Go by Example - - - -
- - `) - - for _, sourcePath := range sourcePaths { - lexer := whichLexer(sourcePath) - lines := readLines(sourcePath) - - segs := []*seg{} - segs = append(segs, &seg{code: "", docs: ""}) - lastSeen := "" - for _, line := range lines { - if todoPat.MatchString(line) { - continue - } - headerMatch := headerPat.MatchString(line) - docsMatch := docsPat.MatchString(line) - emptyMatch := line == "" - lastSeg := segs[len(segs)-1] - lastHeader := lastSeen == "header" - lastDocs := lastSeen == "docs" - newHeader := lastSeen != "header" && lastSeg.docs != "" - newDocs := lastSeen == "code" || lastSeen == "header" - newCode := (lastSeen != "code" && lastSeg.code != "") || lastSeen == "header" - if newHeader || newDocs || newCode { - debug("NEWSEG") - } - if headerMatch || (emptyMatch && lastHeader) { - trimmed := docsPat.ReplaceAllString(line, "") - if newHeader { - newSeg := seg{docs: trimmed, code: ""} - segs = append(segs, &newSeg) - } else { - lastSeg.docs = lastSeg.docs + "\n" + trimmed - } - debug("HEAD") - lastSeen = "header" - } else if docsMatch || (emptyMatch && lastDocs) { - trimmed := docsPat.ReplaceAllString(line, "") - if newDocs { - debug("NEWSEG") - newSeg := seg{docs: trimmed, code: ""} - segs = append(segs, &newSeg) - } else { - lastSeg.docs = lastSeg.docs + "\n" + trimmed - } - debug("DOCS") - lastSeen = "docs" +func parseSegs(sourcePath string) []*seg { + lines := readLines(sourcePath) + segs := []*seg{} + segs = append(segs, &seg{code: "", docs: ""}) + lastSeen := "" + for _, line := range lines { + if todoPat.MatchString(line) { + continue + } + headerMatch := headerPat.MatchString(line) + docsMatch := docsPat.MatchString(line) + emptyMatch := line == "" + lastSeg := segs[len(segs)-1] + lastHeader := lastSeen == "header" + lastDocs := lastSeen == "docs" + newHeader := lastSeen != "header" && lastSeg.docs != "" + newDocs := lastSeen == "code" || lastSeen == "header" + newCode := (lastSeen != "code" && lastSeg.code != "") || lastSeen == "header" + if newHeader || newDocs || newCode { + debug("NEWSEG") + } + if headerMatch || (emptyMatch && lastHeader) { + trimmed := docsPat.ReplaceAllString(line, "") + if newHeader { + newSeg := seg{docs: trimmed, code: ""} + segs = append(segs, &newSeg) } else { - if newCode { - newSeg := seg{docs: "", code: line} - segs = append(segs, &newSeg) - } else { - lastSeg.code = lastSeg.code + "\n" + line - } - debug("CODE") - lastSeen = "code" + lastSeg.docs = lastSeg.docs + "\n" + trimmed } - } - segs = append(segs, &seg{code: "", docs: ""}) - - for _, seg := range segs { - if seg.docs != "" { - seg.docsRendered = string(blackfriday.MarkdownCommon([]byte(seg.docs))) + debug("HEAD") + lastSeen = "header" + } else if docsMatch || (emptyMatch && lastDocs) { + trimmed := docsPat.ReplaceAllString(line, "") + if newDocs { + debug("NEWSEG") + newSeg := seg{docs: trimmed, code: ""} + segs = append(segs, &newSeg) + } else { + lastSeg.docs = lastSeg.docs + "\n" + trimmed } - if seg.code != "" { - seg.codeRendered = cachedRender("/usr/local/bin/pygmentize", []string{"-l", lexer, "-f", "html"}, seg.code) + debug("DOCS") + lastSeen = "docs" + } else { + if newCode { + newSeg := seg{docs: "", code: line} + segs = append(segs, &newSeg) + } else { + lastSeg.code = lastSeg.code + "\n" + line } - } - - for _, seg := range segs { - codeClasses := "code" - if seg.code == "" { - codeClasses = codeClasses + " empty" - } - fmt.Printf( - ` - - - `, seg.docsRendered, codeClasses, seg.codeRendered) + debug("CODE") + lastSeen = "code" } } - - fmt.Print(`
%s%s
`) + return append(segs, &seg{code: "", docs: ""}) +} + +func parseAndRenderSegs(sourcePath string) []*seg { + segs := parseSegs(sourcePath) + lexer := whichLexer(sourcePath) + for _, seg := range segs { + if seg.docs != "" { + seg.docsRendered = string(blackfriday.MarkdownCommon([]byte(seg.docs))) + } + if seg.code != "" { + seg.codeRendered = cachedRender("/usr/local/bin/pygmentize", []string{"-l", lexer, "-f", "html"}, seg.code) + } + } + return segs +} + +func main() { + ensureCache() + fmt.Print(` + + + + Go by Example + + + +
`) + chapterPaths := mustGlob("./src/0*") + for _, chapterPath := range chapterPaths { + fmt.Print(``) + sourcePaths := mustGlob(chapterPath + "/*") + for _, sourcePath := range sourcePaths { + segs := parseAndRenderSegs(sourcePath) + for _, seg := range segs { + codeClasses := "code" + if seg.code == "" { + codeClasses = codeClasses + " empty" + } + fmt.Printf( + ` + + + `, seg.docsRendered, codeClasses, seg.codeRendered) + } + } + fmt.Print(`
%s%s
`) + } + fmt.Print(`
`) } diff --git a/tool/src/measure.go b/tool/src/measure.go index 5557f29..c097fa4 100644 --- a/tool/src/measure.go +++ b/tool/src/measure.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" "path/filepath" + "regexp" "strings" ) @@ -20,6 +21,8 @@ func readLines(path string) []string { return strings.Split(string(srcBytes), "\n") } +var todoPat = regexp.MustCompile("\\/\\/ todo: ") + func main() { sourcePaths, err := filepath.Glob("./src/0*/*") check(err) @@ -28,7 +31,7 @@ func main() { foundLongLine := false lines := readLines(sourcePath) for _, line := range lines { - if len(line) > 60 && !foundLongLine { + if !foundLongLine && !todoPat.MatchString(line) && (len(line) > 58) { fmt.Println(sourcePath) foundLongLine = true foundLongFile = true