Merge pull request #1096 from hashicorp/f-sprintf
config: add "format' function [GH-758]
This commit is contained in:
commit
23609a7af5
|
@ -17,6 +17,7 @@ var Funcs map[string]ast.Function
|
|||
func init() {
|
||||
Funcs = map[string]ast.Function{
|
||||
"file": interpolationFuncFile(),
|
||||
"format": interpolationFuncFormat(),
|
||||
"join": interpolationFuncJoin(),
|
||||
"element": interpolationFuncElement(),
|
||||
"replace": interpolationFuncReplace(),
|
||||
|
@ -66,6 +67,21 @@ func interpolationFuncFile() ast.Function {
|
|||
}
|
||||
}
|
||||
|
||||
// interpolationFuncFormat implements the "replace" function that does
|
||||
// string replacement.
|
||||
func interpolationFuncFormat() ast.Function {
|
||||
return ast.Function{
|
||||
ArgTypes: []ast.Type{ast.TypeString},
|
||||
Variadic: true,
|
||||
VariadicType: ast.TypeAny,
|
||||
ReturnType: ast.TypeString,
|
||||
Callback: func(args []interface{}) (interface{}, error) {
|
||||
format := args[0].(string)
|
||||
return fmt.Sprintf(format, args[1:]...), nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// interpolationFuncJoin implements the "join" function that allows
|
||||
// multi-variable values to be joined by some character.
|
||||
func interpolationFuncJoin() ast.Function {
|
||||
|
|
|
@ -70,6 +70,42 @@ func TestInterpolateFuncFile(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestInterpolateFuncFormat(t *testing.T) {
|
||||
testFunction(t, testFunctionConfig{
|
||||
Cases: []testFunctionCase{
|
||||
{
|
||||
`${format("hello")}`,
|
||||
"hello",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
`${format("hello %s", "world")}`,
|
||||
"hello world",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
`${format("hello %d", 42)}`,
|
||||
"hello 42",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
`${format("hello %05d", 42)}`,
|
||||
"hello 00042",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
`${format("hello %05d", 12345)}`,
|
||||
"hello 12345",
|
||||
false,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestInterpolateFuncJoin(t *testing.T) {
|
||||
testFunction(t, testFunctionConfig{
|
||||
Cases: []testFunctionCase{
|
||||
|
|
|
@ -48,7 +48,8 @@ type Type uint32
|
|||
|
||||
const (
|
||||
TypeInvalid Type = 0
|
||||
TypeString Type = 1 << iota
|
||||
TypeAny Type = 1 << iota
|
||||
TypeString
|
||||
TypeInt
|
||||
TypeFloat
|
||||
)
|
||||
|
|
|
@ -6,16 +6,18 @@ import "fmt"
|
|||
|
||||
const (
|
||||
_Type_name_0 = "TypeInvalid"
|
||||
_Type_name_1 = "TypeString"
|
||||
_Type_name_2 = "TypeInt"
|
||||
_Type_name_3 = "TypeFloat"
|
||||
_Type_name_1 = "TypeAny"
|
||||
_Type_name_2 = "TypeString"
|
||||
_Type_name_3 = "TypeInt"
|
||||
_Type_name_4 = "TypeFloat"
|
||||
)
|
||||
|
||||
var (
|
||||
_Type_index_0 = [...]uint8{0, 11}
|
||||
_Type_index_1 = [...]uint8{0, 10}
|
||||
_Type_index_2 = [...]uint8{0, 7}
|
||||
_Type_index_3 = [...]uint8{0, 9}
|
||||
_Type_index_1 = [...]uint8{0, 7}
|
||||
_Type_index_2 = [...]uint8{0, 10}
|
||||
_Type_index_3 = [...]uint8{0, 7}
|
||||
_Type_index_4 = [...]uint8{0, 9}
|
||||
)
|
||||
|
||||
func (i Type) String() string {
|
||||
|
@ -28,6 +30,8 @@ func (i Type) String() string {
|
|||
return _Type_name_2
|
||||
case i == 8:
|
||||
return _Type_name_3
|
||||
case i == 16:
|
||||
return _Type_name_4
|
||||
default:
|
||||
return fmt.Sprintf("Type(%d)", i)
|
||||
}
|
||||
|
|
|
@ -174,6 +174,10 @@ func (tc *typeCheckCall) TypeCheck(v *TypeCheck) (ast.Node, error) {
|
|||
|
||||
// Verify the args
|
||||
for i, expected := range function.ArgTypes {
|
||||
if expected == ast.TypeAny {
|
||||
continue
|
||||
}
|
||||
|
||||
if args[i] != expected {
|
||||
cn := v.ImplicitConversion(args[i], expected, tc.n.Args[i])
|
||||
if cn != nil {
|
||||
|
@ -188,7 +192,7 @@ func (tc *typeCheckCall) TypeCheck(v *TypeCheck) (ast.Node, error) {
|
|||
}
|
||||
|
||||
// If we're variadic, then verify the types there
|
||||
if function.Variadic {
|
||||
if function.Variadic && function.VariadicType != ast.TypeAny {
|
||||
args = args[len(function.ArgTypes):]
|
||||
for i, t := range args {
|
||||
if t != function.VariadicType {
|
||||
|
|
|
@ -80,6 +80,12 @@ The supported built-in functions are:
|
|||
in this file are _not_ interpolated. The contents of the file are
|
||||
read as-is.
|
||||
|
||||
* `format(format, args...)` - Formats a string according to the given
|
||||
format. The syntax for the format is standard `sprintf` syntax.
|
||||
Good documentation for the syntax can be [found here](http://golang.org/pkg/fmt/).
|
||||
Example to zero-prefix a count, used commonly for naming servers:
|
||||
`format("web-%03d", count.index+1)`.
|
||||
|
||||
* `join(delim, list)` - Joins the list with the delimiter. A list is
|
||||
only possible with splat variables from resources with a count
|
||||
greater than one. Example: `join(",", aws_instance.foo.*.id)`
|
||||
|
|
Loading…
Reference in New Issue