Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add nashdoc tool #175

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions cmd/nashdoc/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package main

import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/NeowayLabs/nash/ast"
"github.com/NeowayLabs/nash/parser"
)

func docUsage(out io.Writer) {
fmt.Fprintf(out, "Usage: %s <package>.<fn name or wildcard>\n", filepath.Base(os.Args[0]))
}

func printDoc(stdout, _ io.Writer, docs []*ast.CommentNode, fn *ast.FnDeclNode) {
fmt.Fprintf(stdout, "fn %s(%s)\n", fn.Name(), strings.Join(fn.Args(), ", "))

for _, doc := range docs {
fmt.Fprintf(stdout, "\t%s\n", doc.String()[2:])
}

fmt.Println()
}

func lookFn(stdout, stderr io.Writer, fname string, pack string, pattern *regexp.Regexp) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why just the first parameters omits type ?

content, err := ioutil.ReadFile(fname)

if err != nil {
fmt.Fprintf(stderr, "error: %s\n", err.Error())
return
}

parser := parser.NewParser(fname, string(content))

tree, err := parser.Parse()

if err != nil {
return
}

nodelen := len(tree.Root.Nodes)

for i, j := 0, 1; j < nodelen; i, j = i+1, j+1 {
var comments []*ast.CommentNode

node := tree.Root.Nodes[i]
next := tree.Root.Nodes[j]

if node.Type() == ast.NodeComment {
comments = append(comments, node.(*ast.CommentNode))
last := node

// process comments
for i = i + 1; i < nodelen-1; i++ {
node = tree.Root.Nodes[i]

if node.Type() == ast.NodeComment &&
node.Line() == last.Line()+1 {
comments = append(comments, node.(*ast.CommentNode))
last = node
} else {
break
}
}

i--
j = i + 1
next = tree.Root.Nodes[j]

if next.Line() != last.Line()+1 {
comments = []*ast.CommentNode{}
}

if next.Type() == ast.NodeFnDecl {
fn := next.(*ast.FnDeclNode)

if pattern.MatchString(fn.Name()) {
printDoc(stdout, stderr, comments, next.(*ast.FnDeclNode))

}
}
} else if node.Type() == ast.NodeFnDecl {
fn := node.(*ast.FnDeclNode)

if pattern.MatchString(fn.Name()) {
// found func, but no docs :-(
printDoc(stdout, stderr, []*ast.CommentNode{}, fn)
}
}

}
}

func walk(stdout, stderr io.Writer, nashpath, pkg string, pattern *regexp.Regexp) error {
return filepath.Walk(nashpath+"/lib", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}

if info.IsDir() {
return nil
}

dirpath := filepath.Dir(path)
dirname := filepath.Base(dirpath)
ext := filepath.Ext(path)

if ext != "" && ext != ".sh" {
return nil
}

if dirname != pkg {
return nil
}

lookFn(stdout, stderr, path, pkg, pattern)

return nil
})
}

func doc(stdout, stderr io.Writer, args []string) error {
if len(args) < 1 {
docUsage(stderr)
return nil
}

packfn := args[0]
parts := strings.Split(packfn, ".")

if len(parts) != 2 {
docUsage(stderr)
return nil
}

pkg := parts[0]

if strings.ContainsAny(parts[1], ".[]()") {
return fmt.Errorf("Only wildcards * and ? supported")
}

patternStr := strings.Replace(parts[1], "*", ".*", -1)
patternStr = strings.Replace(patternStr, "?", ".?", -1)
patternStr = "^" + patternStr + "$"

pattern, err := regexp.Compile(patternStr)

if err != nil {
return fmt.Errorf("invalid pattern: %s", err.Error())
}

nashpath := os.Getenv("NASHPATH")

if nashpath == "" {
homepath := os.Getenv("HOME")

if homepath == "" {
return fmt.Errorf("NASHPATH not set...\n")
}

fmt.Fprintf(stderr, "NASHPATH not set. Using ~/.nash\n")

nashpath = homepath + "/.nash"
}

return walk(stdout, stderr, nashpath, pkg, pattern)
}
102 changes: 102 additions & 0 deletions cmd/nashdoc/doc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package main

import (
"bytes"
"os"
"testing"
)

type (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one type inside type() ? Some reason for this ? consistency ?

testTbl struct {
lookFor string
outExpected string
errExpected string
errStr string
}
)

