diff --git a/modules/digitalocean/display.go b/modules/digitalocean/display.go index 5d14636a..ea85e96b 100644 --- a/modules/digitalocean/display.go +++ b/modules/digitalocean/display.go @@ -44,7 +44,11 @@ func (widget *Widget) content() (string, string, bool) { // Dynamically access the droplet to get the requested columns values for _, colName := range columnSet { - val := droplet.ValueForColumn(colName) + val, err := droplet.StringValueForProperty(colName) + if err != nil { + val = "???" + } + truncVal := utils.Truncate(val, maxColWidth, false) vals = append(vals, truncVal) diff --git a/modules/digitalocean/droplet.go b/modules/digitalocean/droplet.go index 85dafb74..e4e49fc3 100644 --- a/modules/digitalocean/droplet.go +++ b/modules/digitalocean/droplet.go @@ -6,10 +6,9 @@ import ( "strings" "github.com/digitalocean/godo" + "github.com/wtfutil/wtf/utils" ) -const invalidColumn = "???" - // Droplet represents WTF's view of a DigitalOcean droplet type Droplet struct { godo.Droplet @@ -21,11 +20,13 @@ type Droplet struct { // Image represents WTF's view of a DigitalOcean droplet image type Image struct { godo.Image + utils.Reflective } // Region represents WTF's view of a DigitalOcean region type Region struct { godo.Region + utils.Reflective } // NewDroplet creates and returns an instance of Droplet @@ -35,10 +36,12 @@ func NewDroplet(doDroplet godo.Droplet) *Droplet { Image{ *doDroplet.Image, + utils.Reflective{}, }, Region{ *doDroplet.Region, + utils.Reflective{}, }, } @@ -47,58 +50,31 @@ func NewDroplet(doDroplet godo.Droplet) *Droplet { /* -------------------- Exported Functions -------------------- */ -// ValueForColumn returns a string value for the given column -func (drop *Droplet) ValueForColumn(colName string) string { - r := reflect.ValueOf(drop) - f := reflect.Indirect(r).FieldByName(colName) - +// StringValueForProperty returns a string value for the given column +func (drop *Droplet) StringValueForProperty(propName string) (string, error) { var strVal string + var err error // Figure out if we should forward this property to a sub-object // Lets us support "Region.Name" column definitions - split := strings.Split(colName, ".") + split := strings.Split(propName, ".") switch split[0] { case "Image": - strVal = drop.Image.ValueForColumn(split[1]) + strVal, err = drop.Image.StringValueForProperty(split[1]) case "Region": - strVal = drop.Region.ValueForColumn(split[1]) + strVal, err = drop.Region.StringValueForProperty(split[1]) default: - if !f.IsValid() { - strVal = invalidColumn + v := reflect.ValueOf(drop) + refVal := reflect.Indirect(v).FieldByName(propName) + + if !refVal.IsValid() { + err = fmt.Errorf("invalid property name: %s", propName) } else { - strVal = fmt.Sprintf("%v", f) + strVal = fmt.Sprintf("%v", refVal) } } - return strVal -} - -// ValueForColumn returns a string value for the given column -func (reg *Image) ValueForColumn(colName string) string { - r := reflect.ValueOf(reg) - f := reflect.Indirect(r).FieldByName(colName) - - if !f.IsValid() { - return invalidColumn - } - - strVal := fmt.Sprintf("%v", f) - - return strVal -} - -// ValueForColumn returns a string value for the given column -func (reg *Region) ValueForColumn(colName string) string { - r := reflect.ValueOf(reg) - f := reflect.Indirect(r).FieldByName(colName) - - if !f.IsValid() { - return invalidColumn - } - - strVal := fmt.Sprintf("%v", f) - - return strVal + return strVal, err } diff --git a/utils/reflective.go b/utils/reflective.go new file mode 100644 index 00000000..0e5037a4 --- /dev/null +++ b/utils/reflective.go @@ -0,0 +1,25 @@ +package utils + +import ( + "fmt" + "reflect" +) + +// Reflective is a convenience wrapper for objects that makes it possible to +// extract property values from the object by property name +type Reflective struct{} + +// StringValueForProperty returns a string value for the given property +// If the property doesn't exist, it returns an error +func (ref *Reflective) StringValueForProperty(propName string) (string, error) { + v := reflect.ValueOf(ref) + refVal := reflect.Indirect(v).FieldByName(propName) + + if !refVal.IsValid() { + return "", fmt.Errorf("invalid property name: %s", propName) + } + + strVal := fmt.Sprintf("%v", refVal) + + return strVal, nil +}