mirror of
https://github.com/therootcompany/golib.git
synced 2025-10-12 20:18:16 +00:00
251 lines
5.7 KiB
Go
251 lines
5.7 KiB
Go
package transform
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"math/rand"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func Rot13(r io.Reader) *Transformer {
|
|
buf := make([]byte, rand.Int()%256+1) // used to test varying slice sizes
|
|
//buf := make([]byte, 256)
|
|
return NewTransformer(func() ([]byte, error) {
|
|
n, err := r.Read(buf)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := 0; i < n; i++ {
|
|
if buf[i] >= 'a' && buf[i] <= 'z' {
|
|
buf[i] = ((buf[i] - 'a' + 13) % 26) + 'a'
|
|
} else if buf[i] >= 'A' && buf[i] <= 'Z' {
|
|
buf[i] = ((buf[i] - 'A' + 13) % 26) + 'A'
|
|
}
|
|
}
|
|
return buf[:n], nil
|
|
})
|
|
}
|
|
|
|
func TestTransformer(t *testing.T) {
|
|
// simple
|
|
msg := "Hello\n13th Floor"
|
|
data, err := ioutil.ReadAll(Rot13(Rot13(bytes.NewBufferString(msg))))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if msg != string(data) {
|
|
t.Fatalf("expected '%v', got '%v'\n", msg, string(data))
|
|
}
|
|
// random
|
|
rand.Seed(time.Now().UnixNano())
|
|
buf := make([]byte, 10000)
|
|
for i := 0; i < 1000; i++ {
|
|
_, err := rand.Read(buf)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
data, err := ioutil.ReadAll(Rot13(Rot13(bytes.NewBuffer(buf))))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(buf) != string(data) {
|
|
t.Fatalf("expected '%v', got '%v'\n", string(buf), string(data))
|
|
}
|
|
}
|
|
}
|
|
|
|
func ExampleTransformer_rot13() {
|
|
// Rot13 transformation
|
|
rot13 := func(r io.Reader) *Transformer {
|
|
buf := make([]byte, 256)
|
|
return NewTransformer(func() ([]byte, error) {
|
|
n, err := r.Read(buf)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := 0; i < n; i++ {
|
|
if buf[i] >= 'a' && buf[i] <= 'z' {
|
|
buf[i] = ((buf[i] - 'a' + 13) % 26) + 'a'
|
|
} else if buf[i] >= 'A' && buf[i] <= 'Z' {
|
|
buf[i] = ((buf[i] - 'A' + 13) % 26) + 'A'
|
|
}
|
|
}
|
|
return buf[:n], nil
|
|
})
|
|
}
|
|
// Pass the string though the transformer.
|
|
out, err := ioutil.ReadAll(rot13(bytes.NewBufferString("Hello World")))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Printf("%s\n", out)
|
|
// Output:
|
|
// Uryyb Jbeyq
|
|
}
|
|
|
|
func ExampleTransformer_toUpper() {
|
|
// Convert a string to uppper case. Unicode aware.
|
|
toUpper := func(r io.Reader) *Transformer {
|
|
br := bufio.NewReader(r)
|
|
return NewTransformer(func() ([]byte, error) {
|
|
c, _, err := br.ReadRune()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return []byte(strings.ToUpper(string([]rune{c}))), nil
|
|
})
|
|
}
|
|
// Pass the string though the transformer.
|
|
out, err := ioutil.ReadAll(toUpper(bytes.NewBufferString("Hello World")))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Printf("%s\n", out)
|
|
// Output:
|
|
// HELLO WORLD
|
|
}
|
|
|
|
func ExampleTransformer_lineMatcherRegExp() {
|
|
// Filter lines matching a pattern
|
|
matcher := func(r io.Reader, pattern string) *Transformer {
|
|
br := bufio.NewReader(r)
|
|
return NewTransformer(func() ([]byte, error) {
|
|
for {
|
|
line, err := br.ReadBytes('\n')
|
|
matched, _ := regexp.Match(pattern, line)
|
|
if matched {
|
|
return line, err
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
logs := `
|
|
23 Apr 17:32:23.604 [INFO] DB loaded in 0.551 seconds
|
|
23 Apr 17:32:23.605 [WARN] Disk space is low
|
|
23 Apr 17:32:23.054 [INFO] Server started on port 7812
|
|
23 Apr 17:32:23.141 [INFO] Ready for connections
|
|
`
|
|
// Pass the string though the transformer.
|
|
out, err := ioutil.ReadAll(matcher(bytes.NewBufferString(logs), "WARN"))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Printf("%s\n", out)
|
|
// Output:
|
|
// 23 Apr 17:32:23.605 [WARN] Disk space is low
|
|
}
|
|
|
|
func ExampleTransformer_trimmer() {
|
|
// Trim space from all lines
|
|
trimmer := func(r io.Reader) *Transformer {
|
|
br := bufio.NewReader(r)
|
|
return NewTransformer(func() ([]byte, error) {
|
|
for {
|
|
line, err := br.ReadBytes('\n')
|
|
if len(line) > 0 {
|
|
line = append(bytes.TrimSpace(line), '\n')
|
|
}
|
|
return line, err
|
|
}
|
|
})
|
|
}
|
|
|
|
phrases := " lacy timber \n"
|
|
phrases += "\t\thybrid gossiping\t\n"
|
|
phrases += " coy radioactivity\n"
|
|
phrases += "rocky arrow \n"
|
|
// Pass the string though the transformer.
|
|
out, err := ioutil.ReadAll(trimmer(bytes.NewBufferString(phrases)))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Printf("%s\n", out)
|
|
// Output:
|
|
// lacy timber
|
|
// hybrid gossiping
|
|
// coy radioactivity
|
|
// rocky arrow
|
|
}
|
|
|
|
func ExampleTransformer_pipeline() {
|
|
// Filter lines matching a pattern
|
|
matcher := func(r io.Reader, pattern string) *Transformer {
|
|
br := bufio.NewReader(r)
|
|
return NewTransformer(func() ([]byte, error) {
|
|
for {
|
|
line, err := br.ReadBytes('\n')
|
|
matched, _ := regexp.Match(pattern, line)
|
|
if matched {
|
|
return line, err
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// Trim space from all lines
|
|
trimmer := func(r io.Reader) *Transformer {
|
|
br := bufio.NewReader(r)
|
|
return NewTransformer(func() ([]byte, error) {
|
|
for {
|
|
line, err := br.ReadBytes('\n')
|
|
if len(line) > 0 {
|
|
line = append(bytes.TrimSpace(line), '\n')
|
|
}
|
|
return line, err
|
|
}
|
|
})
|
|
}
|
|
|
|
// Convert a string to uppper case. Unicode aware. In this example
|
|
// we only process one rune at a time. It works but it's not ideal
|
|
// for production.
|
|
toUpper := func(r io.Reader) *Transformer {
|
|
br := bufio.NewReader(r)
|
|
return NewTransformer(func() ([]byte, error) {
|
|
c, _, err := br.ReadRune()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return []byte(strings.ToUpper(string([]rune{c}))), nil
|
|
})
|
|
}
|
|
phrases := " lacy timber \n"
|
|
phrases += "\t\thybrid gossiping\t\n"
|
|
phrases += " coy radioactivity\n"
|
|
phrases += "rocky arrow \n"
|
|
|
|
// create a transformer that matches lines on the letter 'o', trims the
|
|
// space from the lines, and transforms to upper case.
|
|
r := toUpper(trimmer(matcher(bytes.NewBufferString(phrases), "o")))
|
|
|
|
// Pass the string though the transformer.
|
|
out, err := ioutil.ReadAll(r)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Printf("%s\n", out)
|
|
// Output:
|
|
// HYBRID GOSSIPING
|
|
// COY RADIOACTIVITY
|
|
// ROCKY ARROW
|
|
}
|