Skip to content

Commit 44bb0d0

Browse files
committed
Refactor the code to be cleaner.
This refactors the entire lot so that it can act as a library in the future, and as a command if used directly. This also increases test coverage considerably... there is still more testing to do though.
1 parent d85e1fd commit 44bb0d0

File tree

9 files changed

+352
-200
lines changed

9 files changed

+352
-200
lines changed

flags.go

Lines changed: 71 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,36 @@ import (
88
"flag"
99
)
1010

11-
type BoolSlice []interface{}
11+
type BoolArg []interface{}
1212
type Args map[string]interface{}
13-
type StringSlice []interface{}
14-
type IntSlice []interface{}
15-
type ArgSlice []interface{}
16-
17-
var (
18-
_cliFlags = ArgSlice{
19-
StringSlice{"file", "", "the file, or dir"},
20-
BoolSlice{"glob", false, "search, and use a dir full of *.gohtml"},
21-
StringSlice{"output", "", "the file to write to"},
22-
BoolSlice{"stdout", false, "print to stdout"},
13+
type StringArg []interface{}
14+
type Flags []interface{}
15+
16+
// Bool pulls a value as a boolean, this
17+
// supports *bool, and bool, because either
18+
// can be given depending on flags
19+
func (a Args) Bool(k string) bool {
20+
o, ok := a[k].(bool)
21+
if ok {
22+
return o
2323
}
24-
)
2524

26-
func (a Args) Bool(k string) bool { return bool(*a[k].(*bool)) }
27-
func (a Args) String(k string) string { return string(*a[k].(*string)) }
28-
func (a Args) Int(k string) int { return int(*a[k].(*int)) }
25+
v := *a[k].(*bool)
26+
return bool(v)
27+
}
28+
29+
// String pulls a value as a boolean, this
30+
// supports *bool, and bool, because either
31+
// can be given depending on flags
32+
func (a Args) String(k string) string {
33+
o, ok := a[k].(string)
34+
if ok {
35+
return o
36+
}
37+
38+
v := *a[k].(*string)
39+
return string(v)
40+
}
2941

3042
// IsEmpty Allows you to check if a value was
3143
// given, this means that it wasn't nil, that it
@@ -38,30 +50,55 @@ func (a Args) IsEmpty(k string) bool {
3850
return false
3951
}
4052

41-
// flags parses our flags, and returns them
53+
// NewFlags provides the default flags, and
54+
// allows somebody who wishes to use as a base to
55+
// add their own flags, by just append()
56+
func NewFlags() *Flags {
57+
return &Flags{
58+
StringArg{"file", "", "the file, or dir"},
59+
BoolArg{"glob", false, "search, and use a dir full of *.gohtml"},
60+
StringArg{"output", "", "the file to write to"},
61+
BoolArg{"stdout", false, "print to stdout"},
62+
BoolArg{"debug", false, "debug output"},
63+
}
64+
}
65+
66+
// Parse parses our flags, and returns them,
4267
// we just encapsulate this to make life a little
4368
// easier at the end of the day, when working.
44-
func flags() (a Args) {
45-
a = make(map[string]interface{})
46-
for _, v := range _cliFlags {
69+
func (f Flags) Parse() (a Args) {
70+
a = make(Args)
71+
for _, v := range f {
4772
switch v.(type) {
48-
case BoolSlice:
49-
vv := v.(BoolSlice)
50-
a[vv[0].(string)] = flag.Bool(vv[0].(string),
51-
vv[1].(bool), vv[2].(string))
52-
53-
case StringSlice:
54-
vv := v.(StringSlice)
55-
a[vv[0].(string)] = flag.String(vv[0].(string),
56-
vv[1].(string), vv[2].(string))
57-
58-
case IntSlice:
59-
vv := v.(IntSlice)
60-
a[vv[0].(string)] = flag.Int(vv[0].(string),
61-
vv[1].(int), vv[2].(string))
73+
case BoolArg:
74+
vv := v.(BoolArg)
75+
k, def, dsc := vv[0].(string), vv[1].(bool), vv[2].(string)
76+
if flag.Lookup(k) == nil {
77+
a[k] = flag.Bool(k, def, dsc)
78+
continue
79+
}
80+
81+
fv := flag.Lookup(k).Value
82+
ov := fv.(flag.Getter).Get()
83+
a[k] = ov.(bool)
84+
85+
case StringArg:
86+
vv := v.(StringArg)
87+
k, def, dsc := vv[0].(string), vv[1].(string), vv[2].(string)
88+
if flag.Lookup(k) == nil {
89+
a[k] = flag.String(k, def, dsc)
90+
continue
91+
}
92+
93+
fv := flag.Lookup(k).Value
94+
ov := fv.(flag.Getter).Get()
95+
a[k] = ov.(string)
6296
}
6397
}
6498

65-
flag.Parse()
99+
if !flag.Parsed() {
100+
flag.Parse()
101+
}
102+
66103
return
67104
}

flags_test.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,51 @@ import (
1010
"github.com/stretchr/testify/assert"
1111
)
1212

13-
func TestIsEmpty(t *testing.T) {
13+
func TestNewFlags(t *testing.T) {
14+
assert.NotEmpty(t, NewFlags())
15+
}
16+
17+
func TestFlags_Parse(t *testing.T) {
18+
a := NewFlags().Parse()
19+
assert.IsType(t,
20+
Args{}, a)
21+
}
22+
23+
func TestArgs_Bool(t *testing.T) {
24+
for _, v := range [][3]interface{}{
25+
{&[]bool{false}[0], false, "it's false when false"},
26+
{&[]bool{true}[0], true, "it's true when true"},
27+
} {
28+
a := Args{"k": v[0]}
29+
assert.IsType(t, a.Bool("k"), v[1], v[2])
30+
}
31+
}
32+
33+
func TestArgs_String(t *testing.T) {
34+
for _, v := range [][3]interface{}{
35+
{&[]string{""}[0], "", "it's false when false"},
36+
} {
37+
a := Args{"k": v[0]}
38+
assert.IsType(t, a.String("k"), v[1], v[2])
39+
}
40+
}
41+
42+
// func TestArgs_Int(t *testing.T) {
43+
// for _, v := range [][3]interface{}{
44+
// {&[]int{1}[0], 1, "it's false when false"},
45+
// } {
46+
// a := Args{"k": v[0]}
47+
// assert.IsType(t, a.Int("k"), v[1], v[2])
48+
// }
49+
// }
50+
51+
func TestArgs_IsEmpty(t *testing.T) {
1452
for _, v := range [][3]interface{}{
1553
{nil, true, "is true on nil"},
1654
{"string", false, "it false on non-empty string"},
1755
{"", true, "it true on \"\""},
1856
} {
19-
args := Args{"k": v[0]}
20-
assert.Equal(t, args.IsEmpty("k"), v[1], v[2])
57+
a := Args{"k": v[0]}
58+
assert.Equal(t, a.IsEmpty("k"), v[1], v[2])
2159
}
2260
}

funcs.go

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -9,80 +9,70 @@ import (
99
"strconv"
1010
"strings"
1111
"text/template"
12-
)
1312

14-
type BoolFunc func(s string) bool
15-
type BoolFuncWithError func(s string) (bool, error)
16-
type StringFuncWithError func(s string) (string, error)
17-
type IntFuncWithError func(s string) (int, error)
18-
type StringFunc func(s string) string
19-
type IntFunc func(s string) int
13+
log "github.com/sirupsen/logrus"
14+
)
2015

2116
// func_trimStr trims a string for you... obviously
22-
func func_trimStr(t *template.Template) StringFunc {
23-
return func(s string) string {
24-
return strings.TrimSpace(s)
25-
}
17+
func (t *Template) _trimStr(s string) string {
18+
return strings.TrimSpace(s)
2619
}
2720

2821
// func_templateExists allows you to check if a
2922
// template exists inside of the templates, this also
3023
// works for context based {{ define "name" }}.
31-
func func_templateExists(t *template.Template) BoolFunc {
32-
return func(s string) bool {
33-
if tt := t.Lookup(s); tt != nil {
34-
return true
35-
}
36-
37-
return false
24+
func (t *Template) _templateExists(s string) bool {
25+
log.Debugf("looking for template %s", s)
26+
if tt := t.template.Lookup(s); tt != nil {
27+
return true
3828
}
29+
30+
return false
3931
}
4032

4133
// func_eExists allows you to check if a var exists
4234
// in your current environment, we do not alter it so
4335
// make sure you use FULLCAP if necessary.
44-
func func_eExists(t *template.Template) BoolFunc {
45-
return func(s string) bool {
46-
_, ok := os.LookupEnv(s)
47-
return ok
48-
}
36+
func (t *Template) _eExists(s string) bool {
37+
_, ok := os.LookupEnv(s)
38+
log.Debugf("checked if env %s exists", s)
39+
return ok
4940
}
5041

5142
// func_eStr allows you to pull out a string env var
52-
func func_eStr(t *template.Template) StringFunc {
53-
return func(s string) string {
54-
if v, ok := os.LookupEnv(s); ok {
55-
return v
56-
}
57-
58-
return ""
43+
func (t *Template) _eStr(s string) string {
44+
if v, ok := os.LookupEnv(s); ok {
45+
return v
5946
}
47+
48+
return ""
6049
}
6150

6251
// func_eBool allows you to pull out a env var as a
6352
// bool, following the same rules as strconv.ParseBool
6453
// where 1, true are true, and all else is false
65-
func func_eBool(t *template.Template) BoolFuncWithError {
66-
return func(s string) (bool, error) {
67-
if v, ok := os.LookupEnv(s); ok {
68-
vv, err := strconv.ParseBool(v)
69-
if err != nil {
70-
return false, err
71-
}
72-
73-
return vv, nil
54+
func (t *Template) _eBool(s string) (bool, error) {
55+
if v, ok := os.LookupEnv(s); ok {
56+
vv, err := strconv.ParseBool(v)
57+
if err != nil {
58+
return false, err
7459
}
7560

76-
return false, nil
61+
return vv, nil
7762
}
63+
64+
return false, nil
7865
}
7966

80-
func funcs(t *template.Template) template.FuncMap {
81-
return template.FuncMap{
82-
"eBool": func_eBool(t),
83-
"templateExists": func_templateExists(t),
84-
"eExists": func_eExists(t),
85-
"trimStr": func_trimStr(t),
86-
"eStr": func_eStr(t),
87-
}
67+
// setupFuncs attaches the funcs to the template
68+
func (t *Template) addFuncs() *Template {
69+
t.template.Funcs(template.FuncMap{
70+
"eBool": t._eBool,
71+
"templateExists": t._templateExists,
72+
"eExists": t._eExists,
73+
"trimStr": t._trimStr,
74+
"eStr": t._eStr,
75+
})
76+
77+
return t
8878
}

0 commit comments

Comments
 (0)