Skip to content

Commit

Permalink
Merge tag '0.2.0' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
nbari committed Nov 6, 2016
2 parents f8327f4 + b83ddfd commit 52a499b
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 95 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -10,7 +10,7 @@ get:
${GO} get

build: get
${GO} get -u gopkg.in/yaml.v2;
# ${GO} get -u gopkg.in/yaml.v2;
${GO} build -ldflags "-X main.version=${VERSION}" -o ${BIN_NAME} cmd/parser/main.go;

clean:
Expand Down
7 changes: 1 addition & 6 deletions README.md
Expand Up @@ -2,15 +2,10 @@
[![codecov](https://codecov.io/gh/nbari/parser/branch/master/graph/badge.svg)](https://codecov.io/gh/nbari/parser)
[![Go Report Card](https://goreportcard.com/badge/github.com/nbari/parser)](https://goreportcard.com/report/github.com/nbari/parser)

# (naive) parser
# parser

Parse a template using variables in a yaml file

This implementation ignores extra position "spaces" and line brakes is parsing
by strings not by bytes therefore the output may deffer with the original format
of the input.



Usage:

Expand Down
10 changes: 10 additions & 0 deletions changelog.md
@@ -0,0 +1,10 @@
Changelog
=========

## 0.2.0
- parse file by character
- better coverage/tests
- fixed position, extra spaces and line breaks are kept like in the template

## 0.1.2
- naive implementation splitting by lines and spaces
173 changes: 103 additions & 70 deletions parse.go
Expand Up @@ -9,89 +9,122 @@ import (

// Parse parse the template
func (p *Parser) Parse() (string, error) {
s := bufio.NewScanner(p.template)
var (
buffer bytes.Buffer
err error
inLoop bool
inLoopBody bool
lineBuffer []string
lineNum int
placeHolder string
position int
variable string
out bytes.Buffer
buf bytes.Buffer
inLoop bool
lineNum int = 1
loopVariable string
placeHolder string
position int
useBuf bool
)

for s.Scan() {
lineNum++
line := s.Text()
scanner := bufio.NewScanner(strings.NewReader(line))
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
word := scanner.Text()
if strings.HasPrefix(word, p.Delimeter) {
switch word {
case "$for":
inLoop = true
continue
case "$endfor$":
inLoop = false
placeHolder = ""
variable = ""
continue
default:
if !inLoop {
word, err = p.Render(word, lineNum)
if err != nil {
return "", err
scanner := bufio.NewScanner(p.template)
scanner.Split(bufio.ScanRunes)

for scanner.Scan() {
c := scanner.Text()
switch c {
case "\n":
lineNum++
if inLoop && position == 3 {
line := buf.String()
buf.Reset()
if strings.Contains(line, placeHolder) {
// loop Body
if k, ok := p.Variables[loopVariable]; ok {
for _, v := range k.([]interface{}) {
ln := fmt.Sprintf("%s\n",
strings.Replace(line,
placeHolder,
fmt.Sprintf("%v", v),
-1),
)
buf.WriteString(ln)
}
lineBuffer = append(lineBuffer, word)
}
continue
} else if len(line) > 0 {
return "", fmt.Errorf("Error parsing template, please verify the syntax on line %d", lineNum)
}
} else if inLoop && position == 4 {
// to avoid the extra line
inLoop = false
position = 0
} else {
buf.WriteString(c)
}
// For block
if inLoop {
if !inLoopBody {
switch position {
case 0:
placeHolder = fmt.Sprintf("%s%s%s", p.Delimeter, word, p.Delimeter)
case 1:
if word != "in" {
return "", fmt.Errorf("Error parsing template, please verify the syntax on line %d", lineNum)
}
case 2:
if !strings.HasSuffix(word, p.Delimeter) {
return "", fmt.Errorf("Error parsing template, please verify the syntax on line %d", lineNum)
}
variable = strings.Replace(word, p.Delimeter, "", -1)
inLoopBody = true
}
position++
} else {
if strings.Contains(line, placeHolder) {
// loop Body
if k, ok := p.Variables[variable]; ok {
for _, v := range k.([]interface{}) {
ln := fmt.Sprintf("%s\n", strings.Replace(line, placeHolder, v.(string), -1))
buffer.WriteString(ln)
useBuf = false
out.WriteString(buf.String())
buf.Reset()
case p.Delimeter:
buf.WriteString(c)
if useBuf && position == 1 {
return "", fmt.Errorf("Error parsing template, please verify the syntax on line %d", lineNum)
} else if useBuf && position == 2 {
position++
loopVariable = strings.Replace(buf.String(), p.Delimeter, "", -1)
buf.Reset()
continue
} else if useBuf && len(buf.String()) == 2 {
useBuf = false
out.WriteString(buf.String())
buf.Reset()
} else if useBuf && !inLoop {
useBuf = false
variable := buf.String()
buf.Reset()
str, err := p.Render(variable, lineNum)
if err != nil {
return "", err
}
out.WriteString(str)
} else if buf.String() == "$endfor$" {
position++
buf.Reset()
// loop again but don't add extra line
continue
} else {
useBuf = true
}
default:
if inLoop && position == 3 {
buf.WriteString(c)
} else if useBuf {
buf.WriteString(c)
if c == " " {
switch buf.String() {
case "$for ":
inLoop = true
buf.Reset()
default:
if inLoop {
switch position {
case 0:
placeHolder = fmt.Sprintf("%s%s%s",
p.Delimeter,
strings.TrimSpace(buf.String()),
p.Delimeter)
case 1:
if buf.String() != "in " {
return "", fmt.Errorf("Error parsing template, please verify the syntax on line %d", lineNum)
}
case 2:
return "", fmt.Errorf("Error parsing template, please verify the syntax on line %d", lineNum)
}
buf.Reset()
position++
} else {
useBuf = false
out.WriteString(buf.String())
buf.Reset()
}
inLoopBody = false
} else {
return "", fmt.Errorf("Error parsing template, please verify the syntax on line %d", lineNum)
}
}
} else {
lineBuffer = append(lineBuffer, word)
out.WriteString(c)
}
}

if lineBuffer != nil {
buffer.WriteString(fmt.Sprintf("%s\n", strings.Join(lineBuffer, " ")))
lineBuffer = nil
}

}
return buffer.String(), nil
return out.String(), nil
}
47 changes: 30 additions & 17 deletions parser_test.go
Expand Up @@ -17,13 +17,38 @@ func TestParser1(t *testing.T) {
}

expected := `A b c Hola!
o
el $dolar si i$$$$$
100 $$ $$$
100ok$
100 ok
The quick brown Fox likes:
loop test
- apple
- orange
- banana
- apple
- orange
- banana
Whenever you are asked if you can do a job,
tell them, 'Certainly I can!'. Then get busy and find out how to do it.
- Theodore Roosevelt`
- Theodore Roosevelt
1 2 3 4
the $dolar sign$
$$ $$ $$$
100ok$`

if strings.TrimSpace(expected) != strings.TrimSpace(out) {
t.Error("not matching")
Expand All @@ -46,6 +71,7 @@ The $quick brown Fox likes:
- $apple
- $orange
- $banana
Whenever you are asked if you can do a job,
tell them, 'Certainly I can!'. Then get busy and find out how to do it.
- Theodore Roosevelt`
Expand All @@ -61,22 +87,9 @@ func TestParser3(t *testing.T) {
t.Fatal(err)
}

out, err := p.Parse()
if err != nil {
t.Fatal(err)
}

expected := `A b c Hola!
The $quick brown Fox likes:
- $apple
- $orange
- $banana
Whenever you are asked if you can do a job,
tell them, 'Certainly I can!'. Then get busy and find out how to do it.
- Theodore Roosevelt`

if strings.TrimSpace(expected) != strings.TrimSpace(out) {
t.Error("not matching")
_, err = p.Parse()
if err == nil {
t.Error("Expecting error")
}
}

Expand Down
2 changes: 1 addition & 1 deletion replace.go
Expand Up @@ -10,7 +10,7 @@ func (p *Parser) Replace(word string) (string, error) {
v := strings.Replace(word, p.Delimeter, "", -1)
k, ok := p.Variables[v]
if ok {
return k.(string), nil
return fmt.Sprintf("%v", k), nil
}
return "", fmt.Errorf("Variable not found")
}
Expand Down
22 changes: 22 additions & 0 deletions test_data/template.txt
@@ -1,6 +1,28 @@
A b c $hello$!
o

el $dolar si i$$$$$

$ok$ $$ $$$
$ok$ok$
$ok$ ok


The quick brown $unit_type$ likes:

$for$ test

$for frut in fruit$
- $frut$
- $frut$
$endfor$

$footer_quote$

1 2 3 4

the $dolar sign$

$$ $$ $$$

$ok$ok$
30 changes: 30 additions & 0 deletions test_data/template1.txt
@@ -0,0 +1,30 @@
A b c $hello$!
o

el $dolar si i$$$$$

$ok$ $$ $$$
$ok$ok$
$ok$ ok


The quick brown $unit_type$ likes:
$for frut in fruit$
- $frut$
- $frut$
$endfor$

second loop:
$for frut in fruit$
- $frut$ $--
$endfor$

$footer_quote$

1 2 3 4

the $dolar sign$

$$ $$ $$$

$ok$ok$
1 change: 1 addition & 0 deletions test_data/template2.txt
Expand Up @@ -3,4 +3,5 @@ The $quick brown $unit_type$ likes:
$for frut in fruit$
- $$frut$
$endfor$

$footer_quote$
6 changes: 6 additions & 0 deletions test_data/template8.txt
@@ -1,6 +1,12 @@
A b c $hello$!
The $quick brown $unit_type$ likes:
$for x in key value$
-xxx
$endfor$

$for x in fruit$
- $frut$
$endfor$
$footer_quote$

$for x in key value$
2 changes: 2 additions & 0 deletions test_data/variables.yaml
@@ -1,3 +1,5 @@
ok: 100
for: loop
hello: Hola
unit_type: Fox
fruit:
Expand Down

0 comments on commit 52a499b

Please sign in to comment.