Skip to content
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

function driver #3

Merged
merged 11 commits into from
Sep 22, 2023
Merged
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
2 changes: 1 addition & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ FROM adrienaury/go-devcontainer:v3.1

USER root

RUN apk add --update --progress --no-cache make gomplate
RUN apk add --update --progress --no-cache make gomplate jq

ARG VERSION_GOLICENSE=0.2.0
ARG VERSION_MILLER=6.8.0
Expand Down
2 changes: 1 addition & 1 deletion cmd/xixo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ There is NO WARRANTY, to the extent permitted by law.`, version, commit, buildDa
}

func run(_ *cobra.Command) error {
driver := xixo.NewDriver(os.Stdin, os.Stdout, subscribers)
driver := xixo.NewShellDriver(os.Stdin, os.Stdout, subscribers)

err := driver.Stream()
if err != nil {
Expand Down
44 changes: 40 additions & 4 deletions pkg/xixo/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,67 @@ import (
"io"
)

type Driver struct {
// ShellDriver represents a driver that processes XML using shell commands.
type ShellDriver struct {
parser *XMLParser
processes []*Process
}

func NewDriver(reader io.Reader, writer io.Writer, callbacks map[string]string) Driver {
// NewShellDriver creates a new ShellDriver instance with the given reader, writer, and callbacks.
func NewShellDriver(reader io.Reader, writer io.Writer, callbacks map[string]string) ShellDriver {
// Create a new XML parser with XPath enabled and initialize processes.
parser := NewXMLParser(reader, writer).EnableXpath()
processes := []*Process{}

// Iterate through the callbacks and create a process for each element.
for elementName, shell := range callbacks {
process := NewProcess(shell)
// Register a JSON callback for the element and add the process to the list.
parser.RegisterJSONCallback(elementName, process.Callback())
processes = append(processes, process)
}

return Driver{parser: parser, processes: processes}
// Return the ShellDriver with the parser and processes.
return ShellDriver{parser: parser, processes: processes}
}

func (d Driver) Stream() error {
// Stream processes the XML using the registered processes and returns any error encountered.
func (d ShellDriver) Stream() error {
// Start each process in parallel.
for _, process := range d.processes {
if err := process.Start(); err != nil {
return err
}
}

// Stream the XML using the parser and return any error encountered.
err := d.parser.Stream()

return err
}

// FuncDriver represents a driver that processes XML using callback functions.
type FuncDriver struct {
parser *XMLParser
}

// NewFuncDriver creates a new FuncDriver instance with the given reader, writer, and callbacks.
func NewFuncDriver(reader io.Reader, writer io.Writer, callbacks map[string]CallbackMap) FuncDriver {
// Create a new XML parser with XPath enabled.
parser := NewXMLParser(reader, writer).EnableXpath()

// Register callback functions for each element.
for elementName, function := range callbacks {
parser.RegisterMapCallback(elementName, function)
}

// Return the FuncDriver with the parser.
return FuncDriver{parser: parser}
}

// Stream processes the XML using registered callback functions and returns any error encountered.
func (d FuncDriver) Stream() error {
// Stream the XML using the parser and return any error encountered.
err := d.parser.Stream()

return err
Expand Down
36 changes: 34 additions & 2 deletions pkg/xixo/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,50 @@ import (
"github.com/youen/xixo/pkg/xixo"
)

// TestMapCallback should convert.
// TestDriverSimpleEdit tests the ShellDriver by creating a reader, writer, and a map of subscribers,
// then it processes the XML and asserts the expected output.
func TestDriverSimpleEdit(t *testing.T) {
t.Parallel()

// Create a reader with an XML string, an empty writer, and a map of subscribers.
reader := bytes.NewBufferString("<root><element1>innerTexta</element1></root>")
writer := bytes.Buffer{}
subscribers := map[string]string{"root": "tr a b"}
driver := xixo.NewDriver(reader, &writer, subscribers)
driver := xixo.NewShellDriver(reader, &writer, subscribers)

// Stream the XML using the driver and assert the expected output.
err := driver.Stream()
assert.Nil(t, err)

expected := "<root>\n <element1>innerTextb</element1>\n</root>"
assert.Equal(t, expected, writer.String())
}

// TestFuncDriverEdit tests the FuncDriver by creating a reader, writer, and a callback function,
// then it processes the XML and asserts the expected output and that the callback was called.
func TestFuncDriverEdit(t *testing.T) {
t.Parallel()

// Create a reader with an XML string, an empty writer, a callback function, and a driver.
reader := bytes.NewBufferString("<root><element1>innerTexta</element1></root>")
writer := bytes.Buffer{}
called := false
callback := func(input map[string]string) (map[string]string, error) {
called = true
input["element1"] = "innerTextb"

return input, nil
}

subscribers := map[string]xixo.CallbackMap{"root": callback}
driver := xixo.NewFuncDriver(reader, &writer, subscribers)

// Stream the XML using the driver, assert the expected output, and check if the callback was called.
err := driver.Stream()
assert.Nil(t, err)

assert.True(t, called)

expected := "<root>\n <element1>innerTextb</element1>\n</root>"
assert.Equal(t, expected, writer.String())
}
15 changes: 13 additions & 2 deletions pkg/xixo/element.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package xixo

import "fmt"
import (
"fmt"
"strings"
)

type XMLElement struct {
Name string
Expand Down Expand Up @@ -90,8 +93,16 @@ func (n *XMLElement) String() string {
xmlChilds = "\n" + xmlChilds
}

attributes := n.Name + " "

for _, attr := range n.attrs {
attributes += fmt.Sprintf("%s=\"%s\" ", attr.name, attr.value)
}

attributes = strings.Trim(attributes, " ")

return fmt.Sprintf("<%s>%s%s</%s>",
n.Name,
attributes,
n.InnerText,
xmlChilds,
n.Name)
Expand Down
4 changes: 4 additions & 0 deletions pkg/xixo/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ func (x *XMLParser) RegisterJSONCallback(match string, callback CallbackJSON) {
x.loopElements[match] = XMLElementToJSONCallback(callback)
}

func (x *XMLParser) RegisterMapCallback(match string, callback CallbackMap) {
x.loopElements[match] = XMLElementToMapCallback(callback)
}

func (x *XMLParser) SkipElements(skipElements []string) *XMLParser {
if len(skipElements) > 0 {
for _, s := range skipElements {
Expand Down
2 changes: 2 additions & 0 deletions test/data/debug_foo_bar_baz_input_expected.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{"bar":"a","baz":"z"}
{"bar":"b"}
20 changes: 10 additions & 10 deletions test/data/foo_bar_baz.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<root>
<foo>
<bar>a</bar>
<baz>z</baz>
</foo>
<foo>
<bar>b</bar>
</foo>
<baz>
<bar>c</bar>
</baz>
<foo>
<bar>a</bar>
<baz fuz="faz">z</baz>
</foo>
<foo>
<bar>b</bar>
</foo>
<baz>
<bar>c</bar>
</baz>
</root>
12 changes: 12 additions & 0 deletions test/data/foo_bar_baz_expected.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<root>
<foo>
<bar>A</bar>
<baz fuz="faz">z</baz>
</foo>
<foo>
<bar>B</bar>
</foo>
<baz>
<bar>c</bar>
</baz>
</root>
17 changes: 17 additions & 0 deletions test/suites/01-run-cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,23 @@ testcases:
- result.systemerr ShouldBeEmpty
- result.systemout ShouldBeEmpty

- name: foo bar example
steps:
- script: cat ../data/foo_bar_baz.xml | xixo --subscribers foo="tee ../workspace/debug_foo_bar_baz_input.jsonl | jq --unbuffered -c '.bar |= ascii_upcase' " > ../workspace/foo_bar_baz.xml
assertions:
- result.code ShouldEqual 0
- result.systemerr ShouldBeEmpty
- script: diff ../data/foo_bar_baz_expected.xml ../workspace/foo_bar_baz.xml
assertions:
- result.code ShouldEqual 0
- result.systemerr ShouldBeEmpty
- result.systemout ShouldBeEmpty
- script: diff ../data/debug_foo_bar_baz_input_expected.jsonl ../workspace/debug_foo_bar_baz_input.jsonl
assertions:
- result.code ShouldEqual 0
- result.systemerr ShouldBeEmpty
- result.systemout ShouldBeEmpty

# - name: copy stream content of user entities in users.xml
# steps:
# - script: cat ../data/users.xml | xixo --subscribers user=cat > ../workspace/users.xml
Expand Down
Loading