Documentation
¶
Overview ¶
Package fn uses a gloo-foo command as an ordinary Go data function.
A gloo command is a github.com/gloo-foo/framework.Command[[]byte, []byte]: a transform over a stream of input lines. That shape is ideal for wiring pipelines and Unix executables, but awkward to call from ordinary code, where you have a buffer or a reader and want a buffer or a reader back. This package closes that gap: it adapts any command — one command, or several composed — into a Pipeline whose method values are plain, directly-callable functions over standard data types.
pipeline := fn.Chain(grep, sort, uniq) // fn.Pipeline
run := pipeline.String // func(string) (string, error)
out, err := run("my input") // call it like any function
Three data shapes are offered, all from the same command:
- Buffered: Pipeline.Bytes, Pipeline.String, Pipeline.Lines read the whole input and return the whole output — for finite data.
- Streaming: Pipeline.Reader returns a lazy io.ReadCloser that pulls output as it is read, so unbounded input (yes | head) never buffers.
Output framing matches a shell filter: each result line is written followed by '\n', so fn.Of(cat).String("abc") yields "abc\n" — identical to printf 'abc' | cat. Pipeline.Lines returns the lines without terminators.
A Pipeline is an immutable value: safe to copy, reuse, and share.
Example (NormalFunction) ¶
A composed pipeline is called like an ordinary function over string data.
package main
import (
"bytes"
"fmt"
gloo "github.com/gloo-foo/framework"
"github.com/gloo-foo/framework/patterns"
"github.com/gloo-foo/fn"
)
// upper is a stand-in command; a real program passes a cmd-* command (Cat, Grep,
// Sort, …) or any Command[[]byte, []byte].
func upper() gloo.Command[[]byte, []byte] {
return patterns.Map(func(line []byte) ([]byte, error) {
return bytes.ToUpper(line), nil
})
}
func keepNonEmpty() gloo.Command[[]byte, []byte] {
return patterns.Filter(func(line []byte) (bool, error) {
return len(line) > 0, nil
})
}
func main() {
pipeline := fn.Chain(upper(), keepNonEmpty())
out, err := pipeline.String("hello\n\nworld")
if err != nil {
panic(err)
}
fmt.Printf("%q\n", out)
}
Output: "HELLO\nWORLD\n"
Index ¶
- type Pipeline
- func (p Pipeline) Bytes(input []byte) ([]byte, error)
- func (p Pipeline) BytesContext(ctx context.Context, input []byte) ([]byte, error)
- func (p Pipeline) Lines(input []byte) ([]string, error)
- func (p Pipeline) LinesContext(ctx context.Context, input []byte) ([]string, error)
- func (p Pipeline) Reader(input io.Reader) io.ReadCloser
- func (p Pipeline) ReaderContext(ctx context.Context, input io.Reader) io.ReadCloser
- func (p Pipeline) String(input string) (string, error)
- func (p Pipeline) StringContext(ctx context.Context, input string) (string, error)
- func (p Pipeline) To(next gloo.Command[[]byte, []byte]) Pipeline
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Pipeline ¶
type Pipeline struct {
// contains filtered or unexported fields
}
Pipeline is a gloo command — one command or several composed — in ordinary data-function form. Its method values (Pipeline.Bytes, Pipeline.String, Pipeline.Lines, Pipeline.Reader) are plain, directly-callable functions over standard byte and reader data.
It is an immutable value with value-receiver methods: safe to copy, reuse across calls, and share across goroutines. Each call runs the command over its own fresh input, so one Pipeline serves many invocations.
func Chain ¶
Chain composes commands left to right into a single Pipeline, feeding each command's output stream to the next. With no arguments it is the identity pipeline (input passes through unchanged).
func (Pipeline) Bytes ¶
Bytes runs the pipeline over input and returns the whole output, each result line terminated by '\n' — matching a shell filter. It uses context.Background; see Pipeline.BytesContext to pass a context.
Example ¶
Bytes runs a command over a whole buffer.
package main
import (
"bytes"
"fmt"
gloo "github.com/gloo-foo/framework"
"github.com/gloo-foo/framework/patterns"
"github.com/gloo-foo/fn"
)
// upper is a stand-in command; a real program passes a cmd-* command (Cat, Grep,
// Sort, …) or any Command[[]byte, []byte].
func upper() gloo.Command[[]byte, []byte] {
return patterns.Map(func(line []byte) ([]byte, error) {
return bytes.ToUpper(line), nil
})
}
func main() {
out, _ := fn.Of(upper()).Bytes([]byte("abc"))
fmt.Printf("%q\n", out)
}
Output: "ABC\n"
func (Pipeline) BytesContext ¶
BytesContext is Pipeline.Bytes with an explicit context: cancelling ctx stops the pipeline.
func (Pipeline) Lines ¶
Lines runs the pipeline over input and returns the output as lines, each without its terminator. It uses context.Background; see Pipeline.LinesContext to pass a context.
func (Pipeline) LinesContext ¶
LinesContext is Pipeline.Lines with an explicit context: cancelling ctx stops the pipeline.
func (Pipeline) Reader ¶
func (p Pipeline) Reader(input io.Reader) io.ReadCloser
Reader runs the pipeline over input and returns its output as a lazy reader: output is produced only as the returned reader is read, so unbounded input (yes | head) never buffers. Each result line is emitted followed by '\n'. Any error the pipeline raises surfaces from Read. Close abandons an unfinished read, tearing the pipeline down; reading to io.EOF releases it too — the caller MUST do one or the other, or the producing goroutine blocks forever (the io.Pipe contract). It uses context.Background; see Pipeline.ReaderContext to pass a context.
Example ¶
Reader streams output lazily from a reader, so unbounded input never buffers.
package main
import (
"bytes"
"fmt"
"io"
"strings"
gloo "github.com/gloo-foo/framework"
"github.com/gloo-foo/framework/patterns"
"github.com/gloo-foo/fn"
)
// upper is a stand-in command; a real program passes a cmd-* command (Cat, Grep,
// Sort, …) or any Command[[]byte, []byte].
func upper() gloo.Command[[]byte, []byte] {
return patterns.Map(func(line []byte) ([]byte, error) {
return bytes.ToUpper(line), nil
})
}
func main() {
r := fn.Of(upper()).Reader(strings.NewReader("one\ntwo"))
out, _ := io.ReadAll(r)
fmt.Printf("%q\n", out)
}
Output: "ONE\nTWO\n"
func (Pipeline) ReaderContext ¶
ReaderContext is Pipeline.Reader with an explicit context: cancelling ctx stops the pipeline and the next Read reports the cancellation.
The command runs in a goroutine that pumps its output through an io.Pipe; the returned reader is the pipe's read half. Because io.Pipe is synchronous, the command only advances as the reader consumes it — the source of the laziness and backpressure.
func (Pipeline) String ¶
String is Pipeline.Bytes over string data: it runs the pipeline over input and returns the whole output as a string. It uses context.Background; see Pipeline.StringContext to pass a context.
func (Pipeline) StringContext ¶
StringContext is Pipeline.String with an explicit context: cancelling ctx stops the pipeline.