Skip to content

Commit

Permalink
Documentation clean up work, added examples for CLI helper functions
Browse files Browse the repository at this point in the history
  • Loading branch information
thrawn01 committed Jun 6, 2018
1 parent 74e453a commit 0359d9f
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 160 deletions.
140 changes: 0 additions & 140 deletions args.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"reflect"
"regexp"
"strconv"
"strings"
)
Expand Down Expand Up @@ -34,82 +33,6 @@ func (nl *NullLogger) Println(...interface{}) {}
// Public Word Formatting Functions
// ***********************************************

// Mixing Spaces and Tabs will have undesired effects
func Dedent(input string) string {
text := []byte(input)

// find the first \n::space:: combo
leadingWhitespace := regexp.MustCompile(`(?m)^[ \t]+`)
idx := leadingWhitespace.FindIndex(text)
if idx == nil {
fmt.Printf("Unable to find \\n::space:: combo\n")
return input
}
//fmt.Printf("idx: '%d:%d'\n", idx[0], idx[1])

// Create a regex to match any the number of spaces we first found
gobbleRegex := fmt.Sprintf("(?m)^[ \t]{%d}?", (idx[1] - idx[0]))
//fmt.Printf("gobbleRegex: '%s'\n", gobbleRegex)
gobbleIndents := regexp.MustCompile(gobbleRegex)
// Find any identical spaces and remove them
dedented := gobbleIndents.ReplaceAll(text, []byte{})
return string(dedented)
}

func DedentTrim(input string, cutset string) string {
return strings.Trim(Dedent(input), cutset)
}

func WordWrap(msg string, indent int, wordWrap int) string {
// Remove any previous formatting
regex, _ := regexp.Compile(" {2,}|\n|\t")
msg = regex.ReplaceAllString(msg, "")

wordWrapLen := wordWrap - indent
if wordWrapLen <= 0 {
panic(fmt.Sprintf("Flag indent spacing '%d' exceeds wordwrap length '%d'\n", indent, wordWrap))
}

if len(msg) < wordWrapLen {
return msg
}

// Split the msg into lines
var lines []string
var eol int
for i := 0; i < len(msg); {
eol = i + wordWrapLen
// If the End Of Line exceeds the message length + our peek at the next character
if (eol + 1) >= len(msg) {
// Slice until the end of the message
lines = append(lines, msg[i:len(msg)])
i = len(msg)
break
}
// Slice this portion of the message into a single line
line := msg[i:eol]
// If the next character past eol is not a space
// (Usually means we are in the middle of a word)
if msg[eol+1] != ' ' {
// Find the last space before the word wrap
idx := strings.LastIndex(line, " ")
eol = i + idx
}
lines = append(lines, msg[i:eol])
i = eol
}
var spacer string
if indent <= 0 {
spacer = fmt.Sprintf("\n%%s")
} else {
spacer = fmt.Sprintf("\n%%-%ds", indent-1)
}

//fmt.Print("fmt: %s\n", spacer)
seperator := fmt.Sprintf(spacer, "")
return strings.Join(lines, seperator)
}