func dotest(t *testing.T, test testTbl) {
testdir := "/src/github.com/NeowayLabs/nash/cmd/nashdoc/testcases/"
nashpath := os.Getenv("GOPATH") + testdir
os.Setenv("NASHPATH", nashpath)

var (
stdout, stderr bytes.Buffer
)

err := doc(&stdout, &stderr, []string{test.lookFor})

if err != nil {
if test.errStr != "" {
if err.Error() != test.errStr {
t.Fatalf("Expected error '%s', but got '%s'",
test.errStr, err.Error())
}
} else {
t.Fatal(err)
}
}

gotOut := string(stdout.Bytes())
gotErr := string(stderr.Bytes())

if test.outExpected != gotOut {
t.Fatalf("Stdout differs: '%s' != '%s'", test.outExpected, gotOut)
}

if test.errExpected != gotErr {
t.Fatalf("Stderr differs: '%s' != '%s'", test.errExpected, gotErr)
}
}

func TestDoc(t *testing.T) {
for _, test := range []testTbl{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Show struct initialization with the field names some love :-), again kind'a hard to understand what is each of the fields.

{
"somepkg.somefn",
`fn somefn(a, b, c, d)
somefn is a testcase function
multiples comments
etc
etc
`, ``, "",
},
// Test empty pkg and func
{
"",
"",
"Usage: nashdoc.test <package>.<fn name or wildcard>\n",
"",
},

// test non existent package
{
"blahbleh.bli",
"",
"",
"",
},

{
"a.a",
`fn a()
`, ``, "",
},

{
"a.b",
`fn b(a)
bleh
`,
``, "",
},
{
"a.c",
`fn c(a, b)
carrr
`,
``, "",
},
} {
dotest(t, test)
}
}
50 changes: 50 additions & 0 deletions cmd/nashdoc/idoc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package main

import (
"fmt"
"io"
"os"
"path/filepath"
"regexp"
)

const banner = `888b 888 888 888 888888
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AAAWWEESOMEEEEEEEE !!! lol

8888b 888 888 888 888888
88888b 888 888 888 888888
888Y88b 888 8888b. .d8888b 88888b. .d8888b 88888b. .d88b. 888888
888 Y88b888 "88b88K 888 "88b 88K 888 "88bd8P Y8b888888
888 Y88888.d888888"Y8888b.888 888 "Y8888b.888 88888888888888888
888 Y8888888 888 X88888 888 X88888 888Y8b. 888888
888 Y888"Y888888 88888P'888 888 88888P'888 888 "Y8888 888888
====================================================================
|| Documentation of ~/.nash/lib projects
`

func idoc(stdout, stderr io.Writer) error {
fmt.Fprintf(stdout, "%s\n", banner)
return walkAll(stdout, stderr, "/home/i4k/.nash", regexp.MustCompile(".*"))
}

func walkAll(stdout, stderr io.Writer, nashpath string, pattern *regexp.Regexp) error {
return filepath.Walk(nashpath+"/lib", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}

if info.IsDir() {
return nil
}

dirpath := filepath.Dir(path)
dirname := filepath.Base(dirpath)
ext := filepath.Ext(path)

if ext != "" && ext != ".sh" {
return nil
}

lookFn(stdout, stderr, path, dirname, pattern)

return nil
})
}
42 changes: 42 additions & 0 deletions cmd/nashdoc/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package main

import (
"flag"
"fmt"
"io"
"os"
)

var (
help *bool
)

func init() {
help = flag.Bool("h", false, "Show this help")
}

func usage() {
flag.PrintDefaults()
}

func main() {
flag.Parse()

if *help {
usage()
os.Exit(0)
}

if err := do(flag.Args(), os.Stdout, os.Stderr); err != nil {
fmt.Printf("error: %s\n", err.Error())
os.Exit(1)
}
}

func do(args []string, stdout, stderr io.Writer) error {
if len(args) == 0 {
return idoc(stdout, stderr)
}

return doc(stdout, stderr, args)
}
13 changes: 13 additions & 0 deletions cmd/nashdoc/testcases/lib/a/a.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
fn a() {

}

# bleh
fn b(a) {

}

# carrr
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One a lisper always a lisper :-P

fn c(a, b) {

}
11 changes: 11 additions & 0 deletions cmd/nashdoc/testcases/lib/somepkg/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env nash

# not relateed comment

# somefn is a testcase function
# multiples comments
# etc
# etc
fn somefn(a, b, c, d) {
echo $a $b $c $d
}