This commit is contained in:
parent
7a2b012833
commit
7c76e61b08
2
go.mod
2
go.mod
|
@ -7,6 +7,7 @@ require (
|
||||||
github.com/chzyer/readline v1.5.1
|
github.com/chzyer/readline v1.5.1
|
||||||
github.com/lmika/gopkgs v0.0.0-20240408110817-a02f6fc67d1f
|
github.com/lmika/gopkgs v0.0.0-20240408110817-a02f6fc67d1f
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
|
lmika.dev/pkg/modash v0.0.0-20250619112300-0be0b6b35b1b
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -17,5 +18,4 @@ require (
|
||||||
go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect
|
go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect
|
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
lmika.dev/pkg/modash v0.0.0-20250619112300-0be0b6b35b1b // indirect
|
|
||||||
)
|
)
|
||||||
|
|
1
go.sum
1
go.sum
|
@ -22,6 +22,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
|
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
|
||||||
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||||
|
|
31
ucl/builtins/fns_test.go
Normal file
31
ucl/builtins/fns_test.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package builtins_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
"ucl.lmika.dev/ucl"
|
||||||
|
"ucl.lmika.dev/ucl/builtins"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFns_Uni(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
descr string
|
||||||
|
eval string
|
||||||
|
want any
|
||||||
|
}{
|
||||||
|
{descr: "uni 1", eval: `s = fns:uni add 2 ; $s 3`, want: 5},
|
||||||
|
{descr: "uni 2", eval: `s = fns:uni (proc { |x| add $x 1 }) ; $s 3`, want: 4},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.descr, func(t *testing.T) {
|
||||||
|
inst := ucl.New(
|
||||||
|
ucl.WithModule(builtins.Fns()),
|
||||||
|
)
|
||||||
|
res, err := inst.EvalString(context.Background(), tt.eval)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.want, res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,12 +10,45 @@ func Lists() ucl.Module {
|
||||||
return ucl.Module{
|
return ucl.Module{
|
||||||
Name: "lists",
|
Name: "lists",
|
||||||
Builtins: map[string]ucl.BuiltinHandler{
|
Builtins: map[string]ucl.BuiltinHandler{
|
||||||
|
"append": listAppend,
|
||||||
"first": listFirst,
|
"first": listFirst,
|
||||||
|
"batch": listBatch,
|
||||||
"uniq": listUniq,
|
"uniq": listUniq,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func listAppend(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
|
var (
|
||||||
|
what ucl.Object
|
||||||
|
item ucl.Object
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := args.Bind(&what); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if what == nil {
|
||||||
|
what = ucl.NewListObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
t, ok := what.(ucl.ModListable)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("expected mutable list")
|
||||||
|
}
|
||||||
|
|
||||||
|
for args.NArgs() > 0 {
|
||||||
|
if err := args.Bind(&item); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := t.Insert(-1, item); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
func listFirst(ctx context.Context, args ucl.CallArgs) (any, error) {
|
func listFirst(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
var (
|
var (
|
||||||
what ucl.Object
|
what ucl.Object
|
||||||
|
@ -125,3 +158,34 @@ func listUniq(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
|
|
||||||
return found, nil
|
return found, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func listBatch(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
|
var (
|
||||||
|
what ucl.Object
|
||||||
|
groupSize int
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := args.Bind(&what, &groupSize); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if groupSize <= 0 {
|
||||||
|
return nil, errors.New("group size must be > 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
groups := ucl.NewListObject()
|
||||||
|
var thisGroup *ucl.ListObject
|
||||||
|
|
||||||
|
if err := eachListOrIterItem(ctx, what, func(idx int, v ucl.Object) error {
|
||||||
|
if thisGroup == nil || thisGroup.Len() == groupSize {
|
||||||
|
thisGroup = ucl.NewListObject()
|
||||||
|
groups.Append(thisGroup)
|
||||||
|
}
|
||||||
|
thisGroup.Append(v)
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups, nil
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,44 @@ import (
|
||||||
"ucl.lmika.dev/ucl/builtins"
|
"ucl.lmika.dev/ucl/builtins"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestLists_Append(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
eval string
|
||||||
|
want any
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{desc: "append 1", eval: `lists:append [1 2 3] 4`, want: []any{1, 2, 3, 4}},
|
||||||
|
{desc: "append 2", eval: `lists:append [1 2 3] 4 5 6`, want: []any{1, 2, 3, 4, 5, 6}},
|
||||||
|
{desc: "append 3", eval: `lists:append [] 1 2 3`, want: []any{1, 2, 3}},
|
||||||
|
{desc: "append 4", eval: `lists:append () 1 2 3`, want: []any{1, 2, 3}},
|
||||||
|
{desc: "append 5", eval: `lists:append [1 2 3]`, want: []any{1, 2, 3}},
|
||||||
|
{desc: "append 6", eval: `l = [] ; lists:append $l 1 2 3 ; $l`, want: []any{1, 2, 3}},
|
||||||
|
{desc: "append 7", eval: `l = [1 2 3] ; lists:append $l [4 5 6] ; $l`, want: []any{1, 2, 3, []any{4, 5, 6}}},
|
||||||
|
{desc: "append 8", eval: `lists:append (seq 3 | itrs:from | itrs:to-list) 4 5 6`, want: []any{0, 1, 2, 4, 5, 6}},
|
||||||
|
|
||||||
|
{desc: "err 1", eval: `lists:append "asa" 1`, wantErr: true},
|
||||||
|
{desc: "err 2", eval: `lists:append 123 1`, wantErr: true},
|
||||||
|
{desc: "err 3", eval: `lists:append [:] 1`, wantErr: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
|
inst := ucl.New(
|
||||||
|
ucl.WithModule(builtins.Itrs()),
|
||||||
|
ucl.WithModule(builtins.Lists()),
|
||||||
|
)
|
||||||
|
res, err := inst.EvalString(context.Background(), tt.eval)
|
||||||
|
if tt.wantErr {
|
||||||
|
assert.Error(t, err)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.want, res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLists_First(t *testing.T) {
|
func TestLists_First(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
@ -45,6 +83,42 @@ func TestLists_First(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLists_Batch(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
eval string
|
||||||
|
want any
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{desc: "batch 1", eval: `lists:batch [1 2 3 4 5] 2`, want: []any{[]any{1, 2}, []any{3, 4}, []any{5}}},
|
||||||
|
{desc: "batch 2", eval: `lists:batch [1 2 3 4] 2`, want: []any{[]any{1, 2}, []any{3, 4}}},
|
||||||
|
{desc: "batch 3", eval: `lists:batch [1 2 3 4 5] 3`, want: []any{[]any{1, 2, 3}, []any{4, 5}}},
|
||||||
|
{desc: "batch 4", eval: `lists:batch [1 2 3 4 5] 12`, want: []any{[]any{1, 2, 3, 4, 5}}},
|
||||||
|
{desc: "batch 5", eval: `lists:batch [1 2 3 4 5] 1`, want: []any{[]any{1}, []any{2}, []any{3}, []any{4}, []any{5}}},
|
||||||
|
{desc: "batch 6", eval: `lists:batch [1] 12`, want: []any{[]any{1}}},
|
||||||
|
{desc: "batch 7", eval: `lists:batch [] 12`, want: []any{}},
|
||||||
|
|
||||||
|
{desc: "err 1", eval: `lists:batch [1 2 3] -3`, wantErr: true},
|
||||||
|
{desc: "err 2", eval: `lists:batch [1 2 3] 0`, wantErr: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
|
inst := ucl.New(
|
||||||
|
ucl.WithModule(builtins.Itrs()),
|
||||||
|
ucl.WithModule(builtins.Lists()),
|
||||||
|
)
|
||||||
|
res, err := inst.EvalString(context.Background(), tt.eval)
|
||||||
|
if tt.wantErr {
|
||||||
|
assert.Error(t, err)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.want, res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLists_Uniq(t *testing.T) {
|
func TestLists_Uniq(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
|
Loading…
Reference in a new issue