lang: funcs: Improve template function
Template function should be able to be called with just one arg (no input vars) and we should correctly use the known arg name and not the string "a" or "b".
This commit is contained in:
@@ -58,7 +58,12 @@ const (
|
|||||||
// TODO: We *might* need to add events for internal function changes over time,
|
// TODO: We *might* need to add events for internal function changes over time,
|
||||||
// but only if they are not pure. We currently only use simple, pure functions.
|
// but only if they are not pure. We currently only use simple, pure functions.
|
||||||
type TemplateFunc struct {
|
type TemplateFunc struct {
|
||||||
|
// Type is the type of the input vars (2nd) arg if one is specified. Nil
|
||||||
|
// is the special undetermined value that is used before type is known.
|
||||||
Type *types.Type // type of vars
|
Type *types.Type // type of vars
|
||||||
|
// NoVars is set to true instead of specifying Type if we have a boring
|
||||||
|
// template that takes no args.
|
||||||
|
NoVars bool
|
||||||
|
|
||||||
init *interfaces.Init
|
init *interfaces.Init
|
||||||
last types.Value // last value received to use for diff
|
last types.Value // last value received to use for diff
|
||||||
@@ -100,17 +105,20 @@ func (obj *TemplateFunc) Polymorphisms(partialType *types.Type, partialValues []
|
|||||||
|
|
||||||
ord := partialType.Ord
|
ord := partialType.Ord
|
||||||
if partialType.Map != nil {
|
if partialType.Map != nil {
|
||||||
if len(ord) != 2 {
|
if len(ord) != 2 && len(ord) != 1 {
|
||||||
return nil, fmt.Errorf("must have exactly two args in template func")
|
return nil, fmt.Errorf("must have exactly one or two args in template func")
|
||||||
}
|
}
|
||||||
if t, exists := partialType.Map[ord[0]]; exists && t != nil {
|
if t, exists := partialType.Map[ord[0]]; exists && t != nil {
|
||||||
if t.Cmp(types.TypeStr) != nil {
|
if t.Cmp(types.TypeStr) != nil {
|
||||||
return nil, fmt.Errorf("first arg for template must be an str")
|
return nil, fmt.Errorf("first arg for template must be an str")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t, exists := partialType.Map[ord[1]]; exists && t != nil {
|
if len(ord) == 1 { // no args being passed in (boring template)
|
||||||
|
return []*types.Type{types.NewType(fmt.Sprintf("func(%s str) str", argNameTemplate))}, nil
|
||||||
|
|
||||||
|
} else if t, exists := partialType.Map[ord[1]]; exists && t != nil {
|
||||||
// known vars type! w00t!
|
// known vars type! w00t!
|
||||||
return []*types.Type{types.NewType(fmt.Sprintf("func(a str, b %s) str", t.String()))}, nil
|
return []*types.Type{types.NewType(fmt.Sprintf("func(%s str, %s %s) str", argNameTemplate, argNameVars, t.String()))}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,8 +133,8 @@ func (obj *TemplateFunc) Build(typ *types.Type) error {
|
|||||||
if typ.Kind != types.KindFunc {
|
if typ.Kind != types.KindFunc {
|
||||||
return fmt.Errorf("input type must be of kind func")
|
return fmt.Errorf("input type must be of kind func")
|
||||||
}
|
}
|
||||||
if len(typ.Ord) != 2 {
|
if len(typ.Ord) != 2 && len(typ.Ord) != 1 {
|
||||||
return fmt.Errorf("the template function needs exactly two args")
|
return fmt.Errorf("the template function needs exactly one or two args")
|
||||||
}
|
}
|
||||||
if typ.Out == nil {
|
if typ.Out == nil {
|
||||||
return fmt.Errorf("return type of function must be specified")
|
return fmt.Errorf("return type of function must be specified")
|
||||||
@@ -146,6 +154,11 @@ func (obj *TemplateFunc) Build(typ *types.Type) error {
|
|||||||
return fmt.Errorf("first arg for template must be an str")
|
return fmt.Errorf("first arg for template must be an str")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(typ.Ord) == 1 { // no args being passed in (boring template)
|
||||||
|
obj.NoVars = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
t1, exists := typ.Map[typ.Ord[1]]
|
t1, exists := typ.Map[typ.Ord[1]]
|
||||||
if !exists || t1 == nil {
|
if !exists || t1 == nil {
|
||||||
return fmt.Errorf("second arg must be specified")
|
return fmt.Errorf("second arg must be specified")
|
||||||
@@ -158,7 +171,7 @@ func (obj *TemplateFunc) Build(typ *types.Type) error {
|
|||||||
// Validate makes sure we've built our struct properly. It is usually unused for
|
// Validate makes sure we've built our struct properly. It is usually unused for
|
||||||
// normal functions that users can use directly.
|
// normal functions that users can use directly.
|
||||||
func (obj *TemplateFunc) Validate() error {
|
func (obj *TemplateFunc) Validate() error {
|
||||||
if obj.Type == nil { // build must be run first
|
if obj.Type == nil && !obj.NoVars { // build must be run first
|
||||||
return fmt.Errorf("type is still unspecified")
|
return fmt.Errorf("type is still unspecified")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -167,7 +180,11 @@ func (obj *TemplateFunc) Validate() error {
|
|||||||
// Info returns some static info about itself.
|
// Info returns some static info about itself.
|
||||||
func (obj *TemplateFunc) Info() *interfaces.Info {
|
func (obj *TemplateFunc) Info() *interfaces.Info {
|
||||||
var sig *types.Type
|
var sig *types.Type
|
||||||
if obj.Type != nil { // don't panic if called speculatively
|
if obj.NoVars {
|
||||||
|
str := fmt.Sprintf("func(%s str) str", argNameTemplate)
|
||||||
|
sig = types.NewType(str)
|
||||||
|
|
||||||
|
} else if obj.Type != nil { // don't panic if called speculatively
|
||||||
str := fmt.Sprintf("func(%s str, %s %s) str", argNameTemplate, argNameVars, obj.Type.String())
|
str := fmt.Sprintf("func(%s str, %s %s) str", argNameTemplate, argNameVars, obj.Type.String())
|
||||||
sig = types.NewType(str)
|
sig = types.NewType(str)
|
||||||
}
|
}
|
||||||
@@ -235,6 +252,15 @@ func (obj *TemplateFunc) run(templateText string, vars types.Value) (string, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
if vars == nil {
|
||||||
|
// run the template
|
||||||
|
if err := tmpl.Execute(buf, nil); err != nil {
|
||||||
|
return "", errwrap.Wrapf(err, "template: execution error")
|
||||||
|
}
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: any objects in here can have their methods called by the template!
|
// NOTE: any objects in here can have their methods called by the template!
|
||||||
var data interface{} // can be many types, eg a struct!
|
var data interface{} // can be many types, eg a struct!
|
||||||
v := vars.Copy() // make a copy since we make modifications to it...
|
v := vars.Copy() // make a copy since we make modifications to it...
|
||||||
@@ -314,8 +340,13 @@ func (obj *TemplateFunc) Stream() error {
|
|||||||
}
|
}
|
||||||
obj.last = input // store for next
|
obj.last = input // store for next
|
||||||
|
|
||||||
tmpl := input.Struct()[argNameTemplate].Str()
|
st := input.Struct()
|
||||||
vars := input.Struct()[argNameVars]
|
|
||||||
|
tmpl := st[argNameTemplate].Str()
|
||||||
|
vars, exists := st[argNameVars]
|
||||||
|
if !exists {
|
||||||
|
vars = nil
|
||||||
|
}
|
||||||
|
|
||||||
result, err := obj.run(tmpl, vars)
|
result, err := obj.run(tmpl, vars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user