Skip to content

Commit

Permalink
Cleans up statements method names, comments, tokens file
Browse files Browse the repository at this point in the history
  • Loading branch information
tomnomnom committed Sep 10, 2016
1 parent 11edf75 commit fbf32d1
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 27 deletions.
27 changes: 18 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,24 +102,25 @@ func main() {
os.Exit(exitOK)
}

var raw io.Reader

// Determine what the program's input should be:
// file, HTTP URL or stdin
var rawInput io.Reader
filename := flag.Arg(0)
if filename == "" || filename == "-" {
raw = os.Stdin
rawInput = os.Stdin
} else {
if !validURL(filename) {
r, err := os.Open(filename)
if err != nil {
fatal(exitOpenFile, err)
}
raw = r
rawInput = r
} else {
r, err := getURL(filename)
if err != nil {
fatal(exitFetchURL, err)
}
raw = r
rawInput = r
}
}

Expand All @@ -133,11 +134,12 @@ func main() {
opts = opts | optNoSort
}

// Pick the appropriate action: gron or ungron
var a actionFn = gron
if ungronFlag {
a = ungron
}
exitCode, err := a(raw, os.Stdout, opts)
exitCode, err := a(rawInput, os.Stdout, opts)

if exitCode != exitOK {
fatal(exitCode, err)
Expand All @@ -146,8 +148,13 @@ func main() {
os.Exit(exitOK)
}

// an actionFn represents a main action of the program, it accepts
// an input, output and a bitfield of options; returning an exit
// code and any error that occurred
type actionFn func(io.Reader, io.Writer, int) (int, error)

// gron is the default action. Given JSON as the input it returns a list
// of assignment statements. Possible options are optNoSort and optMonochrome
func gron(r io.Reader, w io.Writer, opts int) (int, error) {

ss, err := statementsFromJSON(r)
Expand All @@ -174,21 +181,23 @@ func gron(r io.Reader, w io.Writer, opts int) (int, error) {
return exitOK, nil
}

// ungron is the reverse of gron. Given assignment statements as input,
// it returns JSON. The only option is optMonochrome
func ungron(r io.Reader, w io.Writer, opts int) (int, error) {
scanner := bufio.NewScanner(r)

// Make a list of statements from the input
var ss statements
for scanner.Scan() {
s := statementFromString(scanner.Text())
ss.addFull(s)
ss.add(s)
}
if err := scanner.Err(); err != nil {
return exitReadInput, fmt.Errorf("failed to read input statements")
}

// ungron the statements
merged, err := ss.ungron()
// turn the statements into a single merged interface{} type
merged, err := ss.toInterface()
if err != nil {
return exitParseStatements, err
}
Expand Down
26 changes: 12 additions & 14 deletions statements.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,18 @@ func (s statement) withNumericKey(k int) statement {
// E.g statement: json.foo = "bar";
type statements []statement

// add takes a statement representing a path, copies it,
// addWithValue takes a statement representing a path, copies it,
// adds a value token to the end of the statement and appends
// the new statement to the list of statements
func (ss *statements) add(s statement, new token) {
add := make(statement, len(s), len(s)+3)
copy(add, s)
add = append(add, token{"=", typEquals}, new, token{";", typSemi})
*ss = append(*ss, add)
func (ss *statements) addWithValue(path statement, value token) {
s := make(statement, len(path), len(path)+3)
copy(s, path)
s = append(s, token{"=", typEquals}, value, token{";", typSemi})
*ss = append(*ss, s)
}

// addFull appends a new complete statement to list of statements
func (ss *statements) addFull(s statement) {
// add appends a new complete statement to list of statements
func (ss *statements) add(s statement) {
*ss = append(*ss, s)
}

Expand All @@ -102,7 +102,7 @@ func statementFromString(str string) statement {
}

// ungron turns statements into a proper datastructure
func (ss statements) ungron() (interface{}, error) {
func (ss statements) toInterface() (interface{}, error) {

// Get all the individually parsed statements
var parsed []interface{}
Expand Down Expand Up @@ -229,21 +229,19 @@ func statementsFromJSON(r io.Reader) (statements, error) {
func (ss *statements) fill(prefix statement, v interface{}) {

// Add a statement for the current prefix and value
ss.add(prefix, valueTokenFromInterface(v))
ss.addWithValue(prefix, valueTokenFromInterface(v))

// Recurse into objects and arrays
switch vv := v.(type) {

case map[string]interface{}:
// It's an object
for k, sub := range vv {
var newPrefix statement
if validIdentifier(k) {
newPrefix = prefix.withBare(k)
ss.fill(prefix.withBare(k), sub)
} else {
newPrefix = prefix.withQuotedKey(k)
ss.fill(prefix.withQuotedKey(k), sub)
}
ss.fill(newPrefix, sub)
}

case []interface{}:
Expand Down
4 changes: 2 additions & 2 deletions statements_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func TestUngronStatementsSimple(t *testing.T) {
},
}

have, err := in.ungron()
have, err := in.toInterface()

if err != nil {
t.Fatalf("want nil error but have: %s", err)
Expand All @@ -177,7 +177,7 @@ func TestUngronStatementsInvalid(t *testing.T) {
}

for _, c := range cases {
_, err := c.ungron()
_, err := c.toInterface()
if err == nil {
t.Errorf("want non-nil error; have nil")
}
Expand Down
8 changes: 6 additions & 2 deletions tokens.go → token.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ const (
typError
)

// a sprintFn adds color to its input
type sprintFn func(...interface{}) string

// mapping of token types to the appropriate color sprintFn
var sprintFns = map[tokenTyp]sprintFn{
typBare: bareColor.SprintFunc(),
typNumericKey: numColor.SprintFunc(),
Expand All @@ -64,7 +66,7 @@ var sprintFns = map[tokenTyp]sprintFn{
typEmptyObject: braceColor.SprintFunc(),
}

// isValue returns true if the token is a valid value
// isValue returns true if the token is a valid value type
func (t token) isValue() bool {
switch t.typ {
case typString, typNumber, typTrue, typFalse, typNull, typEmptyArray, typEmptyObject:
Expand All @@ -74,7 +76,7 @@ func (t token) isValue() bool {
}
}

// isPunct returns true is the token is punctuation
// isPunct returns true is the token is a punctuation type
func (t token) isPunct() bool {
switch t.typ {
case typDot, typLBrace, typRBrace, typEquals, typSemi:
Expand Down Expand Up @@ -131,6 +133,8 @@ func valueTokenFromInterface(v interface{}) token {
}
}

// quoteString takes a string and returns a quoted and
// escaped string valid for use in gron output
func quoteString(s string) string {
out, err := json.Marshal(s)
if err != nil {
Expand Down
File renamed without changes.

0 comments on commit fbf32d1

Please sign in to comment.