Skip to content

Commit

Permalink
Expression command (#91)
Browse files Browse the repository at this point in the history
plaintext and stdin support
  • Loading branch information
zix99 authored Apr 28, 2023
1 parent 4b0d0eb commit 28c1cfc
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 17 deletions.
4 changes: 3 additions & 1 deletion cmd/commands_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"fmt"
"os"
"rare/pkg/testutil"
"testing"
Expand Down Expand Up @@ -33,7 +34,8 @@ func testCommand(command *cli.Command, cmd string) error {
command,
}
app.ExitErrHandler = func(context *cli.Context, err error) {
// disabled
// disabled failure
fmt.Fprint(os.Stderr, err.Error())
}

commandArgs := append([]string{"app", "_testcommand"}, testutil.SplitQuotedString(cmd)...)
Expand Down
55 changes: 40 additions & 15 deletions cmd/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package cmd
import (
"errors"
"fmt"
"io"
"os"
"rare/pkg/color"
"rare/pkg/expressions"
"rare/pkg/expressions/exprofiler"
Expand All @@ -18,33 +20,44 @@ import (

func expressionFunction(c *cli.Context) error {
var (
expString = c.Args().First()
noOptimize = c.Bool("no-optimize")
data = c.StringSlice("data")
keyPairs = c.StringSlice("key")
benchmark = c.Bool("benchmark")
stats = c.Bool("stats")
expString = c.Args().First()
noOptimize = c.Bool("no-optimize")
data = c.StringSlice("data")
keyPairs = c.StringSlice("key")
benchmark = c.Bool("benchmark")
stats = c.Bool("stats")
skipNewline = c.Bool("skip-newline")
detailed = stats || benchmark
)

if c.NArg() != 1 {
return errors.New("expected exactly 1 expression argument")
return errors.New("expected exactly 1 expression argument. Use - for stdin")
}

if expString == "" {
return errors.New("empty expression")
}
if expString == "-" {
b, err := io.ReadAll(os.Stdin)
if err != nil {
return errors.New("error reading input")
}
expString = string(b)
}

builder := stdlib.NewStdKeyBuilderEx(!noOptimize)
compiled, err := builder.Compile(expString)

if err != nil {
fmt.Fprint(os.Stderr, err.Error())
return errors.New("compile error")
}

expCtx := expressions.KeyBuilderContextArray{
Elements: data,
Keys: parseKeyValuesIntoMap(keyPairs...),
}

if err != nil {
return err
}

// Emulate special keys
{
keys := parseKeyValuesIntoMap(keyPairs...)
Expand All @@ -58,9 +71,16 @@ func expressionFunction(c *cli.Context) error {
}

// Output results
fmt.Printf("Expression: %s\n", color.Wrap(color.BrightWhite, expString))
result := compiled.BuildKey(&expCtx)
fmt.Printf("Result: %s\n", color.Wrap(color.BrightYellow, result))
if detailed {
fmt.Printf("Expression: %s\n", color.Wrap(color.BrightWhite, expString))
fmt.Printf("Result: %s\n", color.Wrap(color.BrightYellow, result))
} else {
fmt.Print(result)
if !skipNewline {
fmt.Println()
}
}

if stats {
stats := exprofiler.GetMetrics(compiled, &expCtx)
Expand Down Expand Up @@ -119,13 +139,18 @@ func buildSpecialKeyJson(matches []string, values map[string]string) string {
func expressionCommand() *cli.Command {
return &cli.Command{
Name: "expression",
Usage: "Test and benchmark expressions",
Usage: "Evaluate and benchmark expressions",
Description: "Given an expression, and optionally some data, test the output and performance of an expression",
ArgsUsage: "<expression>",
ArgsUsage: "<expression|->",
Aliases: []string{"exp"},
Action: expressionFunction,
Category: cmdCatHelp,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "skip-newline",
Aliases: []string{"n"},
Usage: "Don't add a newline character when printing plain result",
},
&cli.BoolFlag{
Name: "benchmark",
Aliases: []string{"b"},
Expand Down
39 changes: 39 additions & 0 deletions cmd/expressions_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package cmd

import (
"os"
"rare/pkg/testutil"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -14,6 +16,26 @@ func TestExpressionCmd(t *testing.T) {
)
}

func TestExpressionOnlyOutput(t *testing.T) {
o, e, err := testCommandCapture(expressionCommand(), `-d bob "hello {0}"`)
assert.NoError(t, err)
assert.Equal(t, e, "")
assert.Equal(t, o, "hello bob\n")
}

func TestExpressionReadStdin(t *testing.T) {
o, e, err := testutil.Capture(func(w *os.File) error {
go func() {
w.WriteString("hello {0}")
w.Close()
}()
return testCommand(expressionCommand(), `-n -d bob -`)
})
assert.NoError(t, err)
assert.Equal(t, e, "")
assert.Equal(t, o, "hello bob")
}

func TestExpressionResults(t *testing.T) {
o, e, err := testCommandCapture(expressionCommand(), `-s -d bob "abc {0}"`)
assert.NoError(t, err)
Expand All @@ -30,6 +52,23 @@ Stats
`, o)
}

func TestExpressionErrors(t *testing.T) {
o, e, err := testCommandCapture(expressionCommand(), "")
assert.Error(t, err)
assert.Empty(t, o)
assert.NotEmpty(t, e)

o, e, err = testCommandCapture(expressionCommand(), `-s ""`)
assert.Error(t, err)
assert.Empty(t, o)
assert.NotEmpty(t, e)

o, e, err = testCommandCapture(expressionCommand(), `-s "unterm {"`)
assert.Error(t, err)
assert.Empty(t, o)
assert.NotEmpty(t, e)
}

func TestKeyParser(t *testing.T) {
k, v := parseKeyValue("")
assert.Empty(t, k)
Expand Down
2 changes: 1 addition & 1 deletion cmd/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func TestFilterFileNotExist(t *testing.T) {
assert.Error(t, err)
assert.Equal(t, 2, err.(cli.ExitCoder).ExitCode())
assert.Equal(t, "", out)
assert.Equal(t, "Matched: 0 / 0\n", eout)
assert.Equal(t, "Matched: 0 / 0\nRead errors", eout)
}

func TestFilterNoMatches(t *testing.T) {
Expand Down

0 comments on commit 28c1cfc

Please sign in to comment.