Skip to content

Commit

Permalink
Merge pull request #195 from Mido-sys/add_slice_append
Browse files Browse the repository at this point in the history
Add append feature for arrays
  • Loading branch information
paganotoni authored Feb 6, 2025
2 parents d62fe8a + 2135de2 commit 01c2c52
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ Arrays in Plush will get translated to the Go type `[]interface{}` when used.
[]interface{}{ 1, 2, "three", "four", h }
```

Arrays in plush can be appended using the following format:

```erb
<% let a = [1, 2, "three", "four", h] %> <% a = a + "hello world"%>
```

If the array passed to plush is not of type `[]interface{}` and an attempt is made to append a value with a data type that does not match the underlying array type, an error will be returned.

## For Loops

There are three different types that can be looped over: maps, arrays/slices, and iterators. The format for them all looks the same:
Expand Down
25 changes: 25 additions & 0 deletions compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,11 +499,36 @@ func (c *compiler) evalInfixExpression(node *ast.InfixExpression) (interface{},
}
case bool:
return c.boolsOperator(lres, rres, node.Operator)
default:
if reflect.TypeOf(t).Kind() == reflect.Slice || reflect.TypeOf(t).Kind() == reflect.Array {
return c.arrayOperator(lres, rres, node.Operator)
}
}

return nil, fmt.Errorf("unable to operate (%s) on %T and %T ", node.Operator, lres, rres)
}

func (c *compiler) arrayOperator(l interface{}, r interface{}, op string) (interface{}, error) {
var err error
switch op {
case "+":
elemType := reflect.TypeOf(l).Elem()
if elemType.Kind() != reflect.Interface {
t := reflect.ValueOf(r).Type()
if elemType != t {
err = fmt.Errorf("cannot append '%v' (untyped %s constant) as %s value in assignment", r, t, elemType)
}
}
if err == nil {
return reflect.Append(reflect.ValueOf(l), reflect.ValueOf(r)), nil
}
default:
err = fmt.Errorf("unkown operator (%s) on %T and %T ", op, l, r)
}

return nil, err
}

func (c *compiler) nilsOperator(l interface{}, r interface{}, op string) (interface{}, error) {
switch op {
case "!=":
Expand Down
32 changes: 32 additions & 0 deletions variables_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package plush_test

import (
"html/template"
"log"
"strings"
"testing"

Expand Down Expand Up @@ -174,6 +175,37 @@ func Test_Render_Let_ArrayAsssign_AssignableToArrayInterface(t *testing.T) {
r.NoError(err)
}

func Test_Render_AppendArray_WithTypeIntArrayTypeString(t *testing.T) {
r := require.New(t)
ctx := plush.NewContext()

ctx.Set("myArray", []string{"a", "b"})
input := `<% let a = myArray %><% a = a + 1 %><%= a %>`
_, err := plush.Render(input, ctx)
r.Error(err)
r.Contains(err.Error(), "cannot append '1' (untyped int constant) as string value in assignment")
}

func Test_Render_AppendArray_CreatedInPlush(t *testing.T) {
r := require.New(t)

input := `<% let a = [1,2,"HelloWorld"] %><% a = a + 2.2 %><%= a %>`
s, err := plush.Render(input, plush.NewContext())
r.NoError(err)
r.Equal(s, "12HelloWorld2.2")
}
func Test_Render_AppendArray_WithTypeInterface(t *testing.T) {
r := require.New(t)
ctx := plush.NewContext()

ctx.Set("myArray", []interface{}{"a", "b"})
input := `<% let a = myArray %><% a = a + 1 %><%= a %>`
s, err := plush.Render(input, ctx)
log.Println(s)
r.NoError(err)
r.Equal("ab1", s)
}

type Category1 struct {
Products []Product1
}
Expand Down

0 comments on commit 01c2c52

Please sign in to comment.