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:
\ 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)
+}