func castString(name string, dest interface{}, value interface{}) (interface{}, error) {
// If value is nil, return the type default
if value == nil {
Expand Down Expand Up @@ -220,27 +143,6 @@ func castStringSlice(name string, dest interface{}, value interface{}) (interfac
return append(dest.([]string), StringToSlice(value.(string), strings.TrimSpace)...), nil
}

// Given a comma separated string, return a slice of string items.
// Return the entire string as the first item if no comma is found.
// // Returns []string{"one"}
// result := args.StringToSlice("one")
//
// // Returns []string{"one", "two", "three"}
// result := args.StringToSlice("one, two, three", strings.TrimSpace)
//
// // Returns []string{"ONE", "TWO", "THREE"}
// result := args.StringToSlice("one, two, three", strings.ToUpper, strings.TrimSpace)
func StringToSlice(value string, modifiers ...func(s string) string) []string {
result := strings.Split(value, ",")
// Apply the modifiers
for _, modifier := range modifiers {
for idx, item := range result {
result[idx] = modifier(item)
}
}
return result
}

func mergeStringMap(src, dest map[string]string) map[string]string {
for key, value := range src {
dest[key] = value
Expand Down Expand Up @@ -320,45 +222,3 @@ func JSONToMap(value string) (map[string]string, error) {
return result, nil
}

func StringToMap(value string) (map[string]string, error) {
tokenizer := NewKeyValueTokenizer(value)
result := make(map[string]string)

var lvalue, rvalue, expression string
for {
lvalue = tokenizer.Next()
if lvalue == "" {
return result, errors.New(fmt.Sprintf("Expected key at pos '%d' but found none; "+
"map values should be 'key=value' separated by commas", tokenizer.Pos))
}
if strings.HasPrefix(lvalue, "{") {
// Assume this is JSON format and attempt to un-marshal
return JSONToMap(value)
}

expression = tokenizer.Next()
if expression != "=" {
return result, errors.New(fmt.Sprintf("Expected '=' after '%s' but found '%s'; "+
"map values should be 'key=value' separated by commas", lvalue, expression))
}
rvalue = tokenizer.Next()
if rvalue == "" {
return result, errors.New(fmt.Sprintf("Expected value after '%s' but found none; "+
"map values should be 'key=value' separated by commas", expression))
}
result[lvalue] = rvalue

// Are there anymore tokens?
delimiter := tokenizer.Next()
if delimiter == "" {
break
}

// Should be a comma next
if delimiter != "," {
return result, errors.New(fmt.Sprintf("Expected ',' after '%s' but found '%s'; "+
"map values should be 'key=value' separated by commas", rvalue, delimiter))
}
}
return result, nil
}
154 changes: 143 additions & 11 deletions cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"

"github.com/pkg/errors"
"regexp"
)

// A collection of CLI build helpers
Expand All @@ -32,8 +33,10 @@ func LoadFile(fileName string) ([]byte, error) {
// // If stdin is getting piped data, read from stdin
// if args.IsCharDevice(os.Stdin) {
// contents, err = ioutil.ReadAll(os.Stdin)
// } else {
// // load from file given instead
// contents, err = args.LoadFile(opts.String("input-file"))
// }
//
func IsCharDevice(file *os.File) bool {
stat, err := file.Stat()
if err != nil {
Expand All @@ -42,16 +45,6 @@ func IsCharDevice(file *os.File) bool {
return (stat.Mode() & os.ModeCharDevice) == 0
}

// Returns true if the flags given are set on src
func hasFlags(src, flag ParseFlag) bool {
return src&flag != 0
}

// Sets all the flags given on dest
func setFlags(dest *ParseFlag, flag ParseFlag) {
*dest = *dest | flag
}

// Returns a curl command representation of the passed http.Request
func CurlString(req *http.Request, payload *[]byte) string {
parts := []string{"curl", "-i", "-X", req.Method, req.URL.String()}
Expand All @@ -64,3 +57,142 @@ func CurlString(req *http.Request, payload *[]byte) string {
}
return strings.Join(parts, " ")
}

// Given an indented string remove the first indentation
// (Mixing Spaces and Tabs will have undesired effects)
func Dedent(input string) string {
text := []byte(input)

// find the first \n::space:: combo
leadingWhitespace := regexp.MustCompile(`(?m)^[ \t]+`)
idx := leadingWhitespace.FindIndex(text)
if idx == nil {
fmt.Printf("Unable to find \\n::space:: combo\n")
return input
}
//fmt.Printf("idx: '%d:%d'\n", idx[0], idx[1])

// Create a regex to match any the number of spaces we first found
gobbleRegex := fmt.Sprintf("(?m)^[ \t]{%d}?", (idx[1] - idx[0]))
//fmt.Printf("gobbleRegex: '%s'\n", gobbleRegex)
gobbleIndents := regexp.MustCompile(gobbleRegex)
// Find any identical spaces and remove them
dedented := gobbleIndents.ReplaceAll(text, []byte{})
return string(dedented)
}

// Exactly like `Dedent()` but trims trailing `cutset` characters
func DedentTrim(input string, cutset string) string {
return strings.Trim(Dedent(input), cutset)
}

// Formats the text `msg` into the form of a paragraph, wrapping the text to the
// character `length` specified. Indenting the second line `indent` number of spaces
func WordWrap(msg string, indent int, length int) string {
// Remove any previous formatting
regex, _ := regexp.Compile(" {2,}|\n|\t")
msg = regex.ReplaceAllString(msg, "")

wordWrapLen := length - indent
if wordWrapLen <= 0 {
panic(fmt.Sprintf("Flag indent spacing '%d' exceeds wordwrap length '%d'\n", indent, length))
}

if len(msg) < wordWrapLen {
return msg
}

// Split the msg into lines
var lines []string
var eol int
for i := 0; i < len(msg); {
eol = i + wordWrapLen
// If the End Of Line exceeds the message length + our peek at the next character
if (eol + 1) >= len(msg) {
// Slice until the end of the message
lines = append(lines, msg[i:len(msg)])
i = len(msg)
break
}
// Slice this portion of the message into a single line
line := msg[i:eol]
// If the next character past eol is not a space
// (Usually means we are in the middle of a word)
if msg[eol+1] != ' ' {
// Find the last space before the word wrap
idx := strings.LastIndex(line, " ")
eol = i + idx
}
lines = append(lines, msg[i:eol])
i = eol
}
var spacer string
if indent <= 0 {
spacer = fmt.Sprintf("\n%%s")
} else {
spacer = fmt.Sprintf("\n%%-%ds", indent-1)
}

//fmt.Print("fmt: %s\n", spacer)
seperator := fmt.Sprintf(spacer, "")
return strings.Join(lines, seperator)
}

// Given a comma separated string, return a slice of string items.
// Return the entire string as the first item if no comma is found.
func StringToSlice(value string, modifiers ...func(s string) string) []string {
result := strings.Split(value, ",")
// Apply the modifiers
for _, modifier := range modifiers {
for idx, item := range result {
result[idx] = modifier(item)
}
}
return result
}

// Given a comma separated string of key values in the form `key=value`.
// Return a map of key values as strings, Also excepts JSON for more complex
// quoted or escaped data.
func StringToMap(value string) (map[string]string, error) {
tokenizer := NewKeyValueTokenizer(value)
result := make(map[string]string)

var lvalue, rvalue, expression string
for {
lvalue = tokenizer.Next()
if lvalue == "" {
return result, errors.New(fmt.Sprintf("Expected key at pos '%d' but found none; "+
"map values should be 'key=value' separated by commas", tokenizer.Pos))
}
if strings.HasPrefix(lvalue, "{") {
// Assume this is JSON format and attempt to un-marshal
return JSONToMap(value)
}

expression = tokenizer.Next()
if expression != "=" {
return result, errors.New(fmt.Sprintf("Expected '=' after '%s' but found '%s'; "+
"map values should be 'key=value' separated by commas", lvalue, expression))
}
rvalue = tokenizer.Next()
if rvalue == "" {
return result, errors.New(fmt.Sprintf("Expected value after '%s' but found none; "+
"map values should be 'key=value' separated by commas", expression))
}
result[lvalue] = rvalue

// Are there anymore tokens?
delimiter := tokenizer.Next()
if delimiter == "" {
break
}

// Should be a comma next
if delimiter != "," {
return result, errors.New(fmt.Sprintf("Expected ',' after '%s' but found '%s'; "+
"map values should be 'key=value' separated by commas", rvalue, delimiter))
}
}
return result, nil
}
Loading

0 comments on commit 0359d9f

Please sign in to comment.