From 8027144b27a787f9f5e28362de84c0fbdceb76ca Mon Sep 17 00:00:00 2001 From: Dean Jackson Date: Sat, 27 Jan 2018 17:52:43 +0100 Subject: [PATCH] Add filter middleware for simpler logic --- filter.go | 36 +++++++++++++++++++++ filter_test.go | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++ scan.go | 24 +++++++------- 3 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 filter.go create mode 100644 filter_test.go diff --git a/filter.go b/filter.go new file mode 100644 index 0000000..d8b917f --- /dev/null +++ b/filter.go @@ -0,0 +1,36 @@ +// +// Copyright (c) 2018 Dean Jackson +// +// MIT Licence. See http://opensource.org/licenses/MIT +// +// Created on 2018-01-27 +// + +package main + +// Filterer passes selectively passes through strings +type Filterer func(in <-chan string) <-chan string + +// Filter is a chain of Filterers +type Filter struct { + Funcs []Filterer +} + +// Use adds a Filterer to the stack +func (f *Filter) Use(fn Filterer) { + f.Funcs = append(f.Funcs, fn) +} + +// Apply runs the filter on a channel. +func (f *Filter) Apply(in <-chan string) <-chan string { + + var out = make(<-chan string) + + // Make stack of handlers + out = f.Funcs[len(f.Funcs)-1](in) + for i := len(f.Funcs) - 2; i >= 0; i-- { + out = f.Funcs[i](out) + } + + return out +} diff --git a/filter_test.go b/filter_test.go new file mode 100644 index 0000000..5a64898 --- /dev/null +++ b/filter_test.go @@ -0,0 +1,87 @@ +// +// Copyright (c) 2018 Dean Jackson +// +// MIT Licence. See http://opensource.org/licenses/MIT +// +// Created on 2018-01-27 +// + +package main + +import ( + "path/filepath" + "testing" +) + +func TestFilter(t *testing.T) { + data := []struct { + in, out []string + }{ + {[]string{""}, []string{}}, + {[]string{"file", "file.txt"}, []string{"file.txt"}}, + {[]string{"file.txt", "file.pdf"}, []string{"file.txt", "file.pdf"}}, + {[]string{"file.mp4", "file.pdf"}, []string{"file.pdf"}}, + } + + for _, td := range data { + + var in = make(chan string) + + // Generate input + go func(c chan string, data []string) { + + for _, s := range data { + if s == "" { + continue + } + x := filepath.Ext(s) + if x == ".mp4" || x == "" { + continue + } + c <- s + } + close(in) + }(in, td.in) + + f := Filter{} + f.Use(func(in <-chan string) <-chan string { + var out = make(chan string) + + go func() { + defer close(out) + + for s := range in { + out <- s + } + + }() + + return out + }) + + out := f.Apply(in) + res := []string{} + for s := range out { + res = append(res, s) + } + + if !strSlicesEqual(res, td.out) { + t.Errorf("Bad Filter. Expected=%#v, Got=%#v", td.out, res) + } + } + +} + +func strSlicesEqual(s1, s2 []string) bool { + if len(s1) != len(s2) { + return false + } + + for i, s := range s1 { + if s != s2[i] { + return false + } + } + + return true +} diff --git a/scan.go b/scan.go index 2609825..0ab92db 100644 --- a/scan.go +++ b/scan.go @@ -53,6 +53,7 @@ func scan() <-chan Project { var ( ins []<-chan string out = make(<-chan Project) + f = &Filter{} ) for name, scanner := range scanners { @@ -71,17 +72,12 @@ func scan() <-chan Project { } // real programs have middleware - out = resultToProject( - filterExcludes( - filterNotExist( - filterDupes( - filterNotProject( - merge(ins...), - ), - ), - ), - conf.Excludes), - ) + f.Use(makeFilterExcludes(conf.Excludes)) + f.Use(filterNotExist) + f.Use(filterDupes) + f.Use(filterNotProject) + + out = resultToProject(f.Apply(merge(ins...))) return out } @@ -271,6 +267,12 @@ func lineCommand(cmd *exec.Cmd, name string) (chan string, error) { return out, err } +func makeFilterExcludes(patterns []string) Filterer { + return func(in <-chan string) <-chan string { + return filterExcludes(in, patterns) + } +} + // Filter files that match any of the glob patterns. func filterExcludes(in <-chan string, patterns []string) <-chan string { var globs []glob.Glob