mirror of
				https://github.com/therootcompany/golib.git
				synced 2025-10-30 20:52:53 +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
 | |
| }
 |