diff --git a/README.md b/README.md index a103eec..1b1b024 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # pgo + Go library for PHP community with convenient functions [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go) @@ -10,31 +11,32 @@ Go library for PHP community with convenient functions * [Installation](#user-content-installation) * [Core](#user-content-core) - * [Serialize/Unserialize](#user-content-serializeunserialize) + * [Serialize/Unserialize](#user-content-serializeunserialize) * [Date](#user-content-date) * [Milli/Micro](#user-content-millimicro) * [Strings](#user-content-strings) - * [StrReplace/StrIReplace](#user-content-strreplace) - * [HTTPBuildQuery](#user-content-httpbuildquery) - * [StripTags](#user-content-striptags) + * [StrReplace/StrIReplace](#user-content-strreplace) + * [HTTPBuildQuery](#user-content-httpbuildquery) + * [StripTags](#user-content-striptags) * [Files](#user-content-files) - * [FileGetContents](#user-content-filegetcontents) - * [FilePutContents](#user-content-fileputcontents) - * [MoveUploadedFile](#user-content-moveuploadedfile) - * [FileExists](#user-content-fileexists) - * [IsFile/IsDir/IsLink](#user-content-isfileisdirislink) + * [FileGetContents](#user-content-filegetcontents) + * [FilePutContents](#user-content-fileputcontents) + * [MoveUploadedFile](#user-content-moveuploadedfile) + * [FileExists](#user-content-fileexists) + * [IsFile/IsDir/IsLink](#user-content-isfileisdirislink) * [Arrays](#user-content-arrays) - * [InArray](#user-content-inarray) - * [ArrayChunk](#user-content-arraychunk) - * [ArrayCombine](#user-content-arraycombine) - * [ArrayCountValues](#user-content-arraycountvalues) - * [ArrayMap](#user-content-arraymap) - * [ArrayFilter](#user-content-arrayfilter) - * [ArrayDiff](#user-content-arraydiff) - * [ArrayUdiff](#user-content-arrayudiff) - * [ArraySum](#user-content-arraysum) - * [ArrayIntersect](#user-content-arrayintersect) - * [Range](#user-content-range) + * [InArray](#user-content-inarray) + * [ArrayChunk](#user-content-arraychunk) + * [ArrayCombine](#user-content-arraycombine) + * [ArrayCountValues](#user-content-arraycountvalues) + * [ArrayMap](#user-content-arraymap) + * [ArrayFilter](#user-content-arrayfilter) + * [ArrayDiff](#user-content-arraydiff) + * [ArrayUdiff](#user-content-arrayudiff) + * [ArraySum](#user-content-arraysum) + * [ArrayIntersect](#user-content-arrayintersect) + * [Range](#user-content-range) + * [EqualSlices](#user-content-equalslices) * [Collections](#user-content-collections) * [PriorityQueue](#user-content-priority-queue) * [Network](#user-content-network) @@ -48,11 +50,12 @@ Go library for PHP community with convenient functions * [Sha2](#user-content-sha2) * [HashFile](#user-content-hashfile) * [HashHmac](#user-content-hashhmac) - * [IsValidMac](#user-content-isvalidmac) + * [IsValidMac](#user-content-isvalidmac) -#### Installation +#### Installation Via go get command: + ```bash go get github.com/arthurkushman/pgo ``` @@ -62,7 +65,10 @@ Imagine that you need to write Go code every day and also have a convenient func ### Core #### Serialize/Unserialize -For instance, to store Go code data in storage engines like rdbms, no-sql, key-value etc, you can use serialization functions to serialize Go code to string and unserialize it back from string to Go code: + +For instance, to store Go code data in storage engines like rdbms, no-sql, key-value etc, you can use serialization +functions to serialize Go code to string and unserialize it back from string to Go code: + ```go m := make(map[int]string, 0) m[0] = "abc" @@ -74,6 +80,7 @@ err = pgo.Unserialize(str, &unserMap) // unserMap -> map[int]string{0: "abc"} ``` ### Date + You can use date function with similar formatting for PHP e.g.: ```go @@ -85,6 +92,7 @@ pgo.Date("Q") // 3 (of 1,2,3,4 quarters) ``` #### Milli/Micro + ```go nowMicro := pgo.UnixMicro() // get current unix microseconds nowMilli := pgo.UnixMilli() // get current unix milliseconds @@ -98,7 +106,9 @@ nowMicroPlusSeven := pgo.Time(now.Add(time.Microsecond * 7)).Microseconds() ### Strings #### StrReplace + replace sub-strings with StrReplace: + ```go subject := "The quick brown fox jumped over the lazy dog" @@ -108,47 +118,60 @@ str, err := pgo.StrReplace([]string{"fox", "dog"}, []string{"cat", "elephant"}, ``` #### HTTPBuildQuery + Bulding a http query string: + ```go queryStr := pgo.HTTPBuildQuery(map[string]interface{}{ - "foo": "bar", - "bar": "baz", - "s": []string{"1", "foo", "2", "bar", "3", "baz"}, +"foo": "bar", +"bar": "baz", +"s": []string{"1", "foo", "2", "bar", "3", "baz"}, }) // bar=baz&foo=bar&s=1&s=foo&s=2&s=bar&s=3&s=baz ``` #### StripTags + Strip tags with exclusion rules: + ```go html := "
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
" str := html.StripTags(html, []string{"a", "span"}) // results in: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." ``` + UPD: As had been stated here - https://github.com/golang/go/issues/22639 -There is a very handy "stripTags" function in html/template, then guys from official team as fast as they got dislike on their negative comment, closed the thread. -That is why libs like `pgo` is appearing and will be move forward/evelove, bypassing strict rules that sometimes looking nonsence. +There is a very handy "stripTags" function in html/template, then guys from official team as fast as they got dislike on +their negative comment, closed the thread. That is why libs like `pgo` is appearing and will be move forward/evelove, +bypassing strict rules that sometimes looking nonsence. ### Files #### FileGetContents + Read files with offset/limit: + ```go content, err := pgo.FileGetContents("somefile.txt", 0, 1024) ``` #### FilePutContents + reflexively write to files with: + ```go n, err := pgo.FilePutContents("somefile.txt", strToWrite, pgo.FileAppend) ``` Read from context (via http(s)): + ```go content, err := pgo.FileGetContents("http://google.com", pgo.NewContext()) ``` #### MoveUploadedFile + Uploading files from web-forms to your server: + ```go ctx := pgo.NewContext() ctx.Req = YourReq @@ -158,15 +181,19 @@ uploaded := ctx.MoveUploadedFile("foo", "/srv/images/pic123.png") ``` #### FileExists + Checking for file existence + ```go if pgo.FileExists("file1.txt") == true { - // do something with existent file +// do something with existent file } ``` #### IsFile/IsDir/IsLink -Check if it is file/dir/symlink + +Check if it is file/dir/symlink + ```go if pgo.IsFile("someFile.txt") { // do something with file @@ -184,7 +211,9 @@ if pgo.IsLink("someLink") { ### Arrays #### InArray + Check if an array contains an element + ```go pgo.InArray(3, []int{1, 2, 3}) // true pgo.InArray("bar33", []string{"foo", "bar", "baz"}) // false @@ -192,28 +221,32 @@ pgo.InArray(3.14159, []float64{33.12, 12.333, 3.14159, 78.4429}) // true ``` #### ArrayChunk + Split an array by chunks (with auto-tailing) + ```go pgo.ArrayChunk([]int{1, 2, 3, 4, 5, 6, 7, 8}, 2) // [][]int{[]int{1, 2}, []int{3, 4}, []int{5, 6}, []int{7, 8}} pgo.ArrayChunk([]string{"foo", "bar", "baz", "fizz", "buzz"}, 3) // [][]string{[]string{"foo", "bar", "baz"}, []string{"fizz", "buzz"}} ``` -#### ArrayCombine +#### ArrayCombine + Create an array by using one array for keys and another for its values + ```go pgo.ArrayCombine([]int{11, 32, 13, 14, 51, 46, 17, 88}, []string{"foo", "bar", "baz", "fizz", "buzz", "mazz", "freez", "lorum"}) /* -map[int]string{ - 11: "foo", - 32: "bar", - 13: "baz", - 14: "fizz", - 51: "buzz", - 46: "mazz", - 17: "freez", - 88: "lorum", - } + map[int]string{ + 11: "foo", + 32: "bar", + 13: "baz", + 14: "fizz", + 51: "buzz", + 46: "mazz", + 17: "freez", + 88: "lorum", + } */ pgo.ArrayCombine([]string{"foo", "bar", "baz", "fizz", "buzz"}, []float64{11.32, 32.42, 13.246, 14.41, 51.98}) /* @@ -228,7 +261,9 @@ map[string]float64{ ``` #### ArrayCountValues + Count all the values of an array/slice + ```go pgo.ArrayCountValues([]string{"foo", "bar", "foo", "baz", "bar", "bar"}) // map[string]int{"foo": 2, "bar": 3, "baz": 1} @@ -236,55 +271,64 @@ pgo.ArrayCountValues([]float64{3.14159, 43.03, 8, 3.14159, 43.02, 8}) // map[flo ``` #### ArrayMap + Apply the callback to the elements of the given arrays + ```go -pgo.ArrayMap([]string{"foo", "bar", "baz"}, func(v string) string { - return strings.ToUpper(v) - }) // []string{"FOO", "BAR", "BAZ"} +pgo.ArrayMap([]string{"foo", "bar", "baz"}, func (v string) string { +return strings.ToUpper(v) +}) // []string{"FOO", "BAR", "BAZ"} -pgo.ArrayMap([]float64{1, 2, 3, 4, 5}, func(v float64) float64 { - return math.Pow(v, 2) - }) // []float64{1, 4, 9, 16, 25} +pgo.ArrayMap([]float64{1, 2, 3, 4, 5}, func (v float64) float64 { +return math.Pow(v, 2) +}) // []float64{1, 4, 9, 16, 25} ``` #### ArrayFilter + filters elements of an array using a callback function + ```go -pgo.ArrayFilter([]float64{1, 2, 3, 4, 5}, func(v float64) bool { - return v > 2.718 - }) // []float64{3, 4, 5} +pgo.ArrayFilter([]float64{1, 2, 3, 4, 5}, func (v float64) bool { +return v > 2.718 +}) // []float64{3, 4, 5} ``` #### ArrayDiff + returns the values in array1 that are not present in any of the other arrays + ```go pgo.ArrayDiff([]string{"foo", "bar", "fizz", "baz"}, []string{"foo", "bar"}) // []string{"fizz", "baz"} pgo.ArrayDiff([]int{3, 43, 8, 4, 9}, []int{3, 8, 9, 4}) // []int{43} ``` #### ArrayUdiff + computes the difference of arrays by using a callback function for data comparison + ```go -pgo.ArrayUdiff(func(a interface{}, b interface{}) int { - if a.(string) > b.(string) { - return 1 - } else if a.(string) < b.(string) { - return -1 - } +pgo.ArrayUdiff(func (a interface{}, b interface{}) int { +if a.(string) > b.(string) { +return 1 +} else if a.(string) < b.(string) { +return -1 +} - return 0 +return 0 }, []string{"foo", "bar", "fizz", "baz"}, []string{"foo", "bar"}) // []string{"fizz", "baz"} -pgo.ArrayUdiff(func(a interface{}, b interface{}) int { - if a.(int) > b.(int) { - return 1 - } else if a.(int) < b.(int) { - return -1 - } +pgo.ArrayUdiff(func (a interface{}, b interface{}) int { +if a.(int) > b.(int) { +return 1 +} else if a.(int) < b.(int) { +return -1 +} - return 0 +return 0 }, []int{3, 43, 8, 4, 9}, []int{3, 8, 9, 4}) // []int{43} ``` + ```go type TestUdiffComparing interface {ComparingValue() string} @@ -298,50 +342,53 @@ type C struct {valueC string} func (c C) ComparingValue() string {return c.valueC} func main() { - a := []A {{valueA: "q"}, {valueA: "e"}, {valueA: "t"}, {valueA: "k"}, {valueA: "g"}, {valueA: "o"}, {valueA: "j"}} - b := []B {{valueB: "q"}, {valueB: "g"}, {valueB: "b"}, {valueB: "h"}, {valueB: "j"}, {valueB: "k"}, {valueB: "l"}} - c := []C {{valueC: "o"}, {valueC: "q"}, {valueC: "e"}, {valueC: "x"}, {valueC: "c"}, {valueC: "v"}, {valueC: "b"}} - - s1 := pgo.ArrayUdiff(func (arr1 interface{}, arr2 interface{}) int { - if arr1.(TestUdiffComparing).ComparingValue() > arr2.(TestUdiffComparing).ComparingValue() { - return 1 - } else if arr1.(TestUdiffComparing).ComparingValue() < arr2.(TestUdiffComparing).ComparingValue() { - return -1 - } - - return 0 - }, a, b, c) +a := []A {{valueA: "q"}, {valueA: "e"}, {valueA: "t"}, {valueA: "k"}, {valueA: "g"}, {valueA: "o"}, {valueA: "j"}} +b := []B {{valueB: "q"}, {valueB: "g"}, {valueB: "b"}, {valueB: "h"}, {valueB: "j"}, {valueB: "k"}, {valueB: "l"}} +c := []C {{valueC: "o"}, {valueC: "q"}, {valueC: "e"}, {valueC: "x"}, {valueC: "c"}, {valueC: "v"}, {valueC: "b"}} + +s1 := pgo.ArrayUdiff(func (arr1 interface{}, arr2 interface{}) int { +if arr1.(TestUdiffComparing).ComparingValue() > arr2.(TestUdiffComparing).ComparingValue() { +return 1 +} else if arr1.(TestUdiffComparing).ComparingValue() < arr2.(TestUdiffComparing).ComparingValue() { +return -1 +} - fmt.Print(s1) // [{t}] +return 0 +}, a, b, c) +fmt.Print(s1) // [{t}] - a2 := []string {"a", "b", "c"} - b2 := []string {"a", "d", "g"} - c2 := []string {"b", "x", "y"} +a2 := []string {"a", "b", "c"} +b2 := []string {"a", "d", "g"} +c2 := []string {"b", "x", "y"} - s2 := pgo.ArrayUdiff(func (arr1 interface{}, arr2 interface{}) int { - if arr1.(string) > arr2.(string) { - return 1 - } else if arr1.(string) < arr2.(string) { - return -1 - } +s2 := pgo.ArrayUdiff(func (arr1 interface{}, arr2 interface{}) int { +if arr1.(string) > arr2.(string) { +return 1 +} else if arr1.(string) < arr2.(string) { +return -1 +} - return 0 - }, a2, b2, c2) +return 0 +}, a2, b2, c2) - fmt.Print(s2) // [c] +fmt.Print(s2) // [c] } ``` #### ArraySum + calculate the sum of values in an array + ```go pgo.ArraySum([]int{12, 54, 32, 12, 33}) // int: 143 ``` #### ArrayIntersect + computes the intersection of arrays + ```go pgo.ArrayIntersect([]int{12, 54, 32, 12, 33}, []int{3, 12, 54, 9}, []int{12, 33, 9}) // []int{12, 54, 33} @@ -349,51 +396,65 @@ pgo.ArrayIntersect([]string{"foo", "bar", "baz", "fizz", "bazz", "fizz", "fizz"} ``` #### Range + creates an int slice of min to max range + ```go pgo.Range(3, 9) // []int{3, 4, 5, 6, 7, 8, 9} // If a step value is given, it will be used as the increment between elements in the sequence. pgo.Range(-3, 7, 5) // []int{-3, 2, 7} ``` + +#### EqualSlices + +Compares two slices and returns true if they are equal, false otherwise (any type of slices support) + +```go +res, err := pgo.EqualSlices([]int{1, 2, 3}, []int{1, 2, 3}, true) // true + +res, err := pgo.EqualSlices([]string{"foo"}, []string{"bar"}, false) // false +``` + See more examples in *_test.go files. ### Collections #### Priority Queue + ```go - // Some items and their priorities. - items := map[string]int{ - "banana": 3, "apple": 2, "pear": 4, "peach": 1, "plum": 6, - } - - // Create a Priority queue, put the items in it, and - // establish the Priority queue (heap) invariants. - pq := make(pgo.PriorityQueue, len(items)) - i := 0 - for value, priority := range items { - pq[i] = &pgo.Item{ - Value: value, - Priority: priority, - Index: i, - } - i++ - } - pq.Init() - - // Insert a new item and then modify its Priority. - item := &pgo.Item{ - Value: "orange", - Priority: 1, - } - pq.Push(item) - pq.Update(item, item.Value, 5) - - item := pq.Pop().(*pgo.Item) // 06:plum - item := pq.Pop().(*pgo.Item) // 05:orange - item := pq.Pop().(*pgo.Item) // 04:pear - item := pq.Pop().(*pgo.Item) // 03:banana - // ... + // Some items and their priorities. +items := map[string]int{ +"banana": 3, "apple": 2, "pear": 4, "peach": 1, "plum": 6, +} + +// Create a Priority queue, put the items in it, and +// establish the Priority queue (heap) invariants. +pq := make(pgo.PriorityQueue, len(items)) +i := 0 +for value, priority := range items { +pq[i] = &pgo.Item{ +Value: value, +Priority: priority, +Index: i, +} +i++ +} +pq.Init() + +// Insert a new item and then modify its Priority. +item := &pgo.Item{ +Value: "orange", +Priority: 1, +} +pq.Push(item) +pq.Update(item, item.Value, 5) + +item := pq.Pop().(*pgo.Item) // 06:plum +item := pq.Pop().(*pgo.Item) // 05:orange +item := pq.Pop().(*pgo.Item) // 04:pear +item := pq.Pop().(*pgo.Item) // 03:banana +// ... ``` ### Network @@ -407,6 +468,7 @@ ip := pgo.Long2ip(2956665461) // "176.59.34.117" ``` #### GetMxrr + ```go isMx, mxs, _ := pgo.GetMxrr("google.com") // e.g.: true, n ``` @@ -414,6 +476,7 @@ isMx, mxs, _ := pgo.GetMxrr("google.com") // e.g.: true, n ### Math #### Rand + ```go rand := pgo.Rand(1, 100) ``` @@ -421,31 +484,41 @@ rand := pgo.Rand(1, 100) ### Crypto #### Md5 + ```go pgo.Md5("abc123") // e99a18c428cb38d5f260853678922e03 ``` + #### Sha1 + ```go pgo.Sha1("abc123") // 6367c48dd193d56ea7b0baad25b19455e529f5ee ``` + #### Sha2 + ```go pgo.Sha2("abc123") // 6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090 ``` + #### HashFile + ```go hex, err := pgo.HashFile("sha1", "example.txt") // 6367c48dd193d56ea7b0baad25b19455e529f5ee ``` + #### HashHmac + ```go hmac := HashHmac("foo bar baz", "secret", sha256.New) // 9efc4f86917b454deae37c869521f88dee79305303fa2283df0b480e3cc8104c ``` + #### IsValidMac + ```go IsValidMac("foo bar baz", hmac, "secret", sha256.New) // true/false ``` - Supporters gratitude: JetBrains logo \ No newline at end of file diff --git a/array.go b/array.go index 1787b1b..1104bb2 100644 --- a/array.go +++ b/array.go @@ -310,3 +310,29 @@ func Range(min, max int, step ...interface{}) []int { return slice } + +// EqualSlices compares two slices and returns true if they are equal, false otherwise +// in case of passing wrong (non-slice) arguments error will be returned +func EqualSlices(a, b interface{}) (bool, error) { + if reflect.TypeOf(a).Kind() != reflect.Slice || reflect.TypeOf(b).Kind() != reflect.Slice { + return false, fmt.Errorf("only slice arguments allowed") + } + + sa := reflect.ValueOf(a) + la := sa.Len() + + sb := reflect.ValueOf(b) + lb := sb.Len() + + if la != lb { + return false, nil + } + + for i := 0; i < la; i++ { + if sa.Index(i).Interface() != sb.Index(i).Interface() { + return false, nil + } + } + + return true, nil +} diff --git a/array_test.go b/array_test.go index 70dd448..cb11824 100644 --- a/array_test.go +++ b/array_test.go @@ -1,12 +1,13 @@ package pgo_test import ( - "github.com/arthurkushman/pgo" - "github.com/stretchr/testify/assert" "math" "reflect" "strings" "testing" + + "github.com/arthurkushman/pgo" + "github.com/stretchr/testify/assert" ) var testInArray = []struct { @@ -355,3 +356,36 @@ func TestRange(t *testing.T) { } } } + +var testEqual = []struct { + a interface{} + b interface{} + res bool +}{ + {[]int{1, 2, 3}, []int{1, 2, 3}, true}, + {[]int{1, 2, 3}, []int{1, 3, 2}, false}, + {[]int{1, 2, 3}, []int{}, false}, + {[]int{}, []int{}, true}, + {[]string{"foo"}, []string{"bar"}, false}, + {[]string{"foo"}, []string{"foo"}, true}, + {[]float64{123.33, 22}, []float64{123.33, 22}, true}, + {[]float64{123.33, 22}, []float64{123.33, 22.1111}, false}, + {[]bool{true, false}, []bool{true, false}, true}, + {[]bool{true, false}, []bool{false, false}, false}, + {[]byte{0, 123, 1}, []byte{0, 123, 1}, true}, + {[]byte{0, 123, 1}, []byte{0, 123, 133}, false}, +} + +func TestEqual(t *testing.T) { + for _, v := range testEqual { + res, err := pgo.EqualSlices(v.a, v.b) + assert.NoError(t, err) + assert.Equal(t, v.res, res) + } + + // check err non-slice type + res, err := pgo.EqualSlices([]int{}, 123) + assert.Error(t, err) + assert.Equal(t, err.Error(), "only slice arguments allowed") + assert.Equal(t, false, res) +}