option.go 3.36 KB
Newer Older
Matt Bell's avatar
Matt Bell committed
1 2
package commands

3 4 5 6
import (
	"errors"
	"reflect"
)
Matt Bell's avatar
Matt Bell committed
7

8 9
var CastError = errors.New("cast error")

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
10
// Types of Command options
Matt Bell's avatar
Matt Bell committed
11
const (
Matt Bell's avatar
Matt Bell committed
12 13 14 15
	Invalid = reflect.Invalid
	Bool    = reflect.Bool
	Int     = reflect.Int
	Uint    = reflect.Uint
16
	Float   = reflect.Float64
Matt Bell's avatar
Matt Bell committed
17
	String  = reflect.String
Matt Bell's avatar
Matt Bell committed
18 19 20 21
)

// Option is used to specify a field that will be provided by a consumer
type Option struct {
22 23 24
	Names       []string     // a list of unique names to
	Type        reflect.Kind // value must be this type
	Description string       // a short string to describe this option
25

26
	// MAYBE_TODO: add more features(?):
Matt Bell's avatar
Matt Bell committed
27 28
	//Default interface{} // the default value (ignored if `Required` is true)
	//Required bool       // whether or not the option must be provided
Matt Bell's avatar
Matt Bell committed
29
}
30

31 32 33
// constructor helper functions
func NewOption(kind reflect.Kind, names ...string) Option {
	if len(names) < 2 {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
34
		// FIXME(btc) don't panic (fix_before_merge)
35 36 37 38
		panic("Options require at least two string values (name and description)")
	}

	desc := names[len(names)-1]
39
	names = names[:len(names)-1]
40 41 42 43 44 45 46 47

	return Option{
		Names:       names,
		Type:        kind,
		Description: desc,
	}
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
48 49 50 51 52 53
// TODO handle description separately. this will take care of the panic case in
// NewOption

// For all func {Type}Option(...string) functions, the last variadic argument
// is treated as the description field.

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
func BoolOption(names ...string) Option {
	return NewOption(Bool, names...)
}
func IntOption(names ...string) Option {
	return NewOption(Int, names...)
}
func UintOption(names ...string) Option {
	return NewOption(Uint, names...)
}
func FloatOption(names ...string) Option {
	return NewOption(Float, names...)
}
func StringOption(names ...string) Option {
	return NewOption(String, names...)
}

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
type OptionValue struct {
	value interface{}
	found bool
}

// Found returns true if the option value was provided by the user (not a default value)
func (ov OptionValue) Found() bool {
	return ov.found
}

// value accessor methods, gets the value as a certain type
func (ov OptionValue) Bool() (bool, error) {
	val, ok := ov.value.(bool)
	if !ok {
		var err error
		if ov.value != nil {
			err = errors.New("error casting to bool")
		}
		return false, err
	}
	return val, nil
}
func (ov OptionValue) Int() (int, error) {
	val, ok := ov.value.(int)
	if !ok {
		var err error
		if ov.value != nil {
			err = errors.New("error casting to int")
		}
		return 0, err
	}
	return val, nil
}
func (ov OptionValue) Uint() (uint, error) {
	val, ok := ov.value.(uint)
	if !ok {
		var err error
		if ov.value != nil {
			err = errors.New("error casting to uint")
		}
		return 0, err
	}
	return val, nil
}
func (ov OptionValue) Float() (float64, error) {
	val, ok := ov.value.(float64)
	if !ok {
		var err error
		if ov.value != nil {
			err = errors.New("error casting to float64")
		}
		return 0.0, err
	}
	return val, nil
}
func (ov OptionValue) String() (string, error) {
	val, ok := ov.value.(string)
	if !ok {
		var err error
		if ov.value != nil {
			err = errors.New("error casting to string")
		}
		return "", err
	}
	return val, nil
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
137 138 139 140 141 142
// Flag names
const (
	EncShort = "enc"
	EncLong  = "encoding"
)

143
// options that are used by this package
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
144
var globalOptions = []Option{
145 146
	Option{[]string{EncShort, EncLong}, String,
		"The encoding type the output should be encoded with (json, xml, or text)"},
147
}
Matt Bell's avatar
Matt Bell committed
148

149
// the above array of Options, wrapped in a Command
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
150
var globalCommand = &Command{
Matt Bell's avatar
Matt Bell committed
151
	Options: globalOptions,
152
}