Skip to content

implement start & end delimiters #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 27 additions & 14 deletions interpol.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,37 @@ func New(opts ...Option) *Interpolator {

// NewWithOptions creates a new interpolator with the given options.
func NewWithOptions(opts *Options) *Interpolator {
startDelimiter := '{'
endDelimiter := '}'
var empty rune
if opts.StartDelimiter != empty {
startDelimiter = opts.StartDelimiter
}
if opts.EndDelimiter != empty {
endDelimiter = opts.EndDelimiter
}
return &Interpolator{
template: templateReader(opts),
output: outputWriter(opts),
format: opts.Format,
rb: make([]rune, 0, 64),
start: -1,
closing: false,
startDelimiter: startDelimiter,
endDelimiter: endDelimiter,
template: templateReader(opts),
output: outputWriter(opts),
format: opts.Format,
rb: make([]rune, 0, 64),
start: -1,
closing: false,
}
}

// Interpolator interpolates Template to Output, according to Format.
type Interpolator struct {
template io.RuneReader
output runeWriter
format Func
rb []rune
start int
closing bool
template io.RuneReader
output runeWriter
format Func
rb []rune
start int
closing bool
startDelimiter rune
endDelimiter rune
}

// Interpolate reads runes from Template and writes them to Output, with the
Expand All @@ -75,9 +88,9 @@ func (i *Interpolator) Interpolate() error {

func (i *Interpolator) parse(r rune, pos int) error {
switch r {
case '{':
case i.startDelimiter:
return i.open(pos)
case '}':
case i.endDelimiter:
return i.close()
default:
return i.append(r)
Expand Down
32 changes: 32 additions & 0 deletions interpol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,38 @@ func TestWithMapKeyNotFound(t *testing.T) {
}
}

func TestWithMapKeyExistsDifferentDelimiters(t *testing.T) {
m := map[string]string{
"test": "World",
"data": "!!!",
}
buffer := bytes.NewBuffer(nil)
format := func(key string, w io.Writer) error {
value, ok := m[key]
if !ok {
return ErrKeyNotFound
}
_, err := w.Write([]byte(value))
return err
}
opts := &Options{
Template: strings.NewReader(`{"hello": "<test><data>"}`),
Output: buffer,
Format: format,
StartDelimiter: '<',
EndDelimiter: '>',
}
i := NewWithOptions(opts)
err := i.Interpolate()
if err != nil {
t.Fatal(err)
}
got := buffer.String()
if got != `{"hello": "World!!!"}` {
t.Errorf("Invalid string: %q", got)
}
}

func TestWithMapNil(t *testing.T) {
str, err := WithMap("hello {test}!!!", nil)
if len(str) != 0 || err != ErrKeyNotFound {
Expand Down
8 changes: 5 additions & 3 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import "io"

// Options contains all options supported by an Interpolator.
type Options struct {
Template io.Reader
Format Func
Output io.Writer
Template io.Reader
Format Func
Output io.Writer
StartDelimiter rune
EndDelimiter rune
}

// Option is an option that can be applied to an Interpolator.
Expand Down