mirror of
https://github.com/danog/liquid.git
synced 2024-11-26 23:34:47 +01:00
contains operates on strings not arrays
This commit is contained in:
parent
ebc29dcbed
commit
9dda87f40f
@ -2,9 +2,46 @@ package expressions
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func makeObjectPropertyEvaluator(obj func(Context) interface{}, attr string) func(Context) interface{} {
|
||||
func makeContainsExpr(e1, e2 func(Context) interface{}) func(Context) interface{} {
|
||||
return func(ctx Context) interface{} {
|
||||
a, aok := e1(ctx).(string)
|
||||
b, bok := e2(ctx).(string)
|
||||
return aok && bok && strings.Contains(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
func makeIndexExpr(obj, index func(Context) interface{}) func(Context) interface{} {
|
||||
return func(ctx Context) interface{} {
|
||||
ref := reflect.ValueOf(obj(ctx))
|
||||
i := reflect.ValueOf(index(ctx))
|
||||
switch ref.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
switch i.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n := int(i.Int())
|
||||
if n < 0 {
|
||||
n = ref.Len() + n
|
||||
}
|
||||
if 0 <= n && n < ref.Len() {
|
||||
return ref.Index(n).Interface()
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
if i.Type().ConvertibleTo(ref.Type().Key()) {
|
||||
item := ref.MapIndex(i.Convert(ref.Type().Key()))
|
||||
if item.IsValid() {
|
||||
return item.Interface()
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func makeObjectPropertyExpr(obj func(Context) interface{}, attr string) func(Context) interface{} {
|
||||
return func(ctx Context) interface{} {
|
||||
ref := reflect.ValueOf(obj(ctx))
|
||||
switch ref.Kind() {
|
||||
@ -33,31 +70,3 @@ func makeObjectPropertyEvaluator(obj func(Context) interface{}, attr string) fun
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func makeIndexEvaluator(obj, index func(Context) interface{}) func(Context) interface{} {
|
||||
return func(ctx Context) interface{} {
|
||||
ref := reflect.ValueOf(obj(ctx))
|
||||
i := reflect.ValueOf(index(ctx))
|
||||
switch ref.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
switch i.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n := int(i.Int())
|
||||
if n < 0 {
|
||||
n = ref.Len() + n
|
||||
}
|
||||
if 0 <= n && n < ref.Len() {
|
||||
return ref.Index(n).Interface()
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
if i.Type().ConvertibleTo(ref.Type().Key()) {
|
||||
item := ref.MapIndex(i.Convert(ref.Type().Key()))
|
||||
if item.IsValid() {
|
||||
return item.Interface()
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -83,8 +83,8 @@ loop_modifiers: /* empty */ { $$ = loopModifiers{} }
|
||||
expr:
|
||||
LITERAL { val := $1; $$ = func(_ Context) interface{} { return val } }
|
||||
| IDENTIFIER { name := $1; $$ = func(ctx Context) interface{} { return ctx.Get(name) } }
|
||||
| expr '.' IDENTIFIER { $$ = makeObjectPropertyEvaluator($1, $3) }
|
||||
| expr '[' expr ']' { $$ = makeIndexEvaluator($1, $3) }
|
||||
| expr '.' IDENTIFIER { $$ = makeObjectPropertyExpr($1, $3) }
|
||||
| expr '[' expr ']' { $$ = makeIndexExpr($1, $3) }
|
||||
| '(' cond ')' { $$ = $2 }
|
||||
;
|
||||
|
||||
@ -143,12 +143,7 @@ rel:
|
||||
return generics.Less(a, b) || generics.Equal(a, b)
|
||||
}
|
||||
}
|
||||
| expr CONTAINS expr {
|
||||
fa, fb := $1, $3
|
||||
$$ = func(ctx Context) interface{} {
|
||||
return generics.Contains(fa(ctx), fb(ctx))
|
||||
}
|
||||
}
|
||||
| expr CONTAINS expr { $$ = makeContainsExpr($1, $3) }
|
||||
;
|
||||
|
||||
cond:
|
||||
|
@ -34,9 +34,9 @@ var evaluatorTests = []struct {
|
||||
{`fruits.size`, 4},
|
||||
|
||||
// Indices
|
||||
{`ar[1]`, "second"},
|
||||
{`ar[-1]`, "third"}, // undocumented
|
||||
{`ar[100]`, nil},
|
||||
{`array[1]`, "second"},
|
||||
{`array[-1]`, "third"}, // undocumented
|
||||
{`array[100]`, nil},
|
||||
{`obj[1]`, nil},
|
||||
{`obj.c[0]`, "r"},
|
||||
|
||||
@ -89,13 +89,13 @@ var evaluatorTests = []struct {
|
||||
{`false or false`, false},
|
||||
{`false or true`, true},
|
||||
|
||||
{`ar contains "first"`, true},
|
||||
{`ar contains "missing"`, false},
|
||||
{`"seafood" contains "foo"`, true},
|
||||
{`"seafood" contains "bar"`, false},
|
||||
}
|
||||
|
||||
var evaluatorTestContext = NewContext(map[string]interface{}{
|
||||
"n": 123,
|
||||
"ar": []string{"first", "second", "third"},
|
||||
"array": []string{"first", "second", "third"},
|
||||
"empty_list": []interface{}{},
|
||||
"fruits": []string{"apples", "oranges", "peaches", "plums"},
|
||||
"obj": map[string]interface{}{
|
||||
|
@ -591,13 +591,13 @@ yydefault:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:86
|
||||
{
|
||||
yyVAL.f = makeObjectPropertyEvaluator(yyDollar[1].f, yyDollar[3].name)
|
||||
yyVAL.f = makeObjectPropertyExpr(yyDollar[1].f, yyDollar[3].name)
|
||||
}
|
||||
case 11:
|
||||
yyDollar = yyS[yypt-4 : yypt+1]
|
||||
//line expressions.y:87
|
||||
{
|
||||
yyVAL.f = makeIndexEvaluator(yyDollar[1].f, yyDollar[3].f)
|
||||
yyVAL.f = makeIndexExpr(yyDollar[1].f, yyDollar[3].f)
|
||||
}
|
||||
case 12:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
@ -693,14 +693,11 @@ yydefault:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:146
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
return generics.Contains(fa(ctx), fb(ctx))
|
||||
}
|
||||
yyVAL.f = makeContainsExpr(yyDollar[1].f, yyDollar[3].f)
|
||||
}
|
||||
case 27:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:156
|
||||
//line expressions.y:151
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
@ -709,7 +706,7 @@ yydefault:
|
||||
}
|
||||
case 28:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:162
|
||||
//line expressions.y:157
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
|
Loading…
Reference in New Issue
Block a user