diff --git a/README.md b/README.md index 6559676..f8cd730 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ chain := rangechain.FromSlice(container) | `FromSlice` | • `slice` - A slice to be used to start the chain. | Starts the chain with the supplied slice. Chaining and terminating methods can now be called on the result. | | `FromArray` | • `array` - An array to be used to start the chain. | Starts the chain with the supplied array. Chaining and terminating methods can now be called on the result. | | `FromChannel` | • `channel` - A channel to be used to start the chain. | Starts the chain with the supplied channel. Chaining and terminating methods can now be called on the result. | -| `FromMap` | • `aMap` - A map to be used to start the chain. | Starts the chain with the supplied map. Chaining and terminating methods can now be called on the result. The singular value used to represent the key and value pairs is `generator.MapTuple` of `github.com/halprin/rangechain/generator`. | +| `FromMap` | • `aMap` - A map to be used to start the chain. | Starts the chain with the supplied map. Chaining and terminating methods can now be called on the result. The singular value used to represent the key and value pairs is `keyvalue.KeyValuer` of `github.com/halprin/rangechain/keyvalue`. | From there, one can call a plethora of additional methods to modify the container passed in originally. The methods are outlined below. The methods fall into one of two categories: chaining or terminating. @@ -76,7 +76,7 @@ terminating method is called. | `Skip` | Skips over the parameter `skipNumber` number of values and effectively removes them from the chain. Also skips over any errors previously generated. | | `Limit` | Stops the chain after the parameter `keepSize` number of values. Any elements afterward are effectively removed. | | `Distinct` | Removes any duplicates. | -| `Flatten` | Will iterate over all the values in the chain, but any value encountered that is a range-able container itself will also have its values iterated over first before continuing with the remaining values in the chain. Maps flatten to its `generator.MapTuple` key and value pairs. | +| `Flatten` | Will iterate over all the values in the chain, but any value encountered that is a range-able container itself will also have its values iterated over first before continuing with the remaining values in the chain. Maps flatten to its `keyvalue.KeyValuer` key and value pairs. | | `Sort` | Sorts the chain given the `Less` function returned from the `returnLessFunction` function parameter. The `returnLessFunction` function is called with the entire serialized chain as a slice and _returns_ a function that satisfies the same requirements as the [Interface type's](https://pkg.go.dev/sort#Interface) `Less` function. See the [`TestSortingMaps` example](./example_test.go). This method is expensive because it must serialize all the values into a slice first. | | `Reverse` | Reverses the order of the chain. The last item will be first, and the first item will be last. This method is expensive because it must serialize all the values into a slice first. | diff --git a/begin.go b/begin.go index 01514f8..a6750d7 100644 --- a/begin.go +++ b/begin.go @@ -1,42 +1,41 @@ package rangechain import ( - "github.com/halprin/rangechain/generator" - "github.com/halprin/rangechain/intermediate" + "github.com/halprin/rangechain/internal/generator" ) // FromSlice starts the chain with the supplied slice. // Chaining and terminating methods can now be called on the result. -func FromSlice(slice interface{}) *intermediate.Link { +func FromSlice(slice interface{}) *Link { sliceGenerator := generator.FromSlice(slice) - link := intermediate.NewLink(sliceGenerator) + link := newLink(sliceGenerator) return link } // FromArray starts the chain with the supplied array. // Chaining and terminating methods can now be called on the result. -func FromArray(array interface{}) *intermediate.Link { +func FromArray(array interface{}) *Link { arrayGenerator := generator.FromArray(array) - link := intermediate.NewLink(arrayGenerator) + link := newLink(arrayGenerator) return link } // FromChannel starts the chain with the supplied channel. // Chaining and terminating methods can now be called on the result. -func FromChannel(channel interface{}) *intermediate.Link { +func FromChannel(channel interface{}) *Link { channelGenerator := generator.FromChannel(channel) - link := intermediate.NewLink(channelGenerator) + link := newLink(channelGenerator) return link } // FromMap starts the chain with the supplied map. -// Chaining and terminating methods can now be called on the result. The singular value used to represent the key and value pairs is `generator.MapTuple` of `github.com/halprin/rangechain/generator`. -func FromMap(aMap interface{}) *intermediate.Link { +// Chaining and terminating methods can now be called on the result. The singular value used to represent the key and value pairs is `keyvalue.KeyValuer` of `github.com/halprin/rangechain/keyvalue`. +func FromMap(aMap interface{}) *Link { mapGenerator := generator.FromMap(aMap) - link := intermediate.NewLink(mapGenerator) + link := newLink(mapGenerator) return link } diff --git a/begin_test.go b/begin_test.go index deb0308..ddec700 100644 --- a/begin_test.go +++ b/begin_test.go @@ -1,7 +1,7 @@ package rangechain import ( - "github.com/halprin/rangechain/generator" + "github.com/halprin/rangechain/keyvalue" "github.com/stretchr/testify/assert" "testing" ) @@ -35,7 +35,7 @@ func TestFromChannel(t *testing.T) { innerInput := []string{"DogCows", "goes", "Moof!", "Do", "you", "like", "Clarus", "the", "DogCow?"} expectedOutput := []interface{}{"DogCows", "goes", "Moof!", "Do", "you", "like", "Clarus", "the", "DogCow?"} - input := createTestChannel(innerInput) + input := createTestStringChannel(innerInput) chain := FromChannel(input) slice, err := chain.Slice() @@ -61,27 +61,40 @@ func TestFromMap(t *testing.T) { chain := FromMap(input) expectedOutput := []interface{}{ - generator.MapTuple{ - Key: key1, - Value: value1, + &testKeyValue{ + TheKey: key1, + TheValue: value1, }, - generator.MapTuple{ - Key: key2, - Value: value2, + &testKeyValue{ + TheKey: key2, + TheValue: value2, }, - generator.MapTuple{ - Key: key3, - Value: value3, + &testKeyValue{ + TheKey: key3, + TheValue: value3, }, } slice, err := chain.Slice() //not testing the order because we are not guaranteed the order in which a map is iterated over - assert.ElementsMatch(expectedOutput, slice) + assertEqualsBasedOnKeyValuerInterface(t, expectedOutput, slice) assert.Nil(err) } -func createTestChannel(stringSlice []string) chan string { +type testKeyValue struct { + TheKey interface{} + TheValue interface{} +} + +func (t *testKeyValue) Key() interface{} { + return t.TheKey +} + +func (t *testKeyValue) Value() interface{} { + return t.TheValue +} + +func createTestStringChannel(stringSlice []string) chan string { stringChannel := make(chan string) go func() { @@ -93,3 +106,38 @@ func createTestChannel(stringSlice []string) chan string { return stringChannel } + +func assertEqualsBasedOnKeyValuerInterface(t *testing.T, expected []interface{}, actual []interface{}) { + assert := assert.New(t) + + assert.Len(actual, len(expected)) + + for _, expectedValue := range expected { + expectedKeyValuer, isType := expectedValue.(keyvalue.KeyValuer) + if !isType { + continue + } + keyToFind := expectedKeyValuer.Key() + foundMatch := false + + for _, actualValue := range actual { + actualKeyValuer, isType := actualValue.(keyvalue.KeyValuer) + if !isType { + continue + } + actualKey := actualKeyValuer.Key() + + if actualKey != keyToFind { + continue + } + + if expectedKeyValuer.Value() != actualKeyValuer.Value() { + continue + } + + foundMatch = true + } + + assert.True(foundMatch) + } +} diff --git a/doc.go b/doc.go index 0d43c47..e6d4edd 100644 --- a/doc.go +++ b/doc.go @@ -28,4 +28,18 @@ // // Notice `stringValue := value.(string)` above. This allows one to do the string concatenation on the next line because // the `+` operator doesn't work on an `interface{}` type. +// +// Continuing the Chain +// +// Chaining methods apply some modification to the values in the container values, but keeps the chain alive. +// This allows additional chaining methods to be subsequently called on the result. The subsequent chain methods operate +// on any changes performed by the previous chain method. +// Because modifications are lazily computed, none of the modifications from chaining methods are applied until _after_ a +// terminating method is called. +// +// Terminating the Chain +// +// Terminating methods also apply some modification, requests some information, or executes something on the values. +// They stop the chaining by returning an actual value. This value will depend on all the previous chaining methods being +// executed first. package rangechain diff --git a/example_test.go b/example_test.go index 728a1b6..d28a37e 100644 --- a/example_test.go +++ b/example_test.go @@ -2,7 +2,7 @@ package rangechain import ( "fmt" - "github.com/halprin/rangechain/generator" + "github.com/halprin/rangechain/keyvalue" "testing" ) @@ -60,17 +60,17 @@ func TestSortingMaps(t *testing.T) { chain := FromMap(aMap) sortedAppleStuff, _ := chain.Sort(func(mapValuesToSort []interface{}) func(int, int) bool { return func(index1 int, index2 int) bool { - mapValue1 := mapValuesToSort[index1].(generator.MapTuple) - mapValue2 := mapValuesToSort[index2].(generator.MapTuple) + mapValue1 := mapValuesToSort[index1].(keyvalue.KeyValuer) + mapValue2 := mapValuesToSort[index2].(keyvalue.KeyValuer) - rating1 := mapValue1.Value.(int) - rating2 := mapValue2.Value.(int) + rating1 := mapValue1.Value().(int) + rating2 := mapValue2.Value().(int) return rating1 > rating2 } }).Map(func(value interface{}) (interface{}, error) { - mapValue := value.(generator.MapTuple) - return mapValue.Key, nil + mapValue := value.(keyvalue.KeyValuer) + return mapValue.Key(), nil }).Slice() fmt.Println(sortedAppleStuff) diff --git a/helper/doc.go b/helper/doc.go deleted file mode 100644 index 8dfffb4..0000000 --- a/helper/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package helper is not meant to be used directly by external users. -package helper diff --git a/intermediate/doc.go b/intermediate/doc.go deleted file mode 100644 index 0f1ab23..0000000 --- a/intermediate/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Package intermediate is used continue or terminate the chain. -// -// Continuing the Chain -// -// Chaining methods apply some modification to the values in the container values, but keeps the chain alive. -// This allows additional chaining methods to be subsequently called on the result. The subsequent chain methods operate -// on any changes performed by the previous chain method. -// Because modifications are lazily computed, none of the modifications from chaining methods are applied until _after_ a -// terminating method is called. -// -// Terminating the Chain -// -// Terminating methods also apply some modification, requests some information, or executes something on the values. -// They stop the chaining by returning an actual value. This value will depend on all the previous chaining methods being -// executed first. -package intermediate diff --git a/intermediate/link.go b/intermediate/link.go deleted file mode 100644 index af4449f..0000000 --- a/intermediate/link.go +++ /dev/null @@ -1,13 +0,0 @@ -package intermediate - -// Link is not meant to be initialized directly by external users. Use the `From*` functions in the parent package rangechain. -type Link struct { - generator func() (interface{}, error) -} - -// NewLink is not meant to be called directly by external users. Use the `From*` functions in the parent package rangechain. -func NewLink(generator func() (interface{}, error)) *Link { - return &Link{ - generator: generator, - } -} diff --git a/generator/generator.go b/internal/generator/generator.go similarity index 69% rename from generator/generator.go rename to internal/generator/generator.go index f5fa99a..b429e44 100644 --- a/generator/generator.go +++ b/internal/generator/generator.go @@ -3,20 +3,14 @@ package generator import ( "errors" - "github.com/halprin/rangechain/helper" + "github.com/halprin/rangechain/internal/helper" "reflect" ) // Exhausted is returned as an expected error from the generators to designate an end of the generator. var Exhausted = errors.New("generator exhausted") -// MapTuple is used to represent the key and value pairs of a map when iterating over a map. -type MapTuple struct { - Key interface{} - Value interface{} -} - -// FromSlice is not meant to be called directly by external users. Creates a generator for a slice. +// FromSlice creates a generator for a slice. func FromSlice(slice interface{}) func() (interface{}, error) { if !helper.IsSlice(slice) { panic("non-slice type provided") @@ -25,7 +19,7 @@ func FromSlice(slice interface{}) func() (interface{}, error) { return generatorFromSliceOrArray(slice) } -// FromArray is not meant to be called directly by external users. Creates a generator for an array. +// FromArray creates a generator for an array. func FromArray(array interface{}) func() (interface{}, error) { if !helper.IsArray(array) { panic("non-array type provided") @@ -34,7 +28,7 @@ func FromArray(array interface{}) func() (interface{}, error) { return generatorFromSliceOrArray(array) } -// FromChannel is not meant to be called directly by external users. Creates a generator for a channel. +// FromChannel creates a generator for a channel. func FromChannel(channel interface{}) func() (interface{}, error) { if !helper.IsChannel(channel) { panic("non-channel type provided") @@ -54,7 +48,7 @@ func FromChannel(channel interface{}) func() (interface{}, error) { } } -// FromMap is not meant to be called directly by external users. Creates a generator for a map. +// FromMap creates a generator for a map. func FromMap(aMap interface{}) func() (interface{}, error) { if !helper.IsMap(aMap) { panic("non-map type provided") @@ -69,12 +63,12 @@ func FromMap(aMap interface{}) func() (interface{}, error) { return 0, Exhausted } - mapTuple := MapTuple{ - Key: mapIterator.Key().Interface(), - Value: mapIterator.Value().Interface(), + tuple := &mapTuple{ + TheKey: mapIterator.Key().Interface(), + TheValue: mapIterator.Value().Interface(), } - return mapTuple, nil + return tuple, nil } } diff --git a/generator/generator_test.go b/internal/generator/generator_test.go similarity index 100% rename from generator/generator_test.go rename to internal/generator/generator_test.go diff --git a/internal/generator/keyvalue.go b/internal/generator/keyvalue.go new file mode 100644 index 0000000..0ac5557 --- /dev/null +++ b/internal/generator/keyvalue.go @@ -0,0 +1,15 @@ +package generator + +// mapTuple implements the `keyvalue.KeyValuer` interface and is used to represent map's keys and values +type mapTuple struct { + TheKey interface{} + TheValue interface{} +} + +func (m *mapTuple) Key() interface{} { + return m.TheKey +} + +func (m *mapTuple) Value() interface{} { + return m.TheValue +} diff --git a/helper/interface.go b/internal/helper/interface.go similarity index 100% rename from helper/interface.go rename to internal/helper/interface.go diff --git a/helper/interface_test.go b/internal/helper/interface_test.go similarity index 100% rename from helper/interface_test.go rename to internal/helper/interface_test.go diff --git a/helper/set.go b/internal/helper/set.go similarity index 100% rename from helper/set.go rename to internal/helper/set.go diff --git a/helper/set_test.go b/internal/helper/set_test.go similarity index 100% rename from helper/set_test.go rename to internal/helper/set_test.go diff --git a/helper/type.go b/internal/helper/type.go similarity index 100% rename from helper/type.go rename to internal/helper/type.go diff --git a/helper/type_test.go b/internal/helper/type_test.go similarity index 100% rename from helper/type_test.go rename to internal/helper/type_test.go diff --git a/keyvalue/interface.go b/keyvalue/interface.go new file mode 100644 index 0000000..e3113a7 --- /dev/null +++ b/keyvalue/interface.go @@ -0,0 +1,8 @@ +// Package keyvalue exists to specify the interface of `KeyValuer`. +package keyvalue + +// KeyValuer is used to represent key and value pairs. +type KeyValuer interface { + Key() interface{} + Value() interface{} +} diff --git a/link.go b/link.go new file mode 100644 index 0000000..a07c712 --- /dev/null +++ b/link.go @@ -0,0 +1,12 @@ +package rangechain + +// Link is not meant to be initialized directly by external users. Use the `From*` functions. +type Link struct { + generator func() (interface{}, error) +} + +func newLink(generator func() (interface{}, error)) *Link { + return &Link{ + generator: generator, + } +} diff --git a/intermediate/link_chain.go b/link_chain.go similarity index 91% rename from intermediate/link_chain.go rename to link_chain.go index 1ab0267..8ed0a6e 100644 --- a/intermediate/link_chain.go +++ b/link_chain.go @@ -1,9 +1,9 @@ -package intermediate +package rangechain import ( "errors" - "github.com/halprin/rangechain/generator" - "github.com/halprin/rangechain/helper" + "github.com/halprin/rangechain/internal/generator" + "github.com/halprin/rangechain/internal/helper" "sort" ) @@ -18,7 +18,7 @@ func (receiver *Link) Map(mapFunction func(interface{}) (interface{}, error)) *L return mapFunction(valueToMap) } - return NewLink(mapGenerator) + return newLink(mapGenerator) } // Filter will run the `filterFunction` parameter function against all the values in the chain. In that function, on return of true, the value will stay, or on false, the value will be removed. @@ -41,7 +41,7 @@ func (receiver *Link) Filter(filterFunction func(interface{}) (bool, error)) *Li } } - return NewLink(filterGenerator) + return newLink(filterGenerator) } // Skip skips over the parameter `skipNumber` number of values and effectively removes them from the chain. Also skips over any errors previously generated. @@ -50,7 +50,7 @@ func (receiver *Link) Skip(skipNumber int) *Link { _, _ = receiver.generator() } - return NewLink(receiver.generator) + return newLink(receiver.generator) } // Limit stops the chain after the parameter `keepSize` number of values. Any elements afterward are effectively removed. @@ -72,7 +72,7 @@ func (receiver *Link) Limit(keepSize int) *Link { return currentValue, err } - return NewLink(limitGenerator) + return newLink(limitGenerator) } // Distinct removes any duplicates. @@ -94,10 +94,10 @@ func (receiver *Link) Distinct() *Link { } } - return NewLink(distinctGenerator) + return newLink(distinctGenerator) } -// Flatten will iterate over all the values in the chain, but any value encountered that is a range-able container itself will also have its values iterated over first before continuing with the remaining values in the chain. Maps flatten to its `generator.MapTuple` key and value pairs. +// Flatten will iterate over all the values in the chain, but any value encountered that is a range-able container itself will also have its values iterated over first before continuing with the remaining values in the chain. Maps flatten to its `keyvalue.KeyValuer` key and value pairs. func (receiver *Link) Flatten() *Link { var currentGenerator func() (interface{}, error) @@ -139,7 +139,7 @@ func (receiver *Link) Flatten() *Link { return innerValue, err } - return NewLink(flattenGenerator) + return newLink(flattenGenerator) } // Sort sorts the chain given the `Less` function returned from the `returnLessFunction` function parameter. The `returnLessFunction` function is called with the entire serialized chain as a slice and _returns_ a function that satisfies the same requirements as the Interface type's `Less` function (https://pkg.go.dev/sort#Interface). This method is expensive because it must serialize all the values into a slice first. @@ -151,7 +151,7 @@ func (receiver *Link) Sort(returnLessFunction func([]interface{}) func(int, int) generation := func() (interface{}, error) { return 0, err } - return NewLink(generation) + return newLink(generation) } lessFunction := returnLessFunction(serializedSlice) @@ -159,7 +159,7 @@ func (receiver *Link) Sort(returnLessFunction func([]interface{}) func(int, int) generation := generator.FromSlice(serializedSlice) - return NewLink(generation) + return newLink(generation) } // Reverse reverses the order of the chain. The last item will be first, and the first item will be last. This method is expensive because it must serialize all the values into a slice first. @@ -171,7 +171,7 @@ func (receiver *Link) Reverse() *Link { generation := func() (interface{}, error) { return 0, err } - return NewLink(generation) + return newLink(generation) } for startIndex, endIndex := 0, len(serializedSlice) - 1; startIndex <= endIndex; startIndex, endIndex = startIndex + 1, endIndex - 1 { @@ -180,5 +180,5 @@ func (receiver *Link) Reverse() *Link { generation := generator.FromSlice(serializedSlice) - return NewLink(generation) + return newLink(generation) } diff --git a/intermediate/link_chain_parallel.go b/link_chain_parallel.go similarity index 97% rename from intermediate/link_chain_parallel.go rename to link_chain_parallel.go index 7fadf3c..8809872 100644 --- a/intermediate/link_chain_parallel.go +++ b/link_chain_parallel.go @@ -1,6 +1,6 @@ -package intermediate +package rangechain -import "github.com/halprin/rangechain/generator" +import "github.com/halprin/rangechain/internal/generator" // MapParallel will run the `mapFunction` parameter function against all the values in the chain in parallel. In that function, return what you want to change the value into or an optional error if an error is encountered. There is overhead to running in parallel so benchmark to ensure you benefit from this version. func (receiver *Link) MapParallel(mapFunction func(interface{}) (interface{}, error)) *Link { @@ -27,7 +27,7 @@ func (receiver *Link) MapParallel(mapFunction func(interface{}) (interface{}, er return value, err } - return NewLink(mapGenerator) + return newLink(mapGenerator) } func mapFunctionAgainstEntireGenerator(generatorToParallelize func() (interface{}, error), mapFunction func(interface{}) (interface{}, error)) ([]chan interface{}, []chan error) { @@ -92,7 +92,7 @@ func (receiver *Link) FilterParallel(filterFunction func(interface{}) (bool, err } } - return NewLink(filterGenerator) + return newLink(filterGenerator) } func filterFunctionAgainstEntireGenerator(generatorToParallelize func() (interface{}, error), filterFunction func(interface{}) (bool, error)) ([]chan interface{}, []chan error) { diff --git a/intermediate/link_chain_parallel_test.go b/link_chain_parallel_test.go similarity index 90% rename from intermediate/link_chain_parallel_test.go rename to link_chain_parallel_test.go index d6f3741..5d1e9bc 100644 --- a/intermediate/link_chain_parallel_test.go +++ b/link_chain_parallel_test.go @@ -1,9 +1,9 @@ -package intermediate +package rangechain import ( "errors" - "github.com/halprin/rangechain/generator" - "github.com/halprin/rangechain/helper" + "github.com/halprin/rangechain/internal/generator" + "github.com/halprin/rangechain/internal/helper" "github.com/stretchr/testify/assert" "testing" ) @@ -18,7 +18,7 @@ func TestMapParallel(t *testing.T) { } generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) mapFunction := func(value interface{}) (interface{}, error) { stringValue := value.(string) @@ -39,7 +39,7 @@ func TestMapParallelHasError(t *testing.T) { inputSlice := []string{"DogCows", "goes", "Moof!", errorValue, "you", "like", "Clarus", "the", "DogCow?"} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) mapFunction := func(value interface{}) (interface{}, error) { stringValue := value.(string) @@ -60,7 +60,7 @@ func TestFilterParallel(t *testing.T) { inputSlice := []int{7, 4, 2, 3, 9, 5, 6, 0, 8, 1} expectedSlice := helper.InterfaceSlice([]int{7, 9, 6, 8}) generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) filterFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -80,7 +80,7 @@ func TestFilterParallelHasError(t *testing.T) { errorValue := 9 inputSlice := []int{7, 4, 2, 3, errorValue, 5, 6, 0, 8, 1} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) filterFunction := func(value interface{}) (bool, error) { intValue := value.(int) diff --git a/intermediate/link_chain_test.go b/link_chain_test.go similarity index 89% rename from intermediate/link_chain_test.go rename to link_chain_test.go index d5e256c..c555a2f 100644 --- a/intermediate/link_chain_test.go +++ b/link_chain_test.go @@ -1,9 +1,9 @@ -package intermediate +package rangechain import ( "errors" - "github.com/halprin/rangechain/generator" - "github.com/halprin/rangechain/helper" + "github.com/halprin/rangechain/internal/generator" + "github.com/halprin/rangechain/internal/helper" "github.com/stretchr/testify/assert" "testing" ) @@ -18,7 +18,7 @@ func TestMap(t *testing.T) { } generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) mapFunction := func(value interface{}) (interface{}, error) { stringValue := value.(string) @@ -42,7 +42,7 @@ func TestMapGeneratesError(t *testing.T) { } generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) mapFunction := func(value interface{}) (interface{}, error) { stringValue := value.(string) @@ -64,7 +64,7 @@ func TestFilter(t *testing.T) { inputSlice := []int{7, 4, 2, 3, 9, 5, 6, 0, 8, 1} expectedSlice := helper.InterfaceSlice([]int{7, 9, 6, 8}) generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) filterFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -84,7 +84,7 @@ func TestFilterHasError(t *testing.T) { expectedError := errors.New("an example error") inputSlice := []int{7, 4, 2, 3, errorValue, 5, 6, 0, 8, 1} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) filterFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -104,7 +104,7 @@ func TestSkip(t *testing.T) { inputSlice := []int{7, 4, 2, 3, 9, 5, 6, 0, 8, 1} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) howManyToSkip := 3 actualSlice, err := link.Skip(howManyToSkip).Slice() @@ -118,7 +118,7 @@ func TestSkipLargerThanSlice(t *testing.T) { inputSlice := []int{7, 4, 2, 3, 9, 5, 6, 0, 8, 1} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualSlice, err := link.Skip(len(inputSlice) + 1).Slice() @@ -131,7 +131,7 @@ func TestLimit(t *testing.T) { inputSlice := []int{7, 4, 2, 3, 9, 5, 6, 0, 8, 1} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) howManyToKeep := 6 actualSlice, err := link.Limit(howManyToKeep).Slice() @@ -145,7 +145,7 @@ func TestLimitLargerThanSlice(t *testing.T) { inputSlice := []int{7, 4, 2, 3, 9, 5, 6, 0, 8, 1} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualSlice, err := link.Limit(len(inputSlice) + 1).Slice() @@ -159,7 +159,7 @@ func TestDistinct(t *testing.T) { inputSlice := []int{7, 4, 2, 7, 3, 7, 9, 5, 5, 2, 6, 0, 8, 1} expectedSlice := helper.InterfaceSlice([]int{7, 4, 2, 3, 9, 5, 6, 0, 8, 1}) generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualSlice, err := link.Distinct().Slice() @@ -173,7 +173,7 @@ func TestFlattenWithSliceOfSlice(t *testing.T) { inputSlice := [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} expectedSlice := helper.InterfaceSlice([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}) generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualSlice, err := link.Flatten().Slice() @@ -187,7 +187,7 @@ func TestFlattenWithSliceMix(t *testing.T) { inputSlice := []interface{}{[]int{1, 2, 3}, 4, []int{7, 8, 9}} expectedSlice := helper.InterfaceSlice([]int{1, 2, 3, 4, 7, 8, 9}) generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualSlice, err := link.Flatten().Slice() @@ -201,7 +201,7 @@ func TestFlattenWithArray(t *testing.T) { inputSlice := []interface{}{[...]int{1, 2, 3}, 4, [...]int{7, 8, 9}} expectedSlice := helper.InterfaceSlice([]int{1, 2, 3, 4, 7, 8, 9}) generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualSlice, err := link.Flatten().Slice() @@ -212,13 +212,13 @@ func TestFlattenWithArray(t *testing.T) { func TestFlattenWithChannel(t *testing.T) { assert := assert.New(t) - firstChannel := createTestChannel([]int{1, 2, 3}) - secondChannel := createTestChannel([]int{7, 8, 9}) + firstChannel := createTestIntChannel([]int{1, 2, 3}) + secondChannel := createTestIntChannel([]int{7, 8, 9}) inputSlice := []interface{}{firstChannel, 4, secondChannel} expectedSlice := helper.InterfaceSlice([]int{1, 2, 3, 4, 7, 8, 9}) generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualSlice, err := link.Flatten().Slice() @@ -243,13 +243,13 @@ func TestFlattenWithSliceAndMap(t *testing.T) { 1, 2, 3, - generator.MapTuple{ - Key: key1, - Value: value1, + &testKeyValue{ + TheKey: key1, + TheValue: value1, }, - generator.MapTuple{ - Key: key2, - Value: value2, + &testKeyValue{ + TheKey: key2, + TheValue: value2, }, 7, 8, @@ -257,12 +257,12 @@ func TestFlattenWithSliceAndMap(t *testing.T) { } generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualSlice, err := link.Flatten().Slice() //not testing the order of the entire expected slice because we are not guaranteed the order in which a map is iterated over - assert.ElementsMatch(expectedSlice, actualSlice) + assertEqualsBasedOnKeyValuerInterface(t, expectedSlice, actualSlice) assert.Nil(err) //test the order for the non-map flattened parts assert.Equal(expectedSlice[0], actualSlice[0]) @@ -279,7 +279,7 @@ func TestSort(t *testing.T) { inputSlice := []int{7, 4, 2, 3, 9, 5, 6, 0, 8, 1} expectedSlice := helper.InterfaceSlice([]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) returnLessFunction := func(sliceToSort []interface{}) func(int, int) bool { return func(i int, j int) bool { @@ -301,7 +301,7 @@ func TestSortHasError(t *testing.T) { errorValue := 9 inputSlice := []int{7, 4, 2, 3, errorValue, 5, 6, 0, 8, 1} generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) returnLessFunction := func(sliceToSort []interface{}) func(int, int) bool { return func(i int, j int) bool { @@ -321,7 +321,7 @@ func TestReverse(t *testing.T) { inputSlice := []int{7, 4, 2, 3, 9, 5, 6, 0, 8, 1} expectedSlice := helper.InterfaceSlice([]int{1, 8, 0, 6, 5, 9, 3, 2, 4, 7}) generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualSlice, err := link.Reverse().Slice() @@ -336,14 +336,14 @@ func TestReverseHasError(t *testing.T) { errorValue := 9 inputSlice := []int{7, 4, 2, 3, errorValue, 5, 6, 0, 8, 1} generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) _, err := link.Reverse().Slice() assert.Equal(expectedError, err) } -func createTestChannel(intSlice []int) chan interface{} { +func createTestIntChannel(intSlice []int) chan interface{} { intChannel := make(chan interface{}) go func() { diff --git a/intermediate/link_termination.go b/link_termination.go similarity index 99% rename from intermediate/link_termination.go rename to link_termination.go index e04b566..e272634 100644 --- a/intermediate/link_termination.go +++ b/link_termination.go @@ -1,8 +1,8 @@ -package intermediate +package rangechain import ( "errors" - "github.com/halprin/rangechain/generator" + "github.com/halprin/rangechain/internal/generator" ) // Slice serializes the chain into a slice and returns it. Also returns an error if any previous chain method generated an error. If an error is returned, the slice is filled in until the error was encountered. diff --git a/intermediate/link_termination_test.go b/link_termination_test.go similarity index 93% rename from intermediate/link_termination_test.go rename to link_termination_test.go index bc53b66..3c704cb 100644 --- a/intermediate/link_termination_test.go +++ b/link_termination_test.go @@ -1,10 +1,10 @@ -package intermediate +package rangechain import ( "errors" - "github.com/halprin/rangechain/generator" - "github.com/halprin/rangechain/helper" + "github.com/halprin/rangechain/internal/generator" + "github.com/halprin/rangechain/internal/helper" "github.com/stretchr/testify/assert" "sync" "testing" @@ -14,7 +14,7 @@ func TestSlice(t *testing.T) { assert := assert.New(t) expectedSlice := []int{987, 8, 26} generation := generator.FromSlice(expectedSlice) - link := NewLink(generation) + link := newLink(generation) actualSlice, err := link.Slice() @@ -29,7 +29,7 @@ func TestSliceWithErrorReturnsPartOfSlice(t *testing.T) { inputSlice := []int{987, 8, errorValue} expectedError := errors.New("an example error yo") generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) actualSlice, err := link.Slice() @@ -42,7 +42,7 @@ func TestChannel(t *testing.T) { expectedSlice := []int{987, 8, 26} generation := generator.FromSlice(expectedSlice) - link := NewLink(generation) + link := newLink(generation) var seenItems []interface{} valueChannel, errorChannel := link.Channel() @@ -62,7 +62,7 @@ func TestChannelHasError(t *testing.T) { inputSlice := []int{987, errorValue, 26} expectedError := errors.New("an example error yo") generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) var seenItems []interface{} valueChannel, errorChannel := link.Channel() @@ -80,7 +80,7 @@ func TestForEach(t *testing.T) { inputSlice := []int{987, 8, 26} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) var seenItems []interface{} forEachFunction := func(value interface{}) { @@ -97,7 +97,7 @@ func TestForEachHasError(t *testing.T) { inputSlice := []int{987, errorValue, 26} expectedError := errors.New("an example error yo") generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) forEachFunction := func(value interface{}) {} err := link.ForEach(forEachFunction) @@ -115,7 +115,7 @@ func TestForEachParallel(t *testing.T) { 8: true, } generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) seenItems := map[int]bool{} seenItemsLock := sync.RWMutex{} @@ -147,7 +147,7 @@ func TestForEachParallelHasError(t *testing.T) { inputSlice := []int{987, errorValue, 26} expectedError := errors.New("an example error yo") generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) forEachFunction := func(value interface{}) {} err := link.ForEachParallel(forEachFunction) @@ -160,7 +160,7 @@ func TestCount(t *testing.T) { inputSlice := []int{987, 8, 26} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualCount, err := link.Count() @@ -175,7 +175,7 @@ func TestCountWithErrorStillCounts(t *testing.T) { inputSlice := []int{987, errorValue, errorValue} expectedError := errors.New("an example error yo") generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) actualCount, err := link.Count() @@ -192,7 +192,7 @@ func TestCountWithFirstErrorReturns(t *testing.T) { expectedError := errors.New("an example error yo") secondError := errors.New("another error") generation := wrapGeneratorWithError(createGeneratorWithError(inputSlice, errorValue, expectedError), secondErrorValue, secondError) - link := NewLink(generation) + link := newLink(generation) _, err := link.Count() @@ -204,7 +204,7 @@ func TestFirst(t *testing.T) { inputSlice := []int{987, 8, 26} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualFirst, err := link.First() @@ -218,7 +218,7 @@ func TestFirstWithEmptySlice(t *testing.T) { var inputSlice []int generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualFirst, err := link.First() @@ -233,7 +233,7 @@ func TestFirstHasError(t *testing.T) { inputSlice := []int{errorValue, 8, 26} expectedError := errors.New("an example error yo") generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) actualFirst, err := link.First() @@ -246,7 +246,7 @@ func TestLast(t *testing.T) { inputSlice := []int{987, 8, 26} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualLast, err := link.Last() @@ -260,7 +260,7 @@ func TestLastWithEmptySlice(t *testing.T) { var inputSlice []int generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) actualLast, err := link.Last() @@ -275,7 +275,7 @@ func TestLastHasError(t *testing.T) { inputSlice := []int{987, 8, errorValue} expectedError := errors.New("an example error yo") generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) _, err := link.Last() @@ -287,7 +287,7 @@ func TestAllMatch(t *testing.T) { inputSlice := []int{984, 8, 26} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) allMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -304,7 +304,7 @@ func TestNotAllMatch(t *testing.T) { inputSlice := []int{984, 7, 26} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) allMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -321,7 +321,7 @@ func TestAllMatchWithEmptySlice(t *testing.T) { var inputSlice []int generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) allMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -340,7 +340,7 @@ func TestAllMatchWithEarlierError(t *testing.T) { inputSlice := []int{984, errorValue, 26} expectedError := errors.New("an example error yo") generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) allMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -359,7 +359,7 @@ func TestAllMatchWithErrorInMatchFunction(t *testing.T) { inputSlice := []int{984, errorValue, 26} expectedError := errors.New("an example error yo") generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) allMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -379,7 +379,7 @@ func TestAnyMatch(t *testing.T) { inputSlice := []int{985, 3, 26} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) anyMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -396,7 +396,7 @@ func TestNotAnyMatch(t *testing.T) { inputSlice := []int{985, 7, 29} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) anyMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -413,7 +413,7 @@ func TestAnyMatchWithEmptySlice(t *testing.T) { var inputSlice []int generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) anyMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -432,7 +432,7 @@ func TestAnyMatchWithEarlierError(t *testing.T) { inputSlice := []int{985, 3, errorValue} expectedError := errors.New("an example error yo") generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) anyMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -451,7 +451,7 @@ func TestAnyMatchWithErrorInMatchFunction(t *testing.T) { inputSlice := []int{985, 3, errorValue} expectedError := errors.New("an example error yo") generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) anyMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -471,7 +471,7 @@ func TestNoneMatch(t *testing.T) { inputSlice := []int{985, 3, 27} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) noneMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -488,7 +488,7 @@ func TestNotNoneMatch(t *testing.T) { inputSlice := []int{985, 7, 28} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) noneMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -505,7 +505,7 @@ func TestNoneMatchWithEmptySlice(t *testing.T) { var inputSlice []int generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) noneMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -524,7 +524,7 @@ func TestNoneMatchWithEarlierError(t *testing.T) { inputSlice := []int{985, errorValue, 27} expectedError := errors.New("an example error yo") generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) noneMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -543,7 +543,7 @@ func TestNoneMatchWithErrorInMatchFunction(t *testing.T) { inputSlice := []int{985, errorValue, 27} expectedError := errors.New("an example error yo") generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) noneMatchFunction := func(value interface{}) (bool, error) { intValue := value.(int) @@ -564,7 +564,7 @@ func TestReduce(t *testing.T) { inputSlice := []int{987, 8, 26} expectedValue := inputSlice[0] * inputSlice[1] * inputSlice[2] generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) reduceFunction := func(firstItem interface{}, secondItem interface{}) (interface{}, error) { firstIntItem := firstItem.(int) @@ -584,7 +584,7 @@ func TestReduceWithOneItem(t *testing.T) { inputSlice := []int{987} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) reduceFunction := func(firstItem interface{}, secondItem interface{}) (interface{}, error) { firstIntItem := firstItem.(int) @@ -604,7 +604,7 @@ func TestReduceWithZeroItems(t *testing.T) { inputSlice := []int{} generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) reduceFunction := func(firstItem interface{}, secondItem interface{}) (interface{}, error) { firstIntItem := firstItem.(int) @@ -625,7 +625,7 @@ func TestReduceWithEarlierError(t *testing.T) { inputSlice := []int{987, 8, errorValue} expectedError := errors.New("an example error yo") generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) reduceFunction := func(firstItem interface{}, secondItem interface{}) (interface{}, error) { firstIntItem := firstItem.(int) @@ -645,7 +645,7 @@ func TestReduceWithErrorInReduceFunction(t *testing.T) { inputSlice := []int{987, 8, errorValue} expectedError := errors.New("an example error yo") generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) reduceFunction := func(firstItem interface{}, secondItem interface{}) (interface{}, error) { firstIntItem := firstItem.(int) @@ -668,7 +668,7 @@ func TestReduceWithInitialValue(t *testing.T) { inputInitialValue := 4 expectedValue := inputInitialValue * inputSlice[0] * inputSlice[1] * inputSlice[2] generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) reduceFunction := func(firstItem interface{}, secondItem interface{}) (interface{}, error) { firstIntItem := firstItem.(int) @@ -688,7 +688,7 @@ func TestReduceWithInitialValueWithOneItem(t *testing.T) { inputSlice := []int{987} inputInitialValue := 4 generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) reduceFunction := func(firstItem interface{}, secondItem interface{}) (interface{}, error) { firstIntItem := firstItem.(int) @@ -708,7 +708,7 @@ func TestReduceWithInitialValueWithZeroItems(t *testing.T) { inputSlice := []int{} inputInitialValue := 4 generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) reduceFunction := func(firstItem interface{}, secondItem interface{}) (interface{}, error) { firstIntItem := firstItem.(int) @@ -729,7 +729,7 @@ func TestReduceWithInitialValueWithEarlierError(t *testing.T) { inputSlice := []int{987, errorValue, 26} expectedError := errors.New("an example error yo") generation := createGeneratorWithError(inputSlice, errorValue, expectedError) - link := NewLink(generation) + link := newLink(generation) reduceFunction := func(firstItem interface{}, secondItem interface{}) (interface{}, error) { firstIntItem := firstItem.(int) @@ -749,7 +749,7 @@ func TestReduceWithInitialValueWithErrorInReduceFunction(t *testing.T) { inputSlice := []int{987, errorValue, 26} expectedError := errors.New("an example error yo") generation := generator.FromSlice(inputSlice) - link := NewLink(generation) + link := newLink(generation) reduceFunction := func(firstItem interface{}, secondItem interface{}) (interface{}, error) { firstIntItem := firstItem.(int)