Skip to content

Commit

Permalink
Merge pull request #166 from hairyhenderson/enhance-indent-165
Browse files Browse the repository at this point in the history
Enhancing indent function
  • Loading branch information
hairyhenderson authored Jun 14, 2017
2 parents 19c7f34 + d57d2c7 commit 2e4a4b1
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 58 deletions.
21 changes: 0 additions & 21 deletions docs/content/functions/general.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,27 +132,6 @@ $ gomplate -f input.tmpl
1-2-3
```

## `indent`

Indents a given string with the given indentation pattern. If the input string has multiple lines, each line will be indented.

#### Example

This function can be especially useful when adding YAML snippets into other YAML documents, where indentation is important:

_`input.tmpl`:_
```
foo:
{{ `{"bar": {"baz": 2}}` | json | toYAML | indent " " }}
```

```console
$ gomplate -f input.tmpl
foo:
bar:
baz: 2
```

## `json`

Converts a JSON string into an object. Only works for JSON Objects (not Arrays or other valid JSON types). This can be used to access properties of JSON objects.
Expand Down
46 changes: 46 additions & 0 deletions docs/content/functions/strings.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,52 @@ $ URL=http://example.com gomplate < input.tmpl
http://example.com:80
```

## `strings.Indent`

**Alias:** `indent`

Indents a string. If the input string has multiple lines, each line will be indented.

### Usage
```go
strings.Indent [width] [indent] input
```
```go
input | strings.Indent [width] [indent]
```

### Arguments

| name | description |
|--------|-------|
| `width` | _(optional)_ number of times to repeat the `indent` string. Default: `1` |
| `indent` | _(optional)_ the string to indent with. Default: `" "` |
| `input` | the string to indent |

### Example

This function can be especially useful when adding YAML snippets into other YAML documents, where indentation is important:

_`input.tmpl`:_
```
foo:
{{ `{"bar": {"baz": 2}}` | json | toYAML | strings.Indent " " }}
{{- `{"qux": true}` | json | toYAML | strings.Indent 2 }}
quux:
{{ `{"quuz": 42}` | json | toYAML | strings.Indent 2 " " -}}
```

```console
$ gomplate -f input.tmpl
foo:
bar:
baz: 2
qux: true

quux:
quuz: 42
```

## `strings.Split`

Creates a slice by splitting a string on a given delimiter.
Expand Down
1 change: 0 additions & 1 deletion funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ func initFuncs(data *Data) template.FuncMap {
"csvByRow": typeconv.CSVByRow,
"csvByColumn": typeconv.CSVByColumn,
"slice": typeconv.Slice,
"indent": typeconv.indent,
"join": typeconv.Join,
"toJSON": typeconv.ToJSON,
"toJSONPretty": typeconv.toJSONPretty,
Expand Down
35 changes: 35 additions & 0 deletions funcs/strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ package funcs
// in templates easier.

import (
"log"
"sync"

"strings"

gompstrings "github.com/hairyhenderson/gomplate/strings"
)

var (
Expand All @@ -31,6 +34,7 @@ func AddStringFuncs(f map[string]interface{}) {
f["toUpper"] = StrNS().ToUpper
f["toLower"] = StrNS().ToLower
f["trimSpace"] = StrNS().TrimSpace
f["indent"] = StrNS().Indent

// these are legacy aliases with non-pipelinable arg order
f["contains"] = strings.Contains
Expand Down Expand Up @@ -98,3 +102,34 @@ func (f *StringFuncs) ToLower(s string) string {
func (f *StringFuncs) TrimSpace(s string) string {
return strings.TrimSpace(s)
}

// Indent -
func (f *StringFuncs) Indent(args ...interface{}) string {
input, ok := args[len(args)-1].(string)
if !ok {
log.Fatal("Indent: invalid arguments")
}
indent := " "
width := 1
switch len(args) {
case 2:
indent, ok = args[0].(string)
if !ok {
width, ok = args[0].(int)
if !ok {
log.Fatal("Indent: invalid arguments")
}
indent = " "
}
case 3:
width, ok = args[0].(int)
if !ok {
log.Fatal("Indent: invalid arguments")
}
indent, ok = args[1].(string)
if !ok {
log.Fatal("Indent: invalid arguments")
}
}
return gompstrings.Indent(width, indent, input)
}
8 changes: 8 additions & 0 deletions funcs/strings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,11 @@ func TestReplaceAll(t *testing.T) {
assert.Equal(t, "ReplacedReplaced",
sf.ReplaceAll("Orig", "Replaced", "OrigOrig"))
}

func TestIndent(t *testing.T) {
sf := &StringFuncs{}
assert.Equal(t, " foo\n bar\n baz", sf.Indent("foo\nbar\nbaz"))
assert.Equal(t, " foo\n bar\n baz", sf.Indent(" ", "foo\nbar\nbaz"))
assert.Equal(t, "---foo\n---bar\n---baz", sf.Indent(3, "-", "foo\nbar\nbaz"))
assert.Equal(t, " foo\n bar\n baz", sf.Indent(3, "foo\nbar\nbaz"))
}
21 changes: 21 additions & 0 deletions strings/strings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package strings

import "strings"

// Indent - indent each line of the string with the given indent string
func Indent(width int, indent, s string) string {
if width > 1 {
indent = strings.Repeat(indent, width)
}
var res []byte
bol := true
for i := 0; i < len(s); i++ {
c := s[i]
if bol && c != '\n' {
res = append(res, indent...)
}
res = append(res, c)
bol = c == '\n'
}
return string(res)
}
17 changes: 17 additions & 0 deletions strings/strings_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package strings

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestIndent(t *testing.T) {
actual := "hello\nworld\n!"
expected := " hello\n world\n !"
assert.Equal(t, expected, Indent(1, " ", actual))
assert.Equal(t, "\n", Indent(1, " ", "\n"))
assert.Equal(t, " foo\n", Indent(1, " ", "foo\n"))
assert.Equal(t, " foo", Indent(1, " ", "foo"))
assert.Equal(t, " foo", Indent(3, " ", "foo"))
}
30 changes: 30 additions & 0 deletions test/integration/strings.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bats

load helper

tmpdir=$(mktemp -u)

function setup () {
mkdir -p $tmpdir
}

function teardown () {
rm -rf $tmpdir || true
}

@test "'strings.Indent'" {
gomplate -i '{{ strings.Indent " " "hello world" }}
{{ "hello\nmultiline\nworld" | indent 2 "-" }}
{{ "foo\nbar" | strings.Indent 2 }}
{{"hello\nworld" | strings.Indent 5 | strings.TrimSpace }}
'
[ "$status" -eq 0 ]
[[ "${output}" == " hello world
--hello
--multiline
--world
foo
bar
hello
world" ]]
}
8 changes: 0 additions & 8 deletions test/integration/typeconv_funcs.bats
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,6 @@ function teardown () {
}' ]]
}

@test "indent" {
gomplate -i '{{ indent " " "hello world" }}{{ "hello\nmultiline\nworld" | indent " " }}'
[ "$status" -eq 0 ]
[[ "${output}" == " hello world hello
multiline
world" ]]
}

@test "join" {
gomplate -i '{{ $a := `[1, 2, 3]` | jsonArray }}{{ join $a "-" }}'
[ "$status" -eq 0 ]
Expand Down
15 changes: 0 additions & 15 deletions typeconv.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,21 +272,6 @@ func (t *TypeConv) Slice(args ...interface{}) []interface{} {
return args
}

// Indent - indent each line of the string with the given indent string
func (t *TypeConv) indent(indent, s string) string {
var res []byte
bol := true
for i := 0; i < len(s); i++ {
c := s[i]
if bol && c != '\n' {
res = append(res, indent...)
}
res = append(res, c)
bol = c == '\n'
}
return string(res)
}

// Join concatenates the elements of a to create a single string.
// The separator string sep is placed between elements in the resulting string.
//
Expand Down
13 changes: 0 additions & 13 deletions typeconv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,19 +170,6 @@ func TestHas(t *testing.T) {
assert.True(t, ty.Has(in["baz"], "qux"))
}

func TestIndent(t *testing.T) {
ty := new(TypeConv)
actual := "hello\nworld\n!"
expected := " hello\n world\n !"
assert.Equal(t, expected, ty.indent(" ", actual))

assert.Equal(t, "\n", ty.indent(" ", "\n"))

assert.Equal(t, " foo\n", ty.indent(" ", "foo\n"))

assert.Equal(t, " foo", ty.indent(" ", "foo"))
}

func TestCSV(t *testing.T) {
ty := new(TypeConv)
in := "first,second,third\n1,2,3\n4,5,6"
Expand Down

0 comments on commit 2e4a4b1

Please sign in to comment.