Fixed field export
This commit is contained in:
parent
43098fa227
commit
ddd5ab74f6
|
@ -113,6 +113,23 @@ func callBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
|||
return inv.invoke(ctx, args.shift(1))
|
||||
}
|
||||
|
||||
func lenBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||
if err := args.expectArgn(1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch v := args.args[0].(type) {
|
||||
case strObject:
|
||||
return intObject(len(string(v))), nil
|
||||
case listable:
|
||||
return intObject(v.Len()), nil
|
||||
case hashable:
|
||||
return intObject(v.Len()), nil
|
||||
}
|
||||
|
||||
return intObject(0), nil
|
||||
}
|
||||
|
||||
func indexBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||
if err := args.expectArgn(1); err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -31,6 +31,7 @@ func New(opts ...InstOption) *Inst {
|
|||
rootEC.addCmd("set", invokableFunc(setBuiltin))
|
||||
rootEC.addCmd("toUpper", invokableFunc(toUpperBuiltin))
|
||||
//rootEC.addCmd("cat", invokableFunc(catBuiltin))
|
||||
rootEC.addCmd("len", invokableFunc(lenBuiltin))
|
||||
rootEC.addCmd("index", invokableFunc(indexBuiltin))
|
||||
rootEC.addCmd("call", invokableFunc(callBuiltin))
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/lmika/gopkgs/fp/slices"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
@ -160,7 +161,7 @@ func fromGoValue(v any) (object, error) {
|
|||
case reflect.Slice:
|
||||
return listableProxyObject{resVal}, nil
|
||||
case reflect.Struct:
|
||||
return structProxyObject{resVal}, nil
|
||||
return newStructProxyObject(resVal), nil
|
||||
}
|
||||
|
||||
return proxyObject{v}, nil
|
||||
|
@ -393,6 +394,14 @@ func (p listableProxyObject) Index(i int) object {
|
|||
|
||||
type structProxyObject struct {
|
||||
v reflect.Value
|
||||
vf []reflect.StructField
|
||||
}
|
||||
|
||||
func newStructProxyObject(v reflect.Value) structProxyObject {
|
||||
return structProxyObject{
|
||||
v: v,
|
||||
vf: slices.Filter(reflect.VisibleFields(v.Type()), func(t reflect.StructField) bool { return t.IsExported() }),
|
||||
}
|
||||
}
|
||||
|
||||
func (s structProxyObject) String() string {
|
||||
|
@ -404,7 +413,7 @@ func (s structProxyObject) Truthy() bool {
|
|||
}
|
||||
|
||||
func (s structProxyObject) Len() int {
|
||||
return s.v.Type().NumField()
|
||||
return len(s.vf)
|
||||
}
|
||||
|
||||
func (s structProxyObject) Value(k string) object {
|
||||
|
@ -416,14 +425,13 @@ func (s structProxyObject) Value(k string) object {
|
|||
}
|
||||
|
||||
func (s structProxyObject) Each(fn func(k string, v object) error) error {
|
||||
for i := 0; i < s.v.Type().NumField(); i++ {
|
||||
f := s.v.Type().Field(i).Name
|
||||
v, err := fromGoValue(s.v.Field(i).Interface())
|
||||
for _, f := range s.vf {
|
||||
v, err := fromGoValue(s.v.FieldByName(f.Name).Interface())
|
||||
if err != nil {
|
||||
v = nil
|
||||
}
|
||||
|
||||
if err := fn(f, v); err != nil {
|
||||
if err := fn(f.Name, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -386,3 +386,62 @@ func TestBuiltins_Index(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuiltins_Len(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
expr string
|
||||
want string
|
||||
}{
|
||||
{desc: "len of list 1", expr: `len ["alpha" "beta" "gamma"]`, want: "3\n"},
|
||||
{desc: "len of list 2", expr: `len ["alpha"]`, want: "1\n"},
|
||||
{desc: "len of list 3", expr: `len []`, want: "0\n"},
|
||||
|
||||
{desc: "len of hash 1", expr: `len ["first":"alpha" "second":"beta" "third":"gamma"]`, want: "3\n"},
|
||||
{desc: "len of hash 2", expr: `len ["first":"alpha" "second":"beta"]`, want: "2\n"},
|
||||
{desc: "len of hash 3", expr: `len ["first":"alpha"]`, want: "1\n"},
|
||||
{desc: "len of hash 4", expr: `len [:]`, want: "0\n"},
|
||||
|
||||
{desc: "len of string 1", expr: `len "Hello, world"`, want: "12\n"},
|
||||
{desc: "len of string 2", expr: `len "chair"`, want: "5\n"},
|
||||
{desc: "len of string 3", expr: `len ""`, want: "0\n"},
|
||||
|
||||
{desc: "len of int", expr: `len 1232`, want: "0\n"},
|
||||
{desc: "len of nil", expr: `len ()`, want: "0\n"},
|
||||
|
||||
{desc: "go list 1", expr: `goInt | len`, want: "3\n"},
|
||||
{desc: "go struct 1", expr: `goStruct | len`, want: "3\n"},
|
||||
{desc: "go struct 2", expr: `index (goStruct) Gamma | len`, want: "2\n"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
outW := bytes.NewBuffer(nil)
|
||||
|
||||
inst := New(WithOut(outW), WithTestBuiltin())
|
||||
inst.SetBuiltin("goInt", func(ctx context.Context, args CallArgs) (any, error) {
|
||||
return []int{6, 5, 4}, nil
|
||||
})
|
||||
inst.SetBuiltin("goStruct", func(ctx context.Context, args CallArgs) (any, error) {
|
||||
return struct {
|
||||
Alpha string
|
||||
Beta string
|
||||
Gamma []int
|
||||
hidden string
|
||||
missing string
|
||||
}{
|
||||
Alpha: "foo",
|
||||
Beta: "bar",
|
||||
Gamma: []int{22, 33},
|
||||
hidden: "hidden",
|
||||
missing: "missing",
|
||||
}, nil
|
||||
})
|
||||
err := inst.EvalAndDisplay(ctx, tt.expr)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.want, outW.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue