Skip to content

Commit bbd9d32

Browse files
committed
variadic string concatenation and initArray methods
1 parent 1434774 commit bbd9d32

File tree

6 files changed

+140
-56
lines changed

6 files changed

+140
-56
lines changed

core/templating/template_helpers.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,13 @@ func (t templateHelpers) split(target, separator string) []string {
116116
return strings.Split(target, separator)
117117
}
118118

119-
func (t templateHelpers) concat(val1, val2 string) string {
120-
return val1 + val2
119+
// Concatenates any number of arguments together as strings.
120+
func (t templateHelpers) concat(args ...interface{}) string {
121+
var parts []string
122+
for _, arg := range args {
123+
parts = append(parts, fmt.Sprint(arg))
124+
}
125+
return strings.Join(parts, "")
121126
}
122127

123128
func (t templateHelpers) isNumeric(stringToCheck string) bool {
@@ -566,6 +571,13 @@ func (t templateHelpers) addToArray(key string, value string, output bool, optio
566571
}
567572
}
568573

574+
// Initializes (clears) an array in the template context under the given key.
575+
func (t templateHelpers) initArray(key string, options *raymond.Options) string {
576+
arrayData := options.ValueFromAllCtx("Kvs").(map[string]interface{})
577+
arrayData[key] = []string{}
578+
return ""
579+
}
580+
569581
func (t templateHelpers) getArray(key string, options *raymond.Options) []string {
570582
arrayData := options.ValueFromAllCtx("Kvs").(map[string]interface{})
571583
if array, ok := arrayData[key]; ok {

core/templating/template_helpers_test.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ package templating
33
import (
44
"testing"
55
"time"
6+
67
. "github.com/onsi/gomega"
78
)
89

9-
10-
1110
// mockRaymondOptions is a minimal mock for raymond.Options for testing
1211
type mockRaymondOptions struct {
1312
internalVars map[string]interface{}
@@ -20,7 +19,6 @@ func (m *mockRaymondOptions) ValueFromAllCtx(key string) interface{} {
2019
return nil
2120
}
2221

23-
2422
func testNow() time.Time {
2523
parsedTime, _ := time.Parse("2006-01-02T15:04:05Z", "2018-01-01T00:00:00Z")
2624
return parsedTime
@@ -107,13 +105,22 @@ func Test_split(t *testing.T) {
107105
}
108106

109107
func Test_concat(t *testing.T) {
108+
110109
RegisterTestingT(t)
111110

112111
unit := templateHelpers{}
113112

114113
Expect(unit.concat("one", " two")).To(Equal("one two"))
115114
}
116115

116+
func Test_concatWithManyStrings(t *testing.T) {
117+
RegisterTestingT(t)
118+
119+
unit := templateHelpers{}
120+
121+
Expect(unit.concat("one", " two", " three", " four")).To(Equal("one two three four"))
122+
}
123+
117124
func Test_length(t *testing.T) {
118125
RegisterTestingT(t)
119126

core/templating/templating.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ type Request struct {
4141
Host string
4242
}
4343

44-
4544
type Templator struct {
4645
SupportedMethodMap map[string]interface{}
4746
TemplateHelper templateHelpers
@@ -62,7 +61,7 @@ func NewEnrichedTemplator(journal *journal.Journal) *Templator {
6261
now: time.Now,
6362
fakerSource: gofakeit.New(0),
6463
TemplateDataSource: templateDataSource,
65-
journal: journal,
64+
journal: journal,
6665
}
6766

6867
helperMethodMap["now"] = t.nowHelper
@@ -79,7 +78,24 @@ func NewEnrichedTemplator(journal *journal.Journal) *Templator {
7978
helperMethodMap["randomUuid"] = t.randomUuid
8079
helperMethodMap["replace"] = t.replace
8180
helperMethodMap["split"] = t.split
82-
helperMethodMap["concat"] = t.concat
81+
//helperMethodMap["concat"] = t.concat
82+
83+
// Register concatMany to accept a slice of interface{}
84+
raymond.RemoveHelper("concat")
85+
raymond.RegisterHelper("concat", func(args ...interface{}) string {
86+
var parts []string
87+
for _, arg := range args {
88+
// If arg is a slice, flatten it
89+
if s, ok := arg.([]interface{}); ok {
90+
for _, v := range s {
91+
parts = append(parts, fmt.Sprint(v))
92+
}
93+
} else {
94+
parts = append(parts, fmt.Sprint(arg))
95+
}
96+
}
97+
return strings.Join(parts, "")
98+
})
8399
helperMethodMap["length"] = t.length
84100
helperMethodMap["substring"] = t.substring
85101
helperMethodMap["rightmostCharacters"] = t.rightmostCharacters
@@ -111,6 +127,7 @@ func NewEnrichedTemplator(journal *journal.Journal) *Templator {
111127
helperMethodMap["subtract"] = t.subtract
112128
helperMethodMap["multiply"] = t.multiply
113129
helperMethodMap["divide"] = t.divide
130+
helperMethodMap["initArray"] = t.initArray
114131
helperMethodMap["addToArray"] = t.addToArray
115132
helperMethodMap["getArray"] = t.getArray
116133
helperMethodMap["putValue"] = t.putValue

core/templating/templating_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,18 @@ func Test_ApplyTemplate_MatchingRowsCsvAndReturnMatchedString(t *testing.T) {
8080
Expect(template).To(Equal(`Test2`))
8181
}
8282

83+
func Test_ApplyTemplate_InitArray_ClearsArray(t *testing.T) {
84+
RegisterTestingT(t)
85+
86+
template, err := ApplyTemplate(
87+
&models.RequestDetails{},
88+
make(map[string]string),
89+
`{{addToArray 'myArray' 'one' false}}{{addToArray 'myArray' 'two' false}}{{addToArray 'myArray' 'three' false}}{{addToArray 'myArray' 'four' false}}{{addToArray 'myArray' 'five' false}}{{initArray 'myArray'}}{{addToArray 'myArray' 'six' false}}{{#each (getArray 'myArray')}}{{this}}{{/each}}`,
90+
)
91+
92+
Expect(err).To(BeNil())
93+
Expect(template).To(Equal("six"))
94+
}
8395
func Test_ApplyTemplate_MatchingRowsCsvMissingDataSource(t *testing.T) {
8496
RegisterTestingT(t)
8597

docs/pages/keyconcepts/templating/templating.rst

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Currently, you can get the following data from request to the response via templ
4949
Helper Methods
5050
--------------
5151

52-
Additional data can come from helper methods. These are the ones Hoverfly currently support:
52+
Additional data can come from helper methods. These are the ones Hoverfly currently supports:
5353

5454
+-----------------------------------------------------------+-----------------------------------------------------------+-----------------------------------------+
5555
| Description | Example | Result |
@@ -529,14 +529,19 @@ In this case, you can use the internal key value data store. The following helpe
529529
+----------------------------+--------------------------------------------+-----------------------+
530530
| Get an entry | ``{{ getValue 'id' }}`` | 123 |
531531
+----------------------------+--------------------------------------------+-----------------------+
532-
| Add a value to an arra | ``{{ addToArray 'names' 'John' true }}`` | John |
532+
| Add a value to an array | ``{{ addToArray 'names' 'John' true }}`` | John |
533+
| Get an array | ``{{ getArray 'names' }}`` | ["John"] |
534+
| Clear an array | ``{{ initArray 'names' }}`` | [] |
533535
+----------------------------+--------------------------------------------+-----------------------+
534536
| Get an array | ``{{ getArray 'names' }}`` | []string{"John" |
535537
+----------------------------+--------------------------------------------+-----------------------+
536538

539+
537540
``addToArray`` will create a new array if one doesn't exist. The boolean argument in ``putValue`` and ``addToArray``
538541
is used to control whether the set value is returned.
539542

543+
``initArray`` will clear an existing array (set it to empty) or create a new empty array if it does not exist. This is useful for resetting arrays inside loops or before reusing them in a template.
544+
540545
.. note::
541546

542547
Each templating session has its own key value store, which means all the data you set will be cleared after the current response is rendered.
@@ -601,7 +606,7 @@ You can use the following helper methods to join, split or replace string values
601606
+-----------------------------------------------------------+-----------------------------------------------------------+-----------------------------------------+
602607
| Description | Example | Result |
603608
+===========================================================+===========================================================+=========================================+
604-
| String concatenate | ``{{ concat 'bee' 'hive' }}`` | beehive |
609+
| String concatenate | ``{{ concat 'bee' 'hive' 'buzz' }}`` | beehivebuzz |
605610
+-----------------------------------------------------------+-----------------------------------------------------------+-----------------------------------------+
606611
| String splitting | ``{{ split 'bee,hive' ',' }}`` | []string{"bee", "hive"} |
607612
+-----------------------------------------------------------+-----------------------------------------------------------+-----------------------------------------+

vendor/github.com/SpectoLabs/raymond/eval.go

Lines changed: 76 additions & 45 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)