package main import ( "bufio" "bytes" "encoding/json" "fmt" "io" "os" "strings" ) type Manager struct { Input Input Filter Filter Output Output } type Input interface { Start() chan *Work } type StdinInput struct { retchan chan *Work } type Filter interface { Filter(chan *Work) chan *Work } type StringFilter struct { retchan chan *Work FilterFuncMap map[string]func(string) string } type Output interface { Output(chan *Work) } type StdoutOutput struct { } type Work struct { data []byte err error } func (i *StdinInput) Start() chan *Work { i.retchan = make(chan *Work, 100) r := bufio.NewReader(os.Stdin) go func() { for { bs, err := r.ReadBytes(byte('\n')) if err == io.EOF { break } if err != nil { fmt.Printf("Error when reading input from Stdin: %q", err) os.Exit(1) } i.retchan <- &Work{data: bs} } close(i.retchan) }() return i.retchan } func (f *StringFilter) Filter(ic chan *Work) chan *Work { f.retchan = make(chan *Work, 100) if f.FilterFuncMap == nil { f.FilterFuncMap = make(map[string]func(string) string, 10) f.FilterFuncMap["F"] = func(s string) string { return strings.ToUpper(s) } } go func() { for w := range ic { dec := json.NewDecoder(bytes.NewReader(w.data)) jm := make(map[string]string, 10) err := dec.Decode(&jm) if err == io.EOF { fmt.Printf("EOF jm: %v\n", jm) f.retchan <- w continue } if err != nil { fmt.Printf("Error when decoding JSON: %q\n", err) w.err = err } changed := false for k, v := range jm { ff, ok := f.FilterFuncMap[k] if !ok { continue } jm[k] = ff(v) changed = true } if changed { bs, err := json.Marshal(jm) if err != nil { fmt.Printf("Error when marshalling JSON: %q\n", err) w.err = err } else { w.data = bs } } f.retchan <- w } close(f.retchan) }() return f.retchan } func (o *StdoutOutput) Output(wc chan *Work) { for w := range wc { fmt.Printf("%s\n", w.data) } } func (m *Manager) Go() { ic := m.Input.Start() fc := m.Filter.Filter(ic) m.Output.Output(fc) } func main() { m := Manager{ Input: &StdinInput{}, Filter: &StringFilter{}, Output: &StdoutOutput{}, } m.Go() }