diff --git a/interfaces/log-parser/oop/analysis.go b/interfaces/log-parser/oop/analysis.go index 84cc24b..ac0ba1d 100644 --- a/interfaces/log-parser/oop/analysis.go +++ b/interfaces/log-parser/oop/analysis.go @@ -10,8 +10,8 @@ package main import "sort" type analysis struct { - sum map[string]result // metrics per domain - keys []string // unique keys + sum map[string]result // metrics per group key + keys []string // unique group keys groupKey groupFunc filter filterFunc } @@ -24,6 +24,31 @@ func newAnalysis() *analysis { } } +// transform the result +func (a *analysis) transform(r result) { + if !a.filter(r) { + return + } + + key := a.groupKey(r) + if _, ok := a.sum[key]; !ok { + a.keys = append(a.keys, key) + } + + a.sum[key] = r.add(a.sum[key]) +} + +// each yields an analysis result +func (a *analysis) each(yield resultFn) error { + sort.Strings(a.keys) + + for _, key := range a.keys { + yield(a.sum[key]) + } + + return nil +} + func (a *analysis) groupBy(g groupFunc) { if g != nil { a.groupKey = g @@ -35,26 +60,3 @@ func (a *analysis) filterBy(f filterFunc) { a.filter = f } } - -// analyse the given result -func (a *analysis) analyse(r result) { - if !a.filter(r) { - return - } - - key := a.groupKey(r) - if _, ok := a.sum[key]; !ok { - a.keys = append(a.keys, key) - } - - a.sum[key] = r.add(a.sum[key]) -} - -// each sends an analysis result to `handle` -func (a *analysis) each(handle resultFn) { - sort.Strings(a.keys) - - for _, domain := range a.keys { - handle(a.sum[domain]) - } -} diff --git a/interfaces/log-parser/oop/chartsummary.go b/interfaces/log-parser/oop/chartreport.go similarity index 88% rename from interfaces/log-parser/oop/chartsummary.go rename to interfaces/log-parser/oop/chartreport.go index 2e6a6de..a878215 100644 --- a/interfaces/log-parser/oop/chartsummary.go +++ b/interfaces/log-parser/oop/chartreport.go @@ -10,12 +10,12 @@ import ( // You need to run: // go get -u github.com/wcharczuk/go-chart -type chartSummary struct { +type chartReport struct { title string width, height int } -func (s *chartSummary) summarize(results iterator) error { +func (s *chartReport) report(results iterator) error { w := os.Stdout donut := c.DonutChart{ diff --git a/interfaces/log-parser/oop/jsonparser.go b/interfaces/log-parser/oop/jsonlog.go similarity index 62% rename from interfaces/log-parser/oop/jsonparser.go rename to interfaces/log-parser/oop/jsonlog.go index 97dc04f..1789e44 100644 --- a/interfaces/log-parser/oop/jsonparser.go +++ b/interfaces/log-parser/oop/jsonlog.go @@ -1,4 +1,4 @@ -// For more tutorials: https://bp.learngoprogramming.com +// For more tutorials: https://bj.learngoprogramming.com // // Copyright © 2018 Inanc Gumus // Learn Go Programming Course @@ -14,26 +14,26 @@ import ( "io/ioutil" ) -type jsonParser struct { - r io.Reader +type jsonLog struct { + reader io.Reader } -func newJSONParser(r io.Reader) *jsonParser { - return &jsonParser{r: r} +func newJSONLog(r io.Reader) *jsonLog { + return &jsonLog{reader: r} } -func (p *jsonParser) parse(handle resultFn) error { - defer readClose(p.r) +func (j *jsonLog) each(yield resultFn) error { + defer readClose(j.reader) - bytes, err := ioutil.ReadAll(p.r) + bytes, err := ioutil.ReadAll(j.reader) if err != nil { return err } - return parseJSON(bytes, handle) + return extractJSON(bytes, yield) } -func parseJSON(bytes []byte, handle resultFn) error { +func extractJSON(bytes []byte, yield resultFn) error { var rs []struct { Domain string Page string @@ -49,7 +49,7 @@ func parseJSON(bytes []byte, handle resultFn) error { } for _, r := range rs { - handle(result{ + yield(result{ domain: r.Domain, page: r.Page, visits: r.Visits, diff --git a/interfaces/log-parser/oop/main.go b/interfaces/log-parser/oop/main.go index c8a9b16..ffe93fc 100644 --- a/interfaces/log-parser/oop/main.go +++ b/interfaces/log-parser/oop/main.go @@ -14,20 +14,23 @@ import ( ) func main() { - a := newAnalysis() - // a.filterBy(notUsing(domainExtFilter("io", "com"))) - // a.groupBy(domainGrouper) + an := newAnalysis() + // an.filterBy(notUsing(domainExtFilter("io", "com"))) + // an.filterBy(domainFilter("org")) + // an.groupBy(domainGrouper) - p := newTextParser(os.Stdin) - s := newTextSummary() + src := newTextLog(os.Stdin) + dst := newTextReport() - // s := &chartSummary{ - // title: "visits per domain", - // width: 1920, - // height: 800, - // } + // s := &chartReport{ + // title: "visits per domain", + // width: 1920, + // height: 800, + // } - if err := report(p, a, s); err != nil { + pipe := newPipeline(src, dst, an) + + if err := pipe.run(); err != nil { log.Fatalln(err) } diff --git a/interfaces/log-parser/oop/pipeline.go b/interfaces/log-parser/oop/pipeline.go new file mode 100644 index 0000000..481df94 --- /dev/null +++ b/interfaces/log-parser/oop/pipeline.go @@ -0,0 +1,68 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "os" + "strings" +) + +type resultFn func(result) + +type iterator interface { + each(resultFn) error +} + +type transformer interface { + transform(result) + iterator +} + +type reporter interface { + report(iterator) error +} + +type pipeline struct { + src iterator + dst reporter + tran transformer +} + +func newPipeline(source iterator, r reporter, t transformer) *pipeline { + return &pipeline{ + src: source, + dst: r, + tran: t, + } +} + +// fromFile generates a default report +func fromFile(path string) (err error) { + f, err := os.Open(path) + if err != nil { + return err + } + + var src iterator + switch { + case strings.HasSuffix(path, ".txt"): + src = newTextLog(f) + case strings.HasSuffix(path, ".json"): + src = newJSONLog(f) + } + + p := newPipeline(src, newTextReport(), newAnalysis()) + return p.run() +} + +func (p *pipeline) run() error { + if err := p.src.each(p.tran.transform); err != nil { + return err + } + return p.dst.report(p.tran) +} diff --git a/interfaces/log-parser/oop/report.go b/interfaces/log-parser/oop/report.go deleted file mode 100644 index 4375b3b..0000000 --- a/interfaces/log-parser/oop/report.go +++ /dev/null @@ -1,63 +0,0 @@ -// For more tutorials: https://blog.learngoprogramming.com -// -// Copyright © 2018 Inanc Gumus -// Learn Go Programming Course -// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ -// - -package main - -import ( - "errors" - "os" - "strings" -) - -type resultFn func(result) - -type parser interface { - parse(resultFn) error -} - -type analyser interface { - analyse(result) -} - -type iterator interface { - each(resultFn) -} - -type summarizer interface { - summarize(iterator) error -} - -func report(p parser, a analyser, s summarizer) error { - if err := p.parse(a.analyse); err != nil { - return err - } - - it, ok := a.(iterator) - if !ok { - return errors.New("cannot iterate on analyser") - } - - return s.summarize(it) -} - -// reportFromFile generates a default report -func reportFromFile(path string) (err error) { - f, err := os.Open(path) - if err != nil { - return err - } - - var p parser - switch { - case strings.HasSuffix(path, ".txt"): - p = newTextParser(f) - case strings.HasSuffix(path, ".json"): - p = newJSONParser(f) - } - - return report(p, newAnalysis(), newTextSummary()) -} diff --git a/interfaces/log-parser/oop/textparser.go b/interfaces/log-parser/oop/textlog.go similarity index 72% rename from interfaces/log-parser/oop/textparser.go rename to interfaces/log-parser/oop/textlog.go index 9894494..7137194 100644 --- a/interfaces/log-parser/oop/textparser.go +++ b/interfaces/log-parser/oop/textlog.go @@ -15,36 +15,36 @@ import ( "strings" ) -type textParser struct { - r io.Reader +type textLog struct { + reader io.Reader } -func newTextParser(r io.Reader) *textParser { - return &textParser{r: r} +func newTextLog(r io.Reader) *textLog { + return &textLog{reader: r} } -func (p *textParser) parse(handle resultFn) error { - defer readClose(p.r) +func (p *textLog) each(yield resultFn) error { + defer readClose(p.reader) var ( l = 1 - in = bufio.NewScanner(p.r) + in = bufio.NewScanner(p.reader) ) for in.Scan() { - r, err := parseFields(in.Text()) + r, err := extractFields(in.Text()) if err != nil { return fmt.Errorf("line %d: %v", l, err) } - handle(r) + yield(r) l++ } return in.Err() } -func parseFields(s string) (r result, err error) { +func extractFields(s string) (r result, err error) { fields := strings.Fields(s) if len(fields) != fieldsLength { return r, fmt.Errorf("wrong number of fields %q", fields) diff --git a/interfaces/log-parser/oop/textsummary.go b/interfaces/log-parser/oop/textreport.go similarity index 84% rename from interfaces/log-parser/oop/textsummary.go rename to interfaces/log-parser/oop/textreport.go index e20376e..9cc98b9 100644 --- a/interfaces/log-parser/oop/textsummary.go +++ b/interfaces/log-parser/oop/textreport.go @@ -21,13 +21,13 @@ const ( flags = 0 ) -type textSummary struct{} +type textReport struct{} -func newTextSummary() *textSummary { - return new(textSummary) +func newTextReport() *textReport { + return new(textReport) } -func (s *textSummary) summarize(results iterator) error { +func (s *textReport) report(results iterator) error { w := tabwriter.NewWriter(os.Stdout, minWidth, tabWidth, padding, ' ', flags) write := fmt.Fprintf