Skip to content

Commit

Permalink
Merge pull request #191 from mattfarina/deepcopy
Browse files Browse the repository at this point in the history
Add deepCopy and mustDeepCopy functions
  • Loading branch information
mattfarina authored Oct 1, 2019
2 parents df4771b + d9bc549 commit e2a53d5
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 13 deletions.
18 changes: 17 additions & 1 deletion dict.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package sprig

import "github.com/imdario/mergo"
import (
"github.com/imdario/mergo"
"github.com/mitchellh/copystructure"
)

func set(d map[string]interface{}, key string, value interface{}) map[string]interface{} {
d[key] = value
Expand Down Expand Up @@ -123,3 +126,16 @@ func values(dict map[string]interface{}) []interface{} {

return values
}

func deepCopy(i interface{}) interface{} {
c, err := mustDeepCopy(i)
if err != nil {
panic("deepCopy error: " + err.Error())
}

return c
}

func mustDeepCopy(i interface{}) (interface{}, error) {
return copystructure.Copy(i)
}
38 changes: 33 additions & 5 deletions dict_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ func TestMerge(t *testing.T) {
"i": "eye", // overridden twice
"j": "jay", // overridden and merged
"k": map[string]interface{}{
"l": true, // overriden
"l": true, // overriden
},
}
assert.Equal(t, expected, dict["dst"])
Expand Down Expand Up @@ -222,9 +222,9 @@ func TestMergeOverwrite(t *testing.T) {
t.Error(err)
}
expected := map[string]interface{}{
"a": 1, // key overwritten from src1
"b": 2, // merged from src1
"c": 3, // merged from dst
"a": 1, // key overwritten from src1
"b": 2, // merged from src1
"c": 3, // merged from dst
"d": map[string]interface{}{ // deep merge
"e": "four",
"f": 5,
Expand All @@ -233,7 +233,7 @@ func TestMergeOverwrite(t *testing.T) {
"h": 10, // merged from src2
"i": "i", // overwritten twice src2 wins
"j": "j", // overwritten twice src2 wins
"k": map[string]interface{} { // deep merge
"k": map[string]interface{}{ // deep merge
"l": false, // overwritten src1 wins
},
}
Expand All @@ -252,3 +252,31 @@ func TestValues(t *testing.T) {
}
}
}

func TestDeepCopy(t *testing.T) {
tests := map[string]string{
`{{- $d := dict "a" 1 "b" 2 | deepCopy }}{{ values $d | sortAlpha | join "," }}`: "1,2",
`{{- $d := dict "a" 1 "b" 2 | deepCopy }}{{ keys $d | sortAlpha | join "," }}`: "a,b",
`{{- $one := dict "foo" (dict "bar" "baz") "qux" true -}}{{ deepCopy $one }}`: "map[foo:map[bar:baz] qux:true]",
}

for tpl, expect := range tests {
if err := runt(tpl, expect); err != nil {
t.Error(err)
}
}
}

func TestMustDeepCopy(t *testing.T) {
tests := map[string]string{
`{{- $d := dict "a" 1 "b" 2 | mustDeepCopy }}{{ values $d | sortAlpha | join "," }}`: "1,2",
`{{- $d := dict "a" 1 "b" 2 | mustDeepCopy }}{{ keys $d | sortAlpha | join "," }}`: "a,b",
`{{- $one := dict "foo" (dict "bar" "baz") "qux" true -}}{{ mustDeepCopy $one }}`: "map[foo:map[bar:baz] qux:true]",
}

for tpl, expect := range tests {
if err := runt(tpl, expect); err != nil {
t.Error(err)
}
}
}
11 changes: 11 additions & 0 deletions docs/dicts.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,17 @@ The above returns `list["value1", "value2", "value 3"]`. Note that the `values`
function gives no guarantees about the result ordering- if you care about this,
then use `sortAlpha`.

## deepCopy, mustDeepCopy

The `deepCopy` and `mustDeepCopy` functions takes a value and makes a deep copy
of the value. This includes dicts and other structures. `deepCopy` panics
when there is a problem while `mustDeepCopy` returns an error to the template
system when there is an error.

```
dict "a" 1 "b" 2 | deepCopy
```

## A Note on Dict Internals

A `dict` is implemented in Go as a `map[string]interface{}`. Go developers can
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The Sprig library provides over 70 template functions for Go's template language
- [Defaults Functions](defaults.md): `default`, `empty`, `coalesce`, `toJson`, `toPrettyJson`, `ternary`
- [Encoding Functions](encoding.md): `b64enc`, `b64dec`, etc.
- [Lists and List Functions](lists.md): `list`, `first`, `uniq`, etc.
- [Dictionaries and Dict Functions](dicts.md): `dict`, `hasKey`, `pluck`, etc.
- [Dictionaries and Dict Functions](dicts.md): `dict`, `hasKey`, `pluck`, `deepCopy`, etc.
- [Type Conversion Functions](conversion.md): `atoi`, `int64`, `toString`, etc.
- [File Path Functions](paths.md): `base`, `dir`, `ext`, `clean`, `isAbs`
- [Flow Control Functions](flow_control.md): `fail`
Expand Down
14 changes: 8 additions & 6 deletions functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,18 @@ var genericMap = map[string]interface{}{
"hello": func() string { return "Hello!" },

// Date functions
"ago": dateAgo,
"ago": dateAgo,
"date": date,
"date_in_zone": dateInZone,
"date_modify": dateModify,
"dateInZone": dateInZone,
"dateInZone": dateInZone,
"dateModify": dateModify,
"durationRound": durationRound,
"htmlDate": htmlDate,
"durationRound": durationRound,
"htmlDate": htmlDate,
"htmlDateInZone": htmlDateInZone,
"must_date_modify": mustDateModify,
"mustDateModify": mustDateModify,
"mustToDate": mustToDate,
"mustDateModify": mustDateModify,
"mustToDate": mustToDate,
"now": func() time.Time { return time.Now() },
"toDate": toDate,
"unixEpoch": unixEpoch,
Expand Down Expand Up @@ -221,6 +221,8 @@ var genericMap = map[string]interface{}{
"mustToJson": mustToJson,
"mustToPrettyJson": mustToPrettyJson,
"ternary": ternary,
"deepCopy": deepCopy,
"mustDeepCopy": mustDeepCopy,

// Reflection
"typeOf": typeOf,
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/google/uuid v1.1.1
github.com/huandu/xstrings v1.2.0
github.com/imdario/mergo v0.3.7
github.com/mitchellh/copystructure v1.0.0
github.com/spf13/cast v1.3.0
github.com/stretchr/testify v1.4.0
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
Expand Down

0 comments on commit e2a53d5

Please sign in to comment.