Skip to content
This repository has been archived by the owner on Jun 14, 2019. It is now read-only.

Commit

Permalink
Reorganize and add tests
Browse files Browse the repository at this point in the history
* Extract Node type and Tree func to tree package.
* Document public interface for package tree.
* Add tests for (Node) Print() output and for Tree() generation of Node.
* Add Godeps, Circle config, and bin/vet from
  https://github.com/thoughtbot/laces
  • Loading branch information
calebhearth committed Oct 7, 2015
1 parent a7f7c80 commit 62418fe
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 92 deletions.
5 changes: 5 additions & 0 deletions Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Godeps/Readme

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Godeps/_workspace/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions bin/vet
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
#
# validates that the project is clean of formatting and vet errors.
# symlink as .git/hooks/pre-commit to use as a pre-commit check.
#

if [[ -n "${GIT_INDEX_FILE}" ]]; then
gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$')
else
gofiles=$(find . ! -path "*/_*" -name "*.go")
fi

[ -z "$gofiles" ] && exit 0

function checkfmt() {
unformatted=$(gofmt -l $*)
[ -z "$unformatted" ] && return 0

echo >&2 "Go files must be formatted with gofmt. Please run:"
for fn in $unformatted; do
echo >&2 " gofmt -w $PWD/$fn"
done

return 1
}

function checkvet() {
unvetted=$(go vet ./... 2>&1 | grep -v "exit status")
[ -z "$unvetted" ] && return 0

echo >&2 "Go files must be vetted. Check these problems:"
IFS=$'\n'
for line in $unvetted; do
echo >&2 " $line"
done
unset IFS

return 1
}

checkfmt $gofiles || fail=yes
checkvet $gofiles || fail=yes

[ -z "$fail" ] || exit 1
20 changes: 20 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# See https://robots.thoughtbot.com/configure-circleci-for-go
machine:
environment:
IMPORT_PATH: "github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
MYGOPATH: "$(echo $GOPATH | cut -d : -f 1)"

dependencies:
pre:
- go get github.com/tools/godep

override:
- mkdir -p "$MYGOPATH/src/$IMPORT_PATH"
- rsync -azC --delete ./ "$MYGOPATH/src/$IMPORT_PATH/"

test:
pre:
- bin/vet

override:
- godep go test ./...
92 changes: 0 additions & 92 deletions ftree.go

This file was deleted.

19 changes: 19 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package main

import (
"bufio"
"os"

"github.com/calebthompson/ftree/tree"
)

func main() {
r := bufio.NewScanner(os.Stdin)
lines := []string{}
for r.Scan() {
lines = append(lines, r.Text())
}

t := tree.Tree(lines, "/")
t.Print(0, nil)
}
60 changes: 60 additions & 0 deletions tree/node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package tree

import (
"fmt"
"sort"
)

// Node is a tree of string. Leaves are empty Nodes or nil.
type Node map[string]Node

// Print recurses through n and its member Nodes to pretty-print a Node as a
// tree such as:
//
// ├── ftree
// │ ├── node.go
// │ ├── tree.go
// │ └── tree_test.go
// └── main.go
//
// Print should initially be called as n.Print(0, nil). The arguments are
// primarily interesting during recursion.
func (n Node) Print(indent int, leaders []string) {
var keys []string
for k := range n {
keys = append(keys, k)
}
sort.Strings(keys)

for i, part := range keys {
if part == "" {
n[part].Print(indent, leaders)
continue
}

for _, l := range leaders {
fmt.Print(l)
}

// For chains of single element maps, such as
// { "Users": { "caleb": { "code": {}, "books": {} } },
// combine to { "Users/caleb": { "code": {}, "books": {} } }.
for {
if len(n[part]) != 1 {
break
}
for k, v := range n[part] {
part += "/" + k
n[part] = v
}
}

if i == len(keys)-1 {
fmt.Printf("%s %s\n", "└──", part)
n[part].Print(indent+1, append(leaders, " "))
} else {
fmt.Printf("%s %s\n", "├──", part)
n[part].Print(indent+1, append(leaders, "│ "))
}
}
}
22 changes: 22 additions & 0 deletions tree/node_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package tree

func ExamplePrint() {
tree := Node{
"caleb": Node{
"code": Node{"ftree": Node{}},
"books": Node{
"Learning Go": Node{},
"The Little Go Book": Node{},
},
},
}

tree.Print(0, nil)

// Output:
// └── caleb
// ├── books
// │ ├── Learning Go
// │ └── The Little Go Book
// └── code/ftree
}
40 changes: 40 additions & 0 deletions tree/tree.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package tree

import "strings"

// Tree splits each line in lines on delim and builds a Node: a tree data
// structure of maps with string keys.
func Tree(lines []string, delim string) Node {
var parts []Node
for _, line := range lines {
parts = append(parts, buildTree(line, delim))
}

var tree Node
for _, part := range parts {
tree = merge(part, tree)
}

return tree
}

func buildTree(line, delim string) Node {
var subtree = Node{}
split := strings.SplitN(line, delim, 2)
if len(split) > 1 {
subtree[split[0]] = buildTree(split[1], delim)
} else {
subtree[split[0]] = Node{}
}
return subtree
}

func merge(src Node, dest Node) Node {
if dest == nil {
dest = Node{}
}
for k, v := range src {
dest[k] = merge(v, dest[k])
}
return dest
}
26 changes: 26 additions & 0 deletions tree/tree_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package tree

import (
"reflect"
"testing"
)

func TestTree(t *testing.T) {
lines := []string{
"caleb/code/ftree",
"caleb/books",
}

want := Node{
"caleb": Node{
"code": Node{"ftree": Node{}},
"books": Node{},
},
}

got := Tree(lines, "/")

if !reflect.DeepEqual(want, got) {
t.Fatalf("Expected \n%#v, got \n%#v", want, got)
}
}

0 comments on commit 62418fe

Please sign in to comment.