porting many functions
This commit is contained in:
parent
083ea05295
commit
10ef61c71c
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/function"
|
||||
"github.com/zclconf/go-cty/cty/gocty"
|
||||
)
|
||||
|
||||
var JoinFunc = function.New(&function.Spec{
|
||||
|
@ -126,6 +127,99 @@ var ChompFunc = function.New(&function.Spec{
|
|||
},
|
||||
})
|
||||
|
||||
// IndentFunc constructions a function that adds a given number of spaces to the
|
||||
// beginnings of all but the first line in a given multi-line string.
|
||||
var IndentFunc = function.New(&function.Spec{
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "spaces",
|
||||
Type: cty.Number,
|
||||
},
|
||||
{
|
||||
Name: "str",
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
Type: function.StaticReturnType(cty.String),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
var spaces int
|
||||
if err := gocty.FromCtyValue(args[0], &spaces); err != nil {
|
||||
return cty.UnknownVal(cty.String), err
|
||||
}
|
||||
data := args[1].AsString()
|
||||
pad := strings.Repeat(" ", spaces)
|
||||
return cty.StringVal(strings.Replace(data, "\n", "\n"+pad, -1)), nil
|
||||
},
|
||||
})
|
||||
|
||||
// ReplaceFunc constructions a function that searches a given string for another
|
||||
// given substring, and replaces each occurence with a given replacement string.
|
||||
var ReplaceFunc = function.New(&function.Spec{
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "str",
|
||||
Type: cty.String,
|
||||
},
|
||||
{
|
||||
Name: "substr",
|
||||
Type: cty.String,
|
||||
},
|
||||
{
|
||||
Name: "replace",
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
Type: function.StaticReturnType(cty.String),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
str := args[0].AsString()
|
||||
substr := args[1].AsString()
|
||||
replace := args[2].AsString()
|
||||
|
||||
// We search/replace using a regexp if the string is surrounded
|
||||
// in forward slashes.
|
||||
if len(substr) > 1 && substr[0] == '/' && substr[len(substr)-1] == '/' {
|
||||
re, err := regexp.Compile(substr[1 : len(substr)-1])
|
||||
if err != nil {
|
||||
return cty.UnknownVal(cty.String), err
|
||||
}
|
||||
|
||||
return cty.StringVal(re.ReplaceAllString(str, replace)), nil
|
||||
}
|
||||
|
||||
return cty.StringVal(strings.Replace(str, substr, replace, -1)), nil
|
||||
},
|
||||
})
|
||||
|
||||
// TitleFunc constructions a function that converts the first letter of each word
|
||||
// in the given string to uppercase.
|
||||
var TitleFunc = function.New(&function.Spec{
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "str",
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
Type: function.StaticReturnType(cty.String),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
return cty.StringVal(strings.Title(args[0].AsString())), nil
|
||||
},
|
||||
})
|
||||
|
||||
// TrimSpaceFunc constructions a function that removes any space characters from
|
||||
// the start and end of the given string.
|
||||
var TrimSpaceFunc = function.New(&function.Spec{
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "str",
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
Type: function.StaticReturnType(cty.String),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
return cty.StringVal(strings.TrimSpace(args[0].AsString())), nil
|
||||
},
|
||||
})
|
||||
|
||||
// Join concatenates together the string elements of one or more lists with a
|
||||
// given separator.
|
||||
func Join(sep cty.Value, lists ...cty.Value) (cty.Value, error) {
|
||||
|
@ -151,3 +245,25 @@ func Split(sep, str cty.Value) (cty.Value, error) {
|
|||
func Chomp(str cty.Value) (cty.Value, error) {
|
||||
return ChompFunc.Call([]cty.Value{str})
|
||||
}
|
||||
|
||||
// Indent adds a given number of spaces to the beginnings of all but the first
|
||||
// line in a given multi-line string.
|
||||
func Indent(spaces, str cty.Value) (cty.Value, error) {
|
||||
return IndentFunc.Call([]cty.Value{spaces, str})
|
||||
}
|
||||
|
||||
// Replace searches a given string for another given substring,
|
||||
// and replaces all occurences with a given replacement string.
|
||||
func Replace(str, substr, replace cty.Value) (cty.Value, error) {
|
||||
return ReplaceFunc.Call([]cty.Value{str, substr, replace})
|
||||
}
|
||||
|
||||
// Title converts the first letter of each word in the given string to uppercase.
|
||||
func Title(str cty.Value) (cty.Value, error) {
|
||||
return TitleFunc.Call([]cty.Value{str})
|
||||
}
|
||||
|
||||
// TrimSpace removes any space characters from the start and end of the given string.
|
||||
func TrimSpace(str cty.Value) (cty.Value, error) {
|
||||
return TrimSpaceFunc.Call([]cty.Value{str})
|
||||
}
|
||||
|
|
|
@ -307,3 +307,202 @@ func TestChomp(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndent(t *testing.T) {
|
||||
tests := []struct {
|
||||
String cty.Value
|
||||
Spaces cty.Value
|
||||
Want cty.Value
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
cty.StringVal(`Fleas:
|
||||
Adam
|
||||
Had'em
|
||||
|
||||
E.E. Cummings`),
|
||||
cty.NumberIntVal(4),
|
||||
cty.StringVal("Fleas:\n Adam\n Had'em\n \n E.E. Cummings"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("oneliner"),
|
||||
cty.NumberIntVal(4),
|
||||
cty.StringVal("oneliner"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal(`#!/usr/bin/env bash
|
||||
date
|
||||
pwd`),
|
||||
cty.NumberIntVal(4),
|
||||
cty.StringVal("#!/usr/bin/env bash\n date\n pwd"),
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("indent(%#v, %#v)", test.Spaces, test.String), func(t *testing.T) {
|
||||
got, err := Indent(test.Spaces, test.String)
|
||||
|
||||
if test.Err {
|
||||
if err == nil {
|
||||
t.Fatal("succeeded; want error")
|
||||
}
|
||||
return
|
||||
} else if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if !got.RawEquals(test.Want) {
|
||||
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplace(t *testing.T) {
|
||||
tests := []struct {
|
||||
String cty.Value
|
||||
Substr cty.Value
|
||||
Replace cty.Value
|
||||
Want cty.Value
|
||||
Err bool
|
||||
}{
|
||||
{ // Regular search and replace
|
||||
cty.StringVal("hello"),
|
||||
cty.StringVal("hel"),
|
||||
cty.StringVal("bel"),
|
||||
cty.StringVal("bello"),
|
||||
false,
|
||||
},
|
||||
{ // Search string doesn't match
|
||||
cty.StringVal("hello"),
|
||||
cty.StringVal("nope"),
|
||||
cty.StringVal("bel"),
|
||||
cty.StringVal("hello"),
|
||||
false,
|
||||
},
|
||||
{ // Regular expression
|
||||
cty.StringVal("hello"),
|
||||
cty.StringVal("/l/"),
|
||||
cty.StringVal("L"),
|
||||
cty.StringVal("heLLo"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("helo"),
|
||||
cty.StringVal("/(l)/"),
|
||||
cty.StringVal("$1$1"),
|
||||
cty.StringVal("hello"),
|
||||
false,
|
||||
},
|
||||
{ // Bad regexp
|
||||
cty.StringVal("hello"),
|
||||
cty.StringVal("/(l/"),
|
||||
cty.StringVal("$1$1"),
|
||||
cty.UnknownVal(cty.String),
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("replace(%#v, %#v, %#v)", test.String, test.Substr, test.Replace), func(t *testing.T) {
|
||||
got, err := Replace(test.String, test.Substr, test.Replace)
|
||||
|
||||
if test.Err {
|
||||
if err == nil {
|
||||
t.Fatal("succeeded; want error")
|
||||
}
|
||||
return
|
||||
} else if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if !got.RawEquals(test.Want) {
|
||||
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTitle(t *testing.T) {
|
||||
tests := []struct {
|
||||
String cty.Value
|
||||
Want cty.Value
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
cty.StringVal("hello"),
|
||||
cty.StringVal("Hello"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("hello world"),
|
||||
cty.StringVal("Hello World"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal(""),
|
||||
cty.StringVal(""),
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("title(%#v)", test.String), func(t *testing.T) {
|
||||
got, err := Title(test.String)
|
||||
|
||||
if test.Err {
|
||||
if err == nil {
|
||||
t.Fatal("succeeded; want error")
|
||||
}
|
||||
return
|
||||
} else if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if !got.RawEquals(test.Want) {
|
||||
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrimSpace(t *testing.T) {
|
||||
tests := []struct {
|
||||
String cty.Value
|
||||
Want cty.Value
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
cty.StringVal(" hello "),
|
||||
cty.StringVal("hello"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal(""),
|
||||
cty.StringVal(""),
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("trimspace(%#v)", test.String), func(t *testing.T) {
|
||||
got, err := TrimSpace(test.String)
|
||||
|
||||
if test.Err {
|
||||
if err == nil {
|
||||
t.Fatal("succeeded; want error")
|
||||
}
|
||||
return
|
||||
} else if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if !got.RawEquals(test.Want) {
|
||||
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ func (s *Scope) Functions() map[string]function.Function {
|
|||
"format": stdlib.FormatFunc,
|
||||
"formatlist": stdlib.FormatListFunc,
|
||||
"indent": unimplFunc, // TODO
|
||||
"index": unimplFunc, // TODO
|
||||
"index": funcs.IndentFunc,
|
||||
"join": funcs.JoinFunc,
|
||||
"jsondecode": stdlib.JSONDecodeFunc,
|
||||
"jsonencode": stdlib.JSONEncodeFunc,
|
||||
|
@ -77,7 +77,7 @@ func (s *Scope) Functions() map[string]function.Function {
|
|||
"min": stdlib.MinFunc,
|
||||
"pathexpand": funcs.PathExpandFunc,
|
||||
"pow": funcs.PowFunc,
|
||||
"replace": unimplFunc, // TODO
|
||||
"replace": funcs.ReplaceFunc,
|
||||
"rsadecrypt": funcs.RsaDecryptFunc,
|
||||
"sha1": funcs.Sha1Func,
|
||||
"sha256": funcs.Sha256Func,
|
||||
|
@ -89,9 +89,9 @@ func (s *Scope) Functions() map[string]function.Function {
|
|||
"substr": stdlib.SubstrFunc,
|
||||
"timestamp": funcs.TimestampFunc,
|
||||
"timeadd": funcs.TimeAddFunc,
|
||||
"title": unimplFunc, // TODO
|
||||
"title": funcs.TitleFunc,
|
||||
"transpose": unimplFunc, // TODO
|
||||
"trimspace": unimplFunc, // TODO
|
||||
"trimspace": funcs.TrimSpace,
|
||||
"upper": stdlib.UpperFunc,
|
||||
"urlencode": funcs.URLEncodeFunc,
|
||||
"uuid": funcs.UUIDFunc,
|
||||
|
|
Loading…
Reference in New Issue