lang: funcs: simple: Add a function from struct generator
This is a helper function that can generate a bunch of functions from a struct type. This is most useful when using a CLI args struct for command line parsing and then storing the values as functions. An alternative version of this might choose to return all of the values as a single giant struct.
This commit is contained in:
@@ -32,6 +32,8 @@ package simple
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/purpleidea/mgmt/lang/funcs"
|
"github.com/purpleidea/mgmt/lang/funcs"
|
||||||
"github.com/purpleidea/mgmt/lang/interfaces"
|
"github.com/purpleidea/mgmt/lang/interfaces"
|
||||||
@@ -196,3 +198,67 @@ func (obj *WrappedFunc) Stream(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StructRegister takes an CLI args struct with optional struct tags, and
|
||||||
|
// generates simple functions from the contained fields in the specified
|
||||||
|
// namespace. If no struct field named `func` is included, then a default
|
||||||
|
// function name which is the lower case representation of the field name will
|
||||||
|
// be used, otherwise the struct tag contents are used. If the struct tag
|
||||||
|
// contains the `-` character, then the field will be skipped.
|
||||||
|
// TODO: An alternative version of this might choose to return all of the values
|
||||||
|
// as a single giant struct.
|
||||||
|
func StructRegister(moduleName string, args interface{}) error {
|
||||||
|
if args == nil {
|
||||||
|
// programming error
|
||||||
|
return fmt.Errorf("could not convert/access our struct")
|
||||||
|
}
|
||||||
|
//fmt.Printf("A: %+v\n", args)
|
||||||
|
|
||||||
|
val := reflect.ValueOf(args)
|
||||||
|
if val.Kind() == reflect.Ptr { // max one de-referencing
|
||||||
|
val = val.Elem()
|
||||||
|
}
|
||||||
|
typ := val.Type()
|
||||||
|
|
||||||
|
for i := 0; i < typ.NumField(); i++ {
|
||||||
|
v := val.Field(i) // value of the field
|
||||||
|
t := typ.Field(i) // struct type, get real type with .Type
|
||||||
|
|
||||||
|
name := strings.ToLower(t.Name) // default
|
||||||
|
if alias, ok := t.Tag.Lookup("func"); ok {
|
||||||
|
if alias == "-" { // skip
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name = alias
|
||||||
|
}
|
||||||
|
//fmt.Printf("N: %+v\n", name) // debug
|
||||||
|
if len(strings.Trim(name, "abcdefghijklmnopqrstuvwxyz_")) > 0 {
|
||||||
|
return fmt.Errorf("struct field index(%d) has invalid char(s) in function name", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
typed, err := types.TypeOf(t.Type) // reflect.Type -> (*types.Type, error)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//fmt.Printf("T: %+v\n", typed.String()) // debug
|
||||||
|
|
||||||
|
ModuleRegister(moduleName, name, &types.FuncValue{
|
||||||
|
T: types.NewType(fmt.Sprintf("func() %s", typed.String())),
|
||||||
|
V: func(input []types.Value) (types.Value, error) {
|
||||||
|
//if args == nil {
|
||||||
|
// // programming error
|
||||||
|
// return nil, fmt.Errorf("could not convert/access our struct")
|
||||||
|
//}
|
||||||
|
|
||||||
|
value, err := types.ValueOf(v) // reflect.Value -> (types.Value, error)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrapf(err, "func `%s.%s()` has nil value", moduleName, name)
|
||||||
|
}
|
||||||
|
//fmt.Printf("V: %+v\n", value) // debug
|
||||||
|
return value, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user