Last active
December 16, 2019 04:24
-
-
Save 3m3x/f586c6bbaf5528af3584254947affc03 to your computer and use it in GitHub Desktop.
Poor-man's CLI in Go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Objective: | |
- to dynamically and arbitrarily call functions of varying signature | |
- to look up help info stored against a function | |
Example: | |
- given the command "func1" and parameter "abc" | |
- call the function by that name (if present), passing in "abc" | |
- given a non-existent function name, return an error message | |
- given command "?" | |
- display the documentation for each function | |
References: | |
https://stackoverflow.com/questions/6769020/go-map-of-functions | |
https://gobyexample.com/errors | |
*/ | |
package main | |
import ( | |
"bufio" | |
"fmt" | |
"os" | |
"strings" | |
) | |
/* | |
Store a function and its description | |
*/ | |
type command struct { | |
docstring string | |
function func(args []string) error | |
} | |
/* | |
Custom error for handling incorrect parameters to a function | |
*/ | |
type argError struct { | |
args int | |
} | |
func (e *argError) Error() string { | |
return fmt.Sprintf("error - arguments required: %d\n", e.args) | |
} | |
/* | |
Our function map or "table" of functions | |
*/ | |
var FUNC_JUMP = map[string]command{ | |
/* | |
func1 <arg> | |
*/ | |
"func1": command{ | |
docstring: "func1 <arg1> - does a thingy", | |
function: func(args []string) error { | |
if len(args) != 1 { | |
return &argError{1} | |
} | |
fmt.Printf("func1! %v\n", args) | |
return nil | |
}, | |
}, | |
/* | |
func2 <arg1> <arg2> | |
*/ | |
"func2": command{ | |
docstring: "func2 <arg1> <arg2> - does a thingy", | |
function: func(args []string) error { | |
if len(args) != 2 { | |
return &argError{2} | |
} | |
fmt.Printf("func2! %v\n", args) | |
return nil | |
}, | |
}, | |
/* | |
func3 | |
*/ | |
"func3": command{ | |
docstring: "func3 - does a thingy", | |
function: func(args []string) error { | |
if len(args) != 0 { | |
return &argError{0} | |
} | |
fmt.Printf("func3! %#v\n", args) | |
return nil | |
}, | |
}, | |
} | |
func printHelp() { | |
for _, command := range FUNC_JUMP { | |
fmt.Println(command.docstring) | |
} | |
fmt.Println("\nexit - quit the program") | |
} | |
func main() { | |
reader := bufio.NewReader(os.Stdin) | |
for { | |
fmt.Print("> ") | |
text, _ := reader.ReadString('\n') | |
text = strings.Replace(text, "\n", "", -1) | |
// Careful! Split can return an array with an emptry string in it which | |
// can 'look invisible' when you're debugging it (so use '%#v' in your | |
// print statements). PSA: your 'empty' array might not be so empty | |
// afterall. | |
tokens := strings.Split(text, " ") | |
if tokens[len(tokens)-1] == "" { | |
tokens = tokens[:len(tokens)-1] // remove the emptry string | |
} | |
cmd := tokens[0] | |
if cmd == "exit" { | |
return | |
} else if cmd == "?" { | |
printHelp() | |
continue | |
} else if _, found := FUNC_JUMP[cmd]; !found { | |
fmt.Printf("invalid command: %s\n", cmd) | |
continue | |
} | |
f := FUNC_JUMP[cmd].function | |
args := tokens[1:] | |
err := f(args) | |
if err != nil { | |
fmt.Println(err) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment