From d2f6fc8572192b2442e63fe15bf483b992d4a4c1 Mon Sep 17 00:00:00 2001 From: Michael Draper Date: Sun, 23 Aug 2020 21:05:11 -0700 Subject: [PATCH 1/5] added the ability to configure the list of considered words --- .idea/babble.iml | 9 +++ .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 ++ .idea/workspace.xml | 192 ++++++++++++++++++++++++++++++++++++++++++++ babble.go | 14 +++- dictionary.go | 74 +++++++++++++++++ dictionary_test.go | 29 +++++++ go.mod | 8 ++ go.sum | 55 +++++++++++++ words.go | 70 ++++++++++++++++ 10 files changed, 463 insertions(+), 2 deletions(-) create mode 100644 .idea/babble.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/workspace.xml create mode 100644 dictionary.go create mode 100644 dictionary_test.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 words.go diff --git a/.idea/babble.iml b/.idea/babble.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/babble.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..dea8e5c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..f831be9 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/babble.go b/babble.go index d65b4c4..b39c7f9 100644 --- a/babble.go +++ b/babble.go @@ -6,6 +6,8 @@ import ( "time" ) +var words []string + func init() { rand.Seed(time.Now().UnixNano()) } @@ -14,12 +16,21 @@ type Babbler struct { Count int Separator string Words []string + Dictionary Dictionary } func NewBabbler() (b Babbler) { + b.Dictionary = NewDictionaryWithConfig(DefaultDictionaryConfig) + b.Count = 2 + b.Separator = "-" + b.Words = words + return +} +func NewBabblerWithConfig(config DictionaryConfig) (b Babbler) { + b.Dictionary = NewDictionaryWithConfig(config) b.Count = 2 b.Separator = "-" - b.Words = readAvailableDictionary() + b.Words = words return } @@ -28,6 +39,5 @@ func (this Babbler) Babble() string { for i := 0; i < this.Count ; i++ { pieces = append(pieces, this.Words[rand.Int()%len(this.Words)]) } - return strings.Join(pieces, this.Separator) } diff --git a/dictionary.go b/dictionary.go new file mode 100644 index 0000000..2612eba --- /dev/null +++ b/dictionary.go @@ -0,0 +1,74 @@ +package babble + +type DictionaryConfig struct { + MinLength int + MaxLength int + CustomWordList *[]string +} +var DefaultDictionaryConfig = DictionaryConfig { + MinLength: 3, + MaxLength: 6, +} + +type Dictionary interface { + SetExcludeFunc(func(s string)bool) // Matches words in list, strings returning true are excluded + SetTransformFunc(func(s string)string) // Executes transformation function when building the list + GetRandomWord() string + GetListLength() int +} + +type babbleDictionary struct { + sourceList []string + excludeFunc func(s string)bool + transformFunc func(s string)string + config *DictionaryConfig +} + +func NewDictionaryWithConfig(c DictionaryConfig) Dictionary { + d := &babbleDictionary{ + config: &c, + sourceList: []string{}, + + } + if c.CustomWordList == nil { + d.sourceList = d.load() + }else{ + d.sourceList = *c.CustomWordList + } + return d +} +func (d *babbleDictionary) GetRandomWord() string { + return getRandomWordFromList(d.config.MinLength, d.config.MaxLength,d.sourceList) +} +func (d *babbleDictionary) GetListLength() int { + return len(d.sourceList) +} +func (d *babbleDictionary) load() []string { + list := readAvailableDictionary() + allEligible := GenerateEligibleWordList(list, d.config.MinLength, d.config.MaxLength) + f := []string{} + if d.excludeFunc != nil { + for _, w := range allEligible{ + if !d.excludeFunc(w) { + if d.transformFunc != nil { + w = d.transformFunc(w) + } + } + } + }else{ + for _, w := range allEligible { + if d.transformFunc != nil { + w = d.transformFunc(w) + } + f = append(f, w) + } + } + return f +} + +func (d *babbleDictionary) SetExcludeFunc(f func(s string)bool){ + d.excludeFunc = f +} +func (d *babbleDictionary) SetTransformFunc(f func(s string)string){ + d.transformFunc = f +} \ No newline at end of file diff --git a/dictionary_test.go b/dictionary_test.go new file mode 100644 index 0000000..7e157c4 --- /dev/null +++ b/dictionary_test.go @@ -0,0 +1,29 @@ +package babble_test + +import ( + "babble" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("dictionary", func() { + var d babble.Dictionary + BeforeEach(func() { + d = babble.NewDictionaryWithConfig(babble.DictionaryConfig{ 1, 5, nil}) + }) + + It("returns a random word", func() { + s := d.GetRandomWord() + ls := len(s) + Expect(ls >= 1).Should(BeTrue()) + Expect(ls <= 5).Should(BeTrue()) + + }) + + Describe("with multiple words", func() { + It("concatenates strings", func() { + + }) + }) +}) + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..54d00b7 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module babble + +go 1.14 + +require ( + github.com/onsi/ginkgo v1.14.0 + github.com/onsi/gomega v1.10.1 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..677be62 --- /dev/null +++ b/go.sum @@ -0,0 +1,55 @@ +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/words.go b/words.go new file mode 100644 index 0000000..bb191c5 --- /dev/null +++ b/words.go @@ -0,0 +1,70 @@ +package babble + +import ( + "fmt" + "math/rand" + "strconv" +) + +type wordIndexByLength map[string][]string + +func addByLength(s string, min int, max int, inMap wordIndexByLength ) { + slen := len(s) + if slen >= min && slen <= max { + l := fmt.Sprintf("%d", slen) + if _, ok := inMap[l]; ok { + inMap[l] = append(inMap[l],s ) + }else{ + inMap[l] = []string{ s } + addByLength(s, min, max, inMap) + } + } + +} + +func sliceWordList(words []string, min int, max int) wordIndexByLength { + if min < 1 || min > max { + min = 1 + } + if max > 36 || min > max { + max = 36 + } + d := map[string][]string {} + + for _, s := range words { + addByLength(s, min, max, d ) + } + return d +} + +func getRandomWordList(min int, max int, list wordIndexByLength) []string { + keys := []int{} + for l := range list { + i, _ := strconv.Atoi(l) + if i > max { + break + } + if i >= min { + keys = append(keys) + } + } + theLength := keys[rand.Int()%len(keys)] + i := string(theLength) + a := list[i] + // return a[rand.Int()%len(a)] + return a +} +func GenerateEligibleWordList(a []string, min int, max int) []string { + words := sliceWordList(a, min, max) + r := []string{} + for _, a := range words { + r = append(r, a...) + } + return r +} +func getRandomWordFromList(min int, max int, wordList []string) string { + if len(wordList) == 0{ + panic("word list is not available") + } + return wordList[rand.Int()%len(wordList)] +} \ No newline at end of file From c176e5045b873bf69ed1c072b259d38d01843669 Mon Sep 17 00:00:00 2001 From: Michael Draper Date: Mon, 24 Aug 2020 07:46:52 -0700 Subject: [PATCH 2/5] added test coverage --- .idea/workspace.xml | 95 ++++++++++++++++----------------- babble.go | 10 ++-- babble_test.go | 12 +++++ dictionary.go | 95 ++++++++++++++++++++++----------- dictionary_test.go | 125 ++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 248 insertions(+), 89 deletions(-) diff --git a/.idea/workspace.xml b/.idea/workspace.xml index f831be9..f53a9d3 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,10 +2,11 @@ - - - + + + + - - + + @@ -55,7 +56,7 @@ - + @@ -63,10 +64,10 @@ - + - + @@ -74,34 +75,23 @@ - + - + + - - + - - - - - - - - - - - + - - + @@ -109,19 +99,18 @@ - - - - - + + + + - - - - - + + + + + @@ -141,42 +130,46 @@ + + + + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + diff --git a/babble.go b/babble.go index b39c7f9..d8a0540 100644 --- a/babble.go +++ b/babble.go @@ -20,17 +20,19 @@ type Babbler struct { } func NewBabbler() (b Babbler) { - b.Dictionary = NewDictionaryWithConfig(DefaultDictionaryConfig) + d := NewDictionaryWithConfig(DefaultDictionaryConfig) + b.Dictionary = d b.Count = 2 b.Separator = "-" - b.Words = words + b.Words = d.GetWordList() return } func NewBabblerWithConfig(config DictionaryConfig) (b Babbler) { - b.Dictionary = NewDictionaryWithConfig(config) + d := NewDictionaryWithConfig(config) + b.Dictionary = d b.Count = 2 b.Separator = "-" - b.Words = words + b.Words = b.Dictionary.GetWordList() return } diff --git a/babble_test.go b/babble_test.go index 921dd18..65b853f 100644 --- a/babble_test.go +++ b/babble_test.go @@ -26,4 +26,16 @@ var _ = Describe("babble", func() { Expect(babbler.Babble()).To(Equal("hello☃hello")) }) }) + + Describe("new babble", func(){ + It("handles a basic configuration", func(){ + babbler = NewBabbler() + Expect( len(babbler.Words) ).Should(Equal(babbler.Dictionary.GetListLength())) + }) + It("accepts a custom dictionary config", func(){ + babbler = NewBabblerWithConfig(DictionaryConfig{ MinLength: 2, MaxLength: 4}) + Expect(len(babbler.Words)).Should(Equal(babbler.Dictionary.GetListLength())) + }) + + }) }) diff --git a/dictionary.go b/dictionary.go index 2612eba..a60e88f 100644 --- a/dictionary.go +++ b/dictionary.go @@ -1,9 +1,18 @@ package babble +import "strings" + +type ExcludeWord func(s string)bool +type TransformWord func(s string) string + type DictionaryConfig struct { MinLength int MaxLength int CustomWordList *[]string + Downcase bool + Upcase bool + ExcludeWord ExcludeWord + TransformWord TransformWord } var DefaultDictionaryConfig = DictionaryConfig { MinLength: 3, @@ -11,64 +20,88 @@ var DefaultDictionaryConfig = DictionaryConfig { } type Dictionary interface { - SetExcludeFunc(func(s string)bool) // Matches words in list, strings returning true are excluded - SetTransformFunc(func(s string)string) // Executes transformation function when building the list GetRandomWord() string GetListLength() int + GetWordList() []string } type babbleDictionary struct { sourceList []string - excludeFunc func(s string)bool - transformFunc func(s string)string config *DictionaryConfig } func NewDictionaryWithConfig(c DictionaryConfig) Dictionary { + if c.Upcase && c.Downcase { + panic("cannot upcase and downcase the dictionary at the same time, invalid dictionary config") + } d := &babbleDictionary{ config: &c, sourceList: []string{}, - } if c.CustomWordList == nil { - d.sourceList = d.load() + d.load() }else{ d.sourceList = *c.CustomWordList + if d.config.ExcludeWord != nil { + d.loadWithExclude() + } else { + newSource := []string{} + for _, s := range d.sourceList { + newSource = append(newSource, d.applyTransform(s)) + } + d.sourceList = newSource + } } return d } func (d *babbleDictionary) GetRandomWord() string { + if d.config.MinLength > d.config.MaxLength { + panic("minimum length cannot exceed maximum length") + } return getRandomWordFromList(d.config.MinLength, d.config.MaxLength,d.sourceList) } func (d *babbleDictionary) GetListLength() int { return len(d.sourceList) } -func (d *babbleDictionary) load() []string { +func (d *babbleDictionary) applyTransform(s string) (ts string) { + txf := d.config.TransformWord + if txf != nil { + ts = txf(s) + }else{ + ts = s + } + if d.config.Downcase { + return strings.ToLower(ts) + } + if d.config.Upcase { + return strings.ToUpper(ts) + } + return ts +} +func (d *babbleDictionary) GetWordList() []string { + return d.sourceList +} +func (d *babbleDictionary) loadWithExclude() { + exc := d.config.ExcludeWord + newSource := []string{} + for _, s := range d.sourceList{ + if(!exc(s)){ + newSource = append(newSource, d.applyTransform(s)) + } + } + d.sourceList = newSource +} +func (d *babbleDictionary) load() { list := readAvailableDictionary() - allEligible := GenerateEligibleWordList(list, d.config.MinLength, d.config.MaxLength) - f := []string{} - if d.excludeFunc != nil { - for _, w := range allEligible{ - if !d.excludeFunc(w) { - if d.transformFunc != nil { - w = d.transformFunc(w) - } - } - } - }else{ - for _, w := range allEligible { - if d.transformFunc != nil { - w = d.transformFunc(w) - } - f = append(f, w) - } + d.sourceList = GenerateEligibleWordList(list, d.config.MinLength, d.config.MaxLength) + if d.config.ExcludeWord != nil { + d.loadWithExclude() + } else { + newSource := []string{} + for _, s := range d.sourceList { + newSource = append(newSource, d.applyTransform(s)) + } + d.sourceList = newSource } - return f } -func (d *babbleDictionary) SetExcludeFunc(f func(s string)bool){ - d.excludeFunc = f -} -func (d *babbleDictionary) SetTransformFunc(f func(s string)string){ - d.transformFunc = f -} \ No newline at end of file diff --git a/dictionary_test.go b/dictionary_test.go index 7e157c4..ec06e9a 100644 --- a/dictionary_test.go +++ b/dictionary_test.go @@ -4,12 +4,15 @@ import ( "babble" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "strings" ) var _ = Describe("dictionary", func() { var d babble.Dictionary + var w string BeforeEach(func() { - d = babble.NewDictionaryWithConfig(babble.DictionaryConfig{ 1, 5, nil}) + d = babble.NewDictionaryWithConfig(babble.DictionaryConfig{ MinLength: 3, MaxLength: 5 }) + w = d.GetRandomWord() }) It("returns a random word", func() { @@ -20,8 +23,124 @@ var _ = Describe("dictionary", func() { }) - Describe("with multiple words", func() { - It("concatenates strings", func() { + Describe("with custom configuration", func() { + It("handles min 0 max 30", func() { + d = babble.NewDictionaryWithConfig(babble.DictionaryConfig{MinLength: 0, MaxLength: 30}) + s := d.GetRandomWord() + ls := len(s) + Expect(ls >= 0).Should(BeTrue()) + Expect(ls <= 30).Should(BeTrue()) + }) + + It("handles min 3 max 3", func() { + d = babble.NewDictionaryWithConfig(babble.DictionaryConfig{ MinLength: 3, MaxLength: 3}) + s := d.GetRandomWord() + ls := len(s) + Expect(ls >= 3).Should(BeTrue()) + Expect(ls <= 3).Should(BeTrue()) + }) + + It("handles when min length is larger than max, should use panic", func() { + d = babble.NewDictionaryWithConfig(babble.DictionaryConfig{ MinLength: 30, MaxLength: 3}) + defer func(){ + r := recover(); + Expect(r).ShouldNot(BeNil()) + }() + d.GetRandomWord() + + }) + It("ExcludeWord", func() { + Expect(w).ShouldNot(BeEmpty()) + a := d.GetListLength() + exc := func(s string)bool { + return s == w + } + c := babble.DictionaryConfig{ + MinLength: 3, + MaxLength: 5, + ExcludeWord: exc, + } + d = babble.NewDictionaryWithConfig(c) + b := d.GetListLength() + Expect(b == a - 1).Should(BeTrue()) + }) + It("TransformWord", func() { + Expect(w).ShouldNot(BeEmpty()) + tw := func(s string)string { + r := []rune(s) + for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { + r[i], r[j] = r[j], r[i] + } + return string(r) + } + c := babble.DictionaryConfig{ + MinLength: 3, + MaxLength: 5, + TransformWord: tw, + } + d = babble.NewDictionaryWithConfig(c) + aw := tw(w) // transform the test word + Expect(aw).ShouldNot(Equal(w)) + words := d.GetWordList() + found := false + for _, txwd := range words { + if txwd == aw { + found = true + } + } + Expect(found).Should(BeTrue()) + + }) + It("uses a custom word list", func(){ + Expect(w).ShouldNot(BeEmpty()) + c := babble.DictionaryConfig{ + MinLength: 3, + MaxLength: 5, + CustomWordList: &[]string{ w }, + } + d = babble.NewDictionaryWithConfig(c) + actual := d.GetRandomWord() + Expect(actual).Should(Equal(w)) + }) + It("upcases", func() { + Expect(w).ShouldNot(BeEmpty()) + c := babble.DictionaryConfig{ + MinLength: 3, + MaxLength: 5, + Upcase: true, + CustomWordList: &[]string{ w }, + } + d = babble.NewDictionaryWithConfig(c) + actual := d.GetRandomWord() + Expect(actual).Should(Equal(strings.ToUpper(w))) + + + }) + It("downcases", func() { + Expect(w).ShouldNot(BeEmpty()) + c := babble.DictionaryConfig{ + MinLength: 3, + MaxLength: 5, + Downcase: true, + CustomWordList: &[]string{ w }, + } + d = babble.NewDictionaryWithConfig(c) + actual := d.GetRandomWord() + Expect(actual).Should(Equal(strings.ToLower(w))) + }) + It("cannot upcase and downcase", func() { + defer func(){ + r := recover(); + Expect(r).ShouldNot(BeNil()) + }() + c := babble.DictionaryConfig{ + MinLength: 3, + MaxLength: 5, + Downcase: true, + Upcase: true, + CustomWordList: &[]string{ w }, + } + d = babble.NewDictionaryWithConfig(c) }) }) From 400e82b61bb458c617f8136f705ad54767be8a84 Mon Sep 17 00:00:00 2001 From: Michael Draper Date: Mon, 24 Aug 2020 07:51:05 -0700 Subject: [PATCH 3/5] cleanup --- .gitignore | 1 + .idea/babble.iml | 9 --- .idea/modules.xml | 8 -- .idea/vcs.xml | 6 -- .idea/workspace.xml | 185 -------------------------------------------- 5 files changed, 1 insertion(+), 208 deletions(-) create mode 100644 .gitignore delete mode 100644 .idea/babble.iml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 .idea/workspace.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/.idea/babble.iml b/.idea/babble.iml deleted file mode 100644 index 5e764c4..0000000 --- a/.idea/babble.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index dea8e5c..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index f53a9d3..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 6a4e21c58148c7c3c3f635cce8d4fe7b9ff425d6 Mon Sep 17 00:00:00 2001 From: Michael Draper Date: Mon, 24 Aug 2020 08:45:39 -0700 Subject: [PATCH 4/5] added documentation and comments --- README.md | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ dictionary.go | 36 +++++++++++++++++- 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4dc2da7..5d8d310 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,104 @@ func main() { return }) ``` +Custom Usage +---- +```go +package your_app + +import ( + "github.com/tjarratt/babble" +) + +func main() { + c := babble.DictionaryConfig { + MinLength: 3, + MaxLength: 5, + } + + babbler := babble.NewBabblerWithConfig(c) + babbler.Separator = "-" + println(babbler.Babble()) // excessive-yak-shaving (or some other phrase) + + // optionally set your own separator + babbler.Separator = " " + println(babbler.Babble()) // "hello from nowhere" (or some other phrase) + + // optionally set the number of words you want + babbler.Count = 1 + println(babbler.Babble()) // antibiomicrobrial (or some other word) + +``` +Upcase +---- +```go +package your_app + +import ( + babble2 "babble" +"github.com/tjarratt/babble" +) + +func main() { + c := babble.DictionaryConfig { + MinLength: 3, + MaxLength: 5, + Upcase: true, + } + + babbler := babble.NewBabblerWithConfig(c) + babbler.Separator = "-" + println(babbler.Babble()) // EXCESSIVE-YAK-SHAVING (or some other phrase) +``` +Downcase +---- +```go + c = babble.DictionaryConfig { + MinLength: 3, + MaxLength: 5, + Downcase: true, + } + + babbler = babble.NewBabblerWithConfig(c) + babbler.Separator = "-" + println(babbler.Babble()) // excessive-yak-shaving (or some other phrase) +``` +Transform +---- +```go + var alternateCase = func (s string)string { + rs, upper := []rune(s), false + for i, r := range rs { + if unicode.IsLetter(r) { + if upper = !upper; upper { + rs[i] = unicode.ToUpper(r) + } + } + } + return string(rs) + } + c = babble.DictionaryConfig { + MinLength: 3, + MaxLength: 5, + TransformWord: alternateCase, + } + + babbler = babble.NewBabblerWithConfig(c) + babbler.Separator = "-" + println(babbler.Babble()) // ExCeSsIvE-YaK-SlUrPiNg the transform is applied to each word individually during load +``` +Custom Word List +---- +```go +customList = []string{ "luke", "leia", "han", "darth", "r2d2" } // C-3PO has been expressly excluded + c = babble.DictionaryConfig { + MinLength: 3, + MaxLength: 5, + CustomWordList: customList, + } + + babbler = babble.NewBabblerWithConfig(c) + babbler.Separator = "-" + println(babbler.Babble()) // luke-darth +``` + diff --git a/dictionary.go b/dictionary.go index a60e88f..d2e6ab2 100644 --- a/dictionary.go +++ b/dictionary.go @@ -6,12 +6,22 @@ type ExcludeWord func(s string)bool type TransformWord func(s string) string type DictionaryConfig struct { + // Limits the lower bound to the length of words in the list MinLength int + // Limits the upper bound to the length of words in the list MaxLength int + // If this pointer is non-nil, this list is used instead of + // the default OS dictionary. CustomWordList *[]string + // Changes all letters in each word to lower case Downcase bool + // Changes all letters in each word to upper case Upcase bool + // If present, this function is emitted on all words in the dictionary, + // if the provided function returns true, the word is not included in the + // word list. ExcludeWord ExcludeWord + // Emittted on all words in the dictionary TransformWord TransformWord } var DefaultDictionaryConfig = DictionaryConfig { @@ -29,7 +39,15 @@ type babbleDictionary struct { sourceList []string config *DictionaryConfig } - +// NewDictionaryWithConfig creates a new dictionary with the supplied +// configuration struct. +// c = babble.DictionaryConfig { +// MinLength: 3, +// MaxLength: 5, +// Downcase: true, +// +// } +// d = NewDictionaryWithConfig(c) func NewDictionaryWithConfig(c DictionaryConfig) Dictionary { if c.Upcase && c.Downcase { panic("cannot upcase and downcase the dictionary at the same time, invalid dictionary config") @@ -54,15 +72,23 @@ func NewDictionaryWithConfig(c DictionaryConfig) Dictionary { } return d } + +// GetRandomWord returns a random word from the dictionary func (d *babbleDictionary) GetRandomWord() string { if d.config.MinLength > d.config.MaxLength { panic("minimum length cannot exceed maximum length") } return getRandomWordFromList(d.config.MinLength, d.config.MaxLength,d.sourceList) } + +// GetListLength returns the length of the currently loaded word list. func (d *babbleDictionary) GetListLength() int { return len(d.sourceList) } + +// applyTransform applies the configured transformation function +// on each string, and if Upcase or Downcase is true, that +// transformation is applied func (d *babbleDictionary) applyTransform(s string) (ts string) { txf := d.config.TransformWord if txf != nil { @@ -78,9 +104,15 @@ func (d *babbleDictionary) applyTransform(s string) (ts string) { } return ts } + +// GetWordList returns the entire list of possible words func (d *babbleDictionary) GetWordList() []string { return d.sourceList } + +// loadWithExclude loads the list of possible words, emitting +// the ExcludeWord function if present to filter candidate +// words. func (d *babbleDictionary) loadWithExclude() { exc := d.config.ExcludeWord newSource := []string{} @@ -91,6 +123,8 @@ func (d *babbleDictionary) loadWithExclude() { } d.sourceList = newSource } + +// load loads the list of possible words func (d *babbleDictionary) load() { list := readAvailableDictionary() d.sourceList = GenerateEligibleWordList(list, d.config.MinLength, d.config.MaxLength) From 1ccae31ae82bfcc4f6e5f63ac4802f7c553cb4a3 Mon Sep 17 00:00:00 2001 From: Michael Draper Date: Mon, 24 Aug 2020 08:48:23 -0700 Subject: [PATCH 5/5] aligned markdown in readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5d8d310..5b15938 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ func main() { c := babble.DictionaryConfig { MinLength: 3, MaxLength: 5, - Upcase: true, + Upcase: true, } babbler := babble.NewBabblerWithConfig(c) @@ -85,7 +85,7 @@ Downcase c = babble.DictionaryConfig { MinLength: 3, MaxLength: 5, - Downcase: true, + Downcase: true, } babbler = babble.NewBabblerWithConfig(c) @@ -109,7 +109,7 @@ Transform c = babble.DictionaryConfig { MinLength: 3, MaxLength: 5, - TransformWord: alternateCase, + TransformWord: alternateCase, } babbler = babble.NewBabblerWithConfig(c)