add more strings functions to text module
This commit is contained in:
parent
69a703bea2
commit
309b03bb30
5 changed files with 414 additions and 4 deletions
|
@ -395,6 +395,31 @@ func FuncASRS(fn func(string) string) *objects.UserFunction {
|
|||
}
|
||||
}
|
||||
|
||||
// FuncASRSs transform a function of 'func(string) []string' signature into a user function object.
|
||||
func FuncASRSs(fn func(string) []string) *objects.UserFunction {
|
||||
return &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 1 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
s1, ok := objects.ToString(args[0])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
res := fn(s1)
|
||||
|
||||
arr := &objects.Array{}
|
||||
for _, osArg := range res {
|
||||
arr.Value = append(arr.Value, &objects.String{Value: osArg})
|
||||
}
|
||||
|
||||
return arr, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FuncASRSE transform a function of 'func(string) (string, error)' signature into a user function object.
|
||||
// User function will return 'true' if underlying native function returns nil.
|
||||
func FuncASRSE(fn func(string) (string, error)) *objects.UserFunction {
|
||||
|
@ -462,6 +487,171 @@ func FuncASSRE(fn func(string, string) error) *objects.UserFunction {
|
|||
}
|
||||
}
|
||||
|
||||
// FuncASSRSs transform a function of 'func(string, string) []string' signature into a user function object.
|
||||
func FuncASSRSs(fn func(string, string) []string) *objects.UserFunction {
|
||||
return &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 2 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
s1, ok := objects.ToString(args[0])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
s2, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
arr := &objects.Array{}
|
||||
for _, res := range fn(s1, s2) {
|
||||
arr.Value = append(arr.Value, &objects.String{Value: res})
|
||||
}
|
||||
|
||||
return arr, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FuncASSIRSs transform a function of 'func(string, string, int) []string' signature into a user function object.
|
||||
func FuncASSIRSs(fn func(string, string, int) []string) *objects.UserFunction {
|
||||
return &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 3 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
s1, ok := objects.ToString(args[0])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
s2, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
i3, ok := objects.ToInt(args[2])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
arr := &objects.Array{}
|
||||
for _, res := range fn(s1, s2, i3) {
|
||||
arr.Value = append(arr.Value, &objects.String{Value: res})
|
||||
}
|
||||
|
||||
return arr, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FuncASSRI transform a function of 'func(string, string) int' signature into a user function object.
|
||||
func FuncASSRI(fn func(string, string) int) *objects.UserFunction {
|
||||
return &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 2 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
s1, ok := objects.ToString(args[0])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
s2, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
return &objects.Int{Value: int64(fn(s1, s2))}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FuncASSRS transform a function of 'func(string, string) string' signature into a user function object.
|
||||
func FuncASSRS(fn func(string, string) string) *objects.UserFunction {
|
||||
return &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 2 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
s1, ok := objects.ToString(args[0])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
s2, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
return &objects.String{Value: fn(s1, s2)}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FuncASSRB transform a function of 'func(string, string) bool' signature into a user function object.
|
||||
func FuncASSRB(fn func(string, string) bool) *objects.UserFunction {
|
||||
return &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 2 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
s1, ok := objects.ToString(args[0])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
s2, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
if fn(s1, s2) {
|
||||
return objects.TrueValue, nil
|
||||
}
|
||||
|
||||
return objects.FalseValue, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FuncASsSRS transform a function of 'func([]string, string) string' signature into a user function object.
|
||||
func FuncASsSRS(fn func([]string, string) string) *objects.UserFunction {
|
||||
return &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (objects.Object, error) {
|
||||
if len(args) != 2 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
var ss1 []string
|
||||
arr, ok := args[0].(*objects.Array)
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
for _, a := range arr.Value {
|
||||
as, ok := objects.ToString(a)
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
ss1 = append(ss1, as)
|
||||
}
|
||||
|
||||
s2, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
return &objects.String{Value: fn(ss1, s2)}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FuncASI64RE transform a function of 'func(string, int64) error' signature
|
||||
// into a user function object.
|
||||
func FuncASI64RE(fn func(string, int64) error) *objects.UserFunction {
|
||||
|
@ -510,6 +700,30 @@ func FuncAIIRE(fn func(int, int) error) *objects.UserFunction {
|
|||
}
|
||||
}
|
||||
|
||||
// FuncASIRS transform a function of 'func(string, int) string' signature
|
||||
// into a user function object.
|
||||
func FuncASIRS(fn func(string, int) string) *objects.UserFunction {
|
||||
return &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||
if len(args) != 2 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
s1, ok := objects.ToString(args[0])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
i2, ok := objects.ToInt(args[1])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
return &objects.String{Value: fn(s1, i2)}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FuncASIIRE transform a function of 'func(string, int, int) error' signature
|
||||
// into a user function object.
|
||||
func FuncASIIRE(fn func(string, int, int) error) *objects.UserFunction {
|
||||
|
@ -607,8 +821,8 @@ func FuncAIRSsE(fn func(int) ([]string, error)) *objects.UserFunction {
|
|||
}
|
||||
|
||||
arr := &objects.Array{}
|
||||
for _, osArg := range res {
|
||||
arr.Value = append(arr.Value, &objects.String{Value: osArg})
|
||||
for _, r := range res {
|
||||
arr.Value = append(arr.Value, &objects.String{Value: r})
|
||||
}
|
||||
|
||||
return arr, nil
|
||||
|
|
|
@ -2,6 +2,8 @@ package stdlib_test
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/d5/tengo/assert"
|
||||
|
@ -115,6 +117,15 @@ func TestFuncASRS(t *testing.T) {
|
|||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncASRSs(t *testing.T) {
|
||||
uf := stdlib.FuncASRSs(func(a string) []string { return []string{a} })
|
||||
ret, err := uf.Call(&objects.String{Value: "foo"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, array(&objects.String{Value: "foo"}), ret)
|
||||
ret, err = uf.Call()
|
||||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncASI64RE(t *testing.T) {
|
||||
uf := stdlib.FuncASI64RE(func(a string, b int64) error { return nil })
|
||||
ret, err := uf.Call(&objects.String{Value: "foo"}, &objects.Int{Value: 5})
|
||||
|
@ -168,7 +179,24 @@ func TestFuncASRSE(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFuncASSRE(t *testing.T) {
|
||||
uf := stdlib.FuncASSRE(func(a, b string) error { return nil })
|
||||
ret, err := uf.Call(&objects.String{Value: "foo"}, &objects.String{Value: "bar"})
|
||||
assert.NoError(t, err)
|
||||
uf = stdlib.FuncASSRE(func(a, b string) error { return errors.New("some error") })
|
||||
ret, err = uf.Call(&objects.String{Value: "foo"}, &objects.String{Value: "bar"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, &objects.Error{Value: &objects.String{Value: "some error"}}, ret)
|
||||
ret, err = uf.Call(&objects.String{Value: "foo"})
|
||||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncASsRS(t *testing.T) {
|
||||
uf := stdlib.FuncASsSRS(func(a []string, b string) string { return strings.Join(a, b) })
|
||||
ret, err := uf.Call(array(&objects.String{Value: "foo"}, &objects.String{Value: "bar"}), &objects.String{Value: " "})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, &objects.String{Value: "foo bar"}, ret)
|
||||
ret, err = uf.Call(&objects.String{Value: "foo"})
|
||||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncARF(t *testing.T) {
|
||||
|
@ -247,6 +275,17 @@ func TestFuncAFFRF(t *testing.T) {
|
|||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncASIRS(t *testing.T) {
|
||||
uf := stdlib.FuncASIRS(func(a string, b int) string { return strings.Repeat(a, b) })
|
||||
ret, err := uf.Call(&objects.String{Value: "ab"}, &objects.Int{Value: 2})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, &objects.String{Value: "abab"}, ret)
|
||||
ret, err = uf.Call()
|
||||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
ret, err = uf.Call(objects.TrueValue)
|
||||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncAIFRF(t *testing.T) {
|
||||
uf := stdlib.FuncAIFRF(func(a int, b float64) float64 {
|
||||
return float64(a) + b
|
||||
|
@ -303,6 +342,24 @@ func TestFuncAIRSsE(t *testing.T) {
|
|||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncASSRSs(t *testing.T) {
|
||||
uf := stdlib.FuncASSRSs(func(a, b string) []string { return []string{a, b} })
|
||||
ret, err := uf.Call(&objects.String{Value: "foo"}, &objects.String{Value: "bar"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, array(&objects.String{Value: "foo"}, &objects.String{Value: "bar"}), ret)
|
||||
ret, err = uf.Call()
|
||||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncASSIRSs(t *testing.T) {
|
||||
uf := stdlib.FuncASSIRSs(func(a, b string, c int) []string { return []string{a, b, strconv.Itoa(c)} })
|
||||
ret, err := uf.Call(&objects.String{Value: "foo"}, &objects.String{Value: "bar"}, &objects.Int{Value: 5})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, array(&objects.String{Value: "foo"}, &objects.String{Value: "bar"}, &objects.String{Value: "5"}), ret)
|
||||
ret, err = uf.Call()
|
||||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncARB(t *testing.T) {
|
||||
uf := stdlib.FuncARB(func() bool { return true })
|
||||
ret, err := uf.Call()
|
||||
|
@ -355,6 +412,33 @@ func TestFuncAYRIE(t *testing.T) {
|
|||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncASSRI(t *testing.T) {
|
||||
uf := stdlib.FuncASSRI(func(a, b string) int { return len(a) + len(b) })
|
||||
ret, err := uf.Call(&objects.String{Value: "foo"}, &objects.String{Value: "bar"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, &objects.Int{Value: 6}, ret)
|
||||
ret, err = uf.Call(&objects.String{Value: "foo"})
|
||||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncASSRS(t *testing.T) {
|
||||
uf := stdlib.FuncASSRS(func(a, b string) string { return a + b })
|
||||
ret, err := uf.Call(&objects.String{Value: "foo"}, &objects.String{Value: "bar"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, &objects.String{Value: "foobar"}, ret)
|
||||
ret, err = uf.Call(&objects.String{Value: "foo"})
|
||||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncASSRB(t *testing.T) {
|
||||
uf := stdlib.FuncASSRB(func(a, b string) bool { return len(a) > len(b) })
|
||||
ret, err := uf.Call(&objects.String{Value: "123"}, &objects.String{Value: "12"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, objects.TrueValue, ret)
|
||||
ret, err = uf.Call(&objects.String{Value: "foo"})
|
||||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func array(elements ...objects.Object) *objects.Array {
|
||||
return &objects.Array{Value: elements}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package stdlib
|
|||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/d5/tengo/objects"
|
||||
)
|
||||
|
@ -232,6 +233,98 @@ var textModule = map[string]objects.Object{
|
|||
return
|
||||
},
|
||||
},
|
||||
|
||||
// compare(a, b) => int
|
||||
"compare": FuncASSRI(strings.Compare),
|
||||
// contains(s, substr) => bool
|
||||
"contains": FuncASSRB(strings.Contains),
|
||||
// contains_any(s, chars) => bool
|
||||
"contains_any": FuncASSRB(strings.ContainsAny),
|
||||
// count(s, substr) => int
|
||||
"count": FuncASSRI(strings.Count),
|
||||
// "equal_fold(s, t) => bool
|
||||
"equal_fold": FuncASSRB(strings.EqualFold),
|
||||
// fields(s) => array(string)
|
||||
"fields": FuncASRSs(strings.Fields),
|
||||
// has_prefix(s, prefix) => bool
|
||||
"has_prefix": FuncASSRB(strings.HasPrefix),
|
||||
// has_suffix(s, suffix) => bool
|
||||
"has_suffix": FuncASSRB(strings.HasSuffix),
|
||||
// index(s, substr) => int
|
||||
"index": FuncASSRI(strings.Index),
|
||||
// index_any(s, chars) => int
|
||||
"index_any": FuncASSRI(strings.IndexAny),
|
||||
// join(arr, sep) => string
|
||||
"join": FuncASsSRS(strings.Join),
|
||||
// last_index(s, substr) => int
|
||||
"last_index": FuncASSRI(strings.LastIndex),
|
||||
// last_index_any(s, chars) => int
|
||||
"last_index_any": FuncASSRI(strings.LastIndexAny),
|
||||
// repeat(s, count) => string
|
||||
"repeat": FuncASIRS(strings.Repeat),
|
||||
// replace(s, old, new, n) => string
|
||||
"replace": &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||
if len(args) != 4 {
|
||||
err = objects.ErrWrongNumArguments
|
||||
return
|
||||
}
|
||||
|
||||
s1, ok := objects.ToString(args[0])
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
s2, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
s3, ok := objects.ToString(args[2])
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
i4, ok := objects.ToInt(args[3])
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
ret = &objects.String{Value: strings.Replace(s1, s2, s3, i4)}
|
||||
|
||||
return
|
||||
},
|
||||
},
|
||||
// split(s, sep) => []string
|
||||
"split": FuncASSRSs(strings.Split),
|
||||
// split_after(s, sep) => []string
|
||||
"split_after": FuncASSRSs(strings.SplitAfter),
|
||||
// split_after_n(s, sep, n) => []string
|
||||
"split_after_n": FuncASSIRSs(strings.SplitAfterN),
|
||||
// split_n(s, sep, n) => []string
|
||||
"split_n": FuncASSIRSs(strings.SplitN),
|
||||
// title(s) => string
|
||||
"title": FuncASRS(strings.Title),
|
||||
// to_lower(s) => string
|
||||
"to_lower": FuncASRS(strings.ToLower),
|
||||
// to_title(s) => string
|
||||
"to_title": FuncASRS(strings.ToTitle),
|
||||
// to_upper(s) => string
|
||||
"to_upper": FuncASRS(strings.ToUpper),
|
||||
// trim_left(s, cutset) => string
|
||||
"trim_left": FuncASSRS(strings.TrimLeft),
|
||||
// trim_prefix(s, prefix) => string
|
||||
"trim_prefix": FuncASSRS(strings.TrimPrefix),
|
||||
// trim_right(s, cutset) => string
|
||||
"trim_right": FuncASSRS(strings.TrimRight),
|
||||
// trim_space(s) => string
|
||||
"trim_space": FuncASRS(strings.TrimSpace),
|
||||
// trim_suffix(s, suffix) => string
|
||||
"trim_suffix": FuncASSRS(strings.TrimSuffix),
|
||||
}
|
||||
|
||||
func stringsRegexpImmutableMap(re *regexp.Regexp) *objects.ImmutableMap {
|
||||
|
|
|
@ -159,5 +159,25 @@ func TestTextRE(t *testing.T) {
|
|||
module(t, "text").call("re_split", d.pattern, d.text, d.count).expect(d.expected, "pattern: %q, text: %q", d.pattern, d.text)
|
||||
module(t, "text").call("re_compile", d.pattern).call("split", d.text, d.count).expect(d.expected, "pattern: %q, text: %q", d.pattern, d.text)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestText(t *testing.T) {
|
||||
module(t, "text").call("compare", "", "").expect(0)
|
||||
module(t, "text").call("compare", "", "a").expect(-1)
|
||||
module(t, "text").call("compare", "a", "").expect(1)
|
||||
module(t, "text").call("compare", "a", "a").expect(0)
|
||||
module(t, "text").call("compare", "a", "b").expect(-1)
|
||||
module(t, "text").call("compare", "b", "a").expect(1)
|
||||
module(t, "text").call("compare", "abcde", "abcde").expect(0)
|
||||
module(t, "text").call("compare", "abcde", "abcdf").expect(-1)
|
||||
module(t, "text").call("compare", "abcdf", "abcde").expect(1)
|
||||
|
||||
module(t, "text").call("contains", "", "").expect(true)
|
||||
module(t, "text").call("contains", "", "a").expect(false)
|
||||
module(t, "text").call("contains", "a", "").expect(true)
|
||||
module(t, "text").call("contains", "a", "a").expect(true)
|
||||
module(t, "text").call("contains", "abcde", "a").expect(true)
|
||||
module(t, "text").call("contains", "abcde", "abcde").expect(true)
|
||||
module(t, "text").call("contains", "abc", "abcde").expect(false)
|
||||
module(t, "text").call("contains", "ab cd", "bc").expect(false)
|
||||
}
|
||||
|
|
|
@ -60,7 +60,6 @@ func TestVariable(t *testing.T) {
|
|||
Name: "d",
|
||||
Value: nil,
|
||||
ValueType: "undefined",
|
||||
StringValue: "",
|
||||
Object: objects.UndefinedValue,
|
||||
IsUndefined: true,
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue