├── .gitignore ├── .travis.yml ├── LICENCE ├── README.md ├── arr.go ├── errors.go ├── files.go ├── helpers_test.go ├── networking.go ├── numbers.go └── strings.go /.gitignore: -------------------------------------------------------------------------------- 1 | # IDEA Ignores # 2 | ################ 3 | *.iml 4 | *.ipr 5 | *.iws 6 | .idea/ 7 | out/ 8 | local.properties 9 | 10 | # Generic Android ignores # 11 | ########################### 12 | bin/ 13 | target 14 | gen/ 15 | 16 | # Built Application Files 17 | ########################### 18 | *.apk 19 | *.ap_ 20 | 21 | # Files for the dex VM 22 | ########################### 23 | *.dex 24 | 25 | # Compiled source # 26 | ################### 27 | *.com 28 | *.class 29 | *.dll 30 | *.exe 31 | *.o 32 | *.so 33 | 34 | # Packages # 35 | ############ 36 | *.7z 37 | *.dmg 38 | *.gz 39 | *.iso 40 | *.rar 41 | *.tar 42 | *.zip 43 | 44 | # Logs and databases # 45 | ###################### 46 | log/ 47 | *.log 48 | *.sql 49 | *.sqlite 50 | 51 | # OS generated files # 52 | ###################### 53 | .DS_Store 54 | .DS_Store? 55 | ehthumbs.db 56 | Icon? 57 | Thumbs.db 58 | 59 | # VCS # 60 | ####### 61 | .svn 62 | .svn/ 63 | CVS 64 | 65 | # XCode 5 # 66 | ########### 67 | *.xcuserstate 68 | *.pbxuser 69 | *.mode1v3 70 | *.mode2v3 71 | *.perspectivev3 72 | xcuserdata/ 73 | *.xccheckout 74 | *.moved-aside 75 | DerivedData 76 | !default.pbxuser 77 | !default.mode1v3 78 | !default.mode2v3 79 | !default.perspectivev3 80 | 81 | # Project Specific # 82 | #################### 83 | go-helpers.test -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: go 4 | 5 | go: 6 | - 1.4.2 7 | - 1.5 8 | 9 | script: 10 | - go test -v 11 | 12 | notifications: 13 | email: false 14 | 15 | branches: 16 | only: 17 | - master -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Emir Ozer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-helpers 2 | 3 | ######**Documentation** : [![GoDoc](https://godoc.org/github.com/emirozer/go-helpers?status.png)](https://godoc.org/github.com/emirozer/go-helpers) 4 | ######**CI Status** : ![travis](https://travis-ci.org/emirozer/go-helpers.svg?branch=master) 5 | A collection of helper functions about anything and everything. Contribute however you like :) 6 | -------------------------------------------------------------------------------- /arr.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | // StringInSlice verifies if a string is present in a slice 4 | func StringInSlice(str string, slice []string) bool { 5 | for _, item := range slice { 6 | if item == str { 7 | return true 8 | } 9 | } 10 | return false 11 | } 12 | 13 | // DiffSlices takes two integer slices and returns the diff between them 14 | // e.g. DiffSlices(X, Y) will return the elements that are only in X 15 | // If an integer is present in both slices but not the same number of time, 16 | // it will be reflected in the result 17 | func DiffSlices(X, Y []int) (ret []int) { 18 | m := make(map[int]int) 19 | 20 | for _, y := range Y { 21 | m[y]++ 22 | } 23 | 24 | for _, x := range X { 25 | if m[x] > 0 { 26 | m[x]-- 27 | continue 28 | } 29 | ret = append(ret, x) 30 | } 31 | 32 | return ret 33 | } 34 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | // Simple Panic on error 4 | func Check(e error) { 5 | if e != nil { 6 | panic(e) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /files.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "os" 5 | "crypto/md5" 6 | "io" 7 | "encoding/hex" 8 | ) 9 | 10 | // MD5 hash string of a provided valid file path 11 | // http://www.mrwaggel.be/post/generate-md5-hash-of-a-file/ 12 | func Md5Hash(path string) (string, error) { 13 | //Initialize variable returnMD5String now in case an error has to be returned 14 | var returnMD5String string 15 | 16 | //Open the passed argument and check for any error 17 | file, err := os.Open(path) 18 | if err != nil { 19 | return returnMD5String, err 20 | } 21 | 22 | //Tell the program to call the following function when the current function returns 23 | defer file.Close() 24 | 25 | //Open a new hash interface to write to 26 | hash := md5.New() 27 | 28 | //Copy the file in the hash interface and check for any error 29 | if _, err := io.Copy(hash, file); err != nil { 30 | return returnMD5String, err 31 | } 32 | 33 | //Get the 16 bytes hash 34 | hashInBytes := hash.Sum(nil)[:16] 35 | 36 | //Convert the bytes to a string 37 | returnMD5String = hex.EncodeToString(hashInBytes) 38 | 39 | return returnMD5String, err 40 | } 41 | 42 | 43 | // FileExists verifies if a filepath exists 44 | func FileExists(name string) bool { 45 | _, err := os.Stat(name) 46 | return !os.IsNotExist(err) 47 | } -------------------------------------------------------------------------------- /helpers_test.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "reflect" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | const ( 10 | separator = "%20" 11 | text = "A collection of helper functions about anything and everything" 12 | textSHA1 = "e181303567270f6ee37444a21e568039d88b2267" 13 | textWithSeparator = "A%20collection%20of%20helper%20functions%20about%20anything%20and%20everything" 14 | textReversed = "gnihtyreve dna gnihtyna tuoba snoitcnuf repleh fo noitcelloc A" 15 | uniqueWord = "abcdef ghijklmn" 16 | notUniqueWord = "abcdef ghijkklmn" 17 | lowerWordInput = "galatasaray" 18 | upperWordOutput = "Galatasaray" 19 | lowerWordsInput = "lorem ipsum dolor sit amet." 20 | upperWordsOutput = "Lorem Ipsum Dolor Sit Amet." 21 | ) 22 | 23 | var ( 24 | sliceIntX = []int{46, 77, 89, 43, 3, 33, 0, 10, 95} 25 | sliceIntY = []int{5, 93, 54, 10, 48, 66, 97, 95, 46, 11, 8, 56, 72} 26 | sliceIntDiffX = []int{77, 89, 43, 3, 33, 0} 27 | sliceIntDiffY = []int{5, 93, 54, 48, 66, 97, 11, 8, 56, 72} 28 | duplicateIntsS = []int{1, 1, 2, 2, 3, 3} 29 | nonDup = []int{1, 2, 3} 30 | ) 31 | 32 | // --- --- --- Tests 33 | 34 | // Tests for the AllUniqueWord function 35 | func Test_AllUniqueWord(t *testing.T) { 36 | // Should return true 37 | if result := AllUniqueWord(uniqueWord); !result { 38 | t.Errorf("Expected result: true, got %t instead\n", result) 39 | } 40 | // Should return false 41 | if result := AllUniqueWord(notUniqueWord); result { 42 | t.Errorf("Expected result: false, got %t instead\n", result) 43 | } 44 | } 45 | 46 | // Tests for the ReverseStr function 47 | func Test_ReverseStr(t *testing.T) { 48 | if result := ReverseStr(text); result != textReversed { 49 | t.Errorf("Expected result: %q, got %q instead\n", textReversed, result) 50 | } 51 | } 52 | 53 | // Tests for the StrPermutation function 54 | func Test_StrPermutation(t *testing.T) { 55 | // Should return true 56 | if result := StrPermutation(text, text); !result { 57 | t.Errorf("Expected result: true, got %t instead\n", result) 58 | } 59 | // Should return false 60 | if result := StrPermutation(text, text+"some more text"); result { 61 | t.Errorf("Expected result: false, got %t instead\n", result) 62 | } 63 | } 64 | 65 | // Tests for the ReplaceSpacesWSymb function 66 | func Test_ReplaceSpacesWSymb(t *testing.T) { 67 | if result := ReplaceSpacesWSymb(text, separator); result != textWithSeparator { 68 | t.Errorf("Expected result: %q, got %q instead\n", textWithSeparator, result) 69 | } 70 | } 71 | 72 | // TODO 73 | // func Test_PseudoUUID(t *testing.T) {} 74 | 75 | func Test_RandomString(t *testing.T) { 76 | size := 50 77 | var result string 78 | if result = RandomString(size); len(result) != size { 79 | t.Errorf("Expected result size: %d, got %d instead (result: %q)\n", size, len(result), result) 80 | } 81 | if RandomString(size) == result { 82 | t.Error("The strings returned are not random, got two time the same one\n") 83 | } 84 | } 85 | 86 | func Test_RandInt(t *testing.T) { 87 | result := RandInt(10, 30) 88 | 89 | if result < 10 || result > 30 { 90 | t.Error("The generated integer is out of min, max bounds") 91 | } 92 | 93 | } 94 | 95 | // Tests for the DiffSlices function 96 | func Test_DiffSlices(t *testing.T) { 97 | result := DiffSlices(sliceIntX, sliceIntY) 98 | if len(sliceIntDiffX) != len(result) { 99 | t.Logf("Result size (%d) is different from the expected result size (%d)\n", len(sliceIntDiffX), len(result)) 100 | t.FailNow() 101 | } 102 | for i, value := range result { 103 | if value != sliceIntDiffX[i] { 104 | t.Logf("Expected result at index %d: \"%d\", got \"%d\" instead\n", i, sliceIntDiffX[i], value) 105 | t.FailNow() 106 | } 107 | } 108 | result = DiffSlices(sliceIntY, sliceIntX) 109 | if len(sliceIntDiffY) != len(result) { 110 | t.Logf("Result size (%d) is different from the expected result size (%d)\n", len(sliceIntDiffY), len(result)) 111 | t.FailNow() 112 | } 113 | for i, value := range result { 114 | if value != sliceIntDiffY[i] { 115 | t.Logf("Expected result at index %d: \"%d\", got \"%d\" instead\n", i, sliceIntDiffY[i], value) 116 | t.FailNow() 117 | } 118 | } 119 | } 120 | 121 | // Tests for the SHA1hash function 122 | func Test_SHA1hash(t *testing.T) { 123 | if result := SHA1hash(text); result != textSHA1 { 124 | t.Errorf("Expected result: %q, got %q instead\n", textSHA1, result) 125 | } 126 | } 127 | 128 | // Tests for the FileExists function 129 | func Test_FileExists(t *testing.T) { 130 | if found := FileExists("./files.go"); !found { 131 | t.Errorf("Expected result: true, got %t instead\n", found) 132 | } 133 | if found := FileExists("./non_existent_file.go"); found { 134 | t.Errorf("Expected result: true, got %t instead\n", found) 135 | } 136 | } 137 | 138 | // Tests for the StringInSlice function 139 | func Test_StringInSlice(t *testing.T) { 140 | slice := strings.Split(text, " ") 141 | in := "helper" 142 | notIn := "potato" 143 | 144 | // Should return true 145 | if result := StringInSlice(in, slice); !result { 146 | t.Errorf("Expected result: true, got %t instead\n", result) 147 | } 148 | 149 | // Should return false 150 | if result := StringInSlice(notIn, slice); result { 151 | t.Errorf("Expected result: false, got %t instead\n", result) 152 | } 153 | } 154 | 155 | // Tests for the UpperCaseFirst function 156 | func Test_UpperCaseFirst(t *testing.T) { 157 | if result := UpperCaseFirst(lowerWordInput); result != upperWordOutput { 158 | t.Errorf("Expected result: %q, got %q instead\n", upperWordOutput, result) 159 | } 160 | } 161 | 162 | // Tests for the UpperCaseWords function 163 | func Test_UpperCaseWords(t *testing.T) { 164 | if result := UpperCaseWords(lowerWordsInput); result != upperWordsOutput { 165 | t.Errorf("Expected result: %q, got %q instead\n", upperWordsOutput, result) 166 | } 167 | } 168 | 169 | func Test_RemoveDuplicatesFromIntSlice(t *testing.T) { 170 | if result := RemoveDuplicatesFromIntSlice(duplicateIntsS); reflect.DeepEqual(result, nonDup) == false { 171 | t.Errorf("Cannot find expected result, %q , %q", result, nonDup) 172 | } 173 | } 174 | 175 | // --- --- --- Benchmarks 176 | 177 | // Benchmark for the ReverseStr function 178 | func Benchmark_ReverseStr(b *testing.B) { 179 | str := "this is the string to reverse" 180 | for n := 0; n < b.N; n++ { 181 | ReverseStr(str) 182 | } 183 | b.StopTimer() 184 | } 185 | 186 | // Benchmark for the AllUniqueWord function 187 | func Benchmark_AllUniqueWord(b *testing.B) { 188 | str := "this is the string to test" 189 | for n := 0; n < b.N; n++ { 190 | AllUniqueWord(str) 191 | } 192 | b.StopTimer() 193 | } 194 | 195 | // Benchmark for the StringInSlice function 196 | func Benchmark_StringInSlice(b *testing.B) { 197 | slice := strings.Split(text, " ") 198 | str := "potato" 199 | for n := 0; n < b.N; n++ { 200 | StringInSlice(str, slice) 201 | } 202 | b.StopTimer() 203 | } 204 | 205 | // Benchmark for the SHA1hash function 206 | func Benchmark_SHA1hash(b *testing.B) { 207 | for n := 0; n < b.N; n++ { 208 | SHA1hash(text) 209 | } 210 | b.StopTimer() 211 | } 212 | 213 | // Benchmark for the DiffSlices function 214 | func Benchmark_DiffSlices(b *testing.B) { 215 | for n := 0; n < b.N; n++ { 216 | DiffSlices(sliceIntX, sliceIntY) 217 | } 218 | b.StopTimer() 219 | } 220 | 221 | // Benchmark for the ReplaceSpacesWSymb function 222 | func Benchmark_ReplaceSpacesWSymb(b *testing.B) { 223 | for n := 0; n < b.N; n++ { 224 | ReplaceSpacesWSymb(text, separator) 225 | } 226 | b.StopTimer() 227 | } 228 | 229 | // Benchmark for the StrPermutation function 230 | func Benchmark_StrPermutation(b *testing.B) { 231 | for n := 0; n < b.N; n++ { 232 | StrPermutation(text, text) 233 | } 234 | b.StopTimer() 235 | } 236 | 237 | // Benchmark for the StrPermutation function 238 | func Benchmark_RandomString(b *testing.B) { 239 | for n := 0; n < b.N; n++ { 240 | RandomString(50) 241 | } 242 | b.StopTimer() 243 | } 244 | 245 | // Benchmark for the UpperCaseFirst function 246 | func Benchmark_UpperCaseFirst(b *testing.B) { 247 | for n := 0; n < b.N; n++ { 248 | UpperCaseFirst(lowerWordInput) 249 | } 250 | b.StopTimer() 251 | } 252 | 253 | // Benchmark for the UpperCaseFirst function 254 | func Benchmark_UpperCaseWords(b *testing.B) { 255 | for n := 0; n < b.N; n++ { 256 | UpperCaseFirst(lowerWordsInput) 257 | } 258 | b.StopTimer() 259 | } 260 | 261 | // ensuring MD5 hash doesn't throw an error, otherwise we can assume it works. 262 | func Test_Md5Hash(t *testing.T) { 263 | _, err := Md5Hash("./files.go"); 264 | if err != nil { 265 | t.Errorf("File MD5 hash test failed") 266 | } 267 | } 268 | 269 | // Test FirstNChars 270 | func Test_firstNChars(t *testing.T) { 271 | if FirstNCharacters("Helllllooo World!!!!!!!", 3) != "Hel" { 272 | t.Errorf("First N chars fail") 273 | } 274 | } 275 | 276 | // Test LastNChars 277 | func Test_lastNChars(t *testing.T) { 278 | if LastNCharacters("Helllllooo World!!!!!!!", 3) != "!!!" { 279 | t.Errorf("Last N chars fail") 280 | } 281 | } -------------------------------------------------------------------------------- /networking.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "os" 5 | "fmt" 6 | "net" 7 | ) 8 | 9 | // GetLocalIpv4 returns a string of the host machine local ipv4 10 | func GetLocalIpv4() string { 11 | host, _ := os.Hostname() 12 | addrs, _ := net.LookupIP(host) 13 | for _, addr := range addrs { 14 | if ipv4 := addr.To4(); ipv4 != nil { 15 | return fmt.Sprintf("%s", ipv4) 16 | } 17 | } 18 | return "localhost" 19 | } 20 | -------------------------------------------------------------------------------- /numbers.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | rnd "math/rand" 5 | "time" 6 | ) 7 | 8 | // RandInt returns a random integer between the min and max you set 9 | func RandInt(min int, max int) int { 10 | rnd.Seed(time.Now().UnixNano()) 11 | return min + rnd.Intn(max-min) 12 | } 13 | -------------------------------------------------------------------------------- /strings.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/sha1" 6 | "encoding/hex" 7 | "fmt" 8 | rnd "math/rand" 9 | "reflect" 10 | "regexp" 11 | "strings" 12 | "time" 13 | "unicode" 14 | ) 15 | 16 | // AllUniqueWord will return a bool value based on 17 | // the string containing only unique characters or not. 18 | func AllUniqueWord(str string) bool { 19 | result := make(map[rune]int) 20 | for _, v := range str { 21 | result[v]++ 22 | } 23 | for _, v := range result { 24 | if v > 1 { 25 | return false 26 | } 27 | } 28 | return true 29 | } 30 | 31 | // ReverseStr returns the string reversed rune-wise left to right 32 | // Source: https://github.com/golang/example/tree/master/stringutil 33 | func ReverseStr(s string) (result string) { 34 | r := []rune(s) 35 | for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { 36 | r[i], r[j] = r[j], r[i] 37 | } 38 | return string(r) 39 | } 40 | 41 | // StrPermutation checks if two strings have the same characters in the same amount 42 | func StrPermutation(a string, b string) bool { 43 | ma := make(map[rune]int) 44 | mb := make(map[rune]int) 45 | 46 | for _, v := range a { 47 | ma[v]++ 48 | } 49 | for _, v := range b { 50 | mb[v]++ 51 | } 52 | return reflect.DeepEqual(ma, mb) 53 | } 54 | 55 | // ReplaceSpacesWSymb expects two strings, first arg being the string itself 56 | // Second argument is the symbol to replace spaces 57 | // e.g. s := "emir ozer" symb := "%20" / Result will be "emir%20ozer" 58 | func ReplaceSpacesWSymb(s string, symb string) (result string) { 59 | return strings.Join(strings.Fields(s), symb) 60 | } 61 | 62 | //PseudoUUID generates a uuid like string 63 | func PseudoUUID() (uuid string) { 64 | b := make([]byte, 16) 65 | _, err := rand.Read(b) 66 | if err != nil { 67 | fmt.Println("Error: ", err) 68 | return 69 | } 70 | 71 | uuid = fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) 72 | 73 | return 74 | } 75 | 76 | // RandomString returns a random string of size l 77 | // Source: https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang 78 | func RandomString(l int) string { 79 | const ( 80 | letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 81 | size = int64(len(letters)) 82 | ) 83 | rnd.Seed(time.Now().UnixNano()) 84 | bytes := make([]byte, l) 85 | for i := range bytes { 86 | bytes[i] = letters[rnd.Int63()%size] 87 | } 88 | return string(bytes) 89 | } 90 | 91 | 92 | // SHA1hash calculates a SHA1 given a string 93 | func SHA1hash(cad string) string { 94 | data := sha1.Sum([]byte(cad)) 95 | return hex.EncodeToString(data[:]) 96 | } 97 | 98 | // UpperCaseFirst changes a string's first character to uppercase 99 | func UpperCaseFirst(s string) string { 100 | phrase := []rune(s) 101 | phrase[0] = unicode.ToUpper(phrase[0]) 102 | return string(phrase) 103 | } 104 | 105 | // UpperCaseWords changes all words' first character to uppercase (Delimited by single space) 106 | func UpperCaseWords(s string) string { 107 | var stack []string 108 | r := regexp.MustCompile("[^\\s]+") 109 | words := r.FindAllString(s, -1) 110 | 111 | for index := range words { 112 | first := strings.ToUpper(string(words[index][0])) 113 | rest := words[index][1:] 114 | stack = append(stack, first+rest) 115 | } 116 | 117 | return strings.Join(stack, " ") 118 | } 119 | 120 | // RemoveDuplicatesFromIntSlice receives a slice of integers and iterates through them 121 | // eliminating duplicate items in the slice. 122 | func RemoveDuplicatesFromIntSlice(a []int) []int { 123 | result := []int{} 124 | seen := map[int]int{} 125 | for _, val := range a { 126 | if _, ok := seen[val]; !ok { 127 | result = append(result, val) 128 | seen[val] = val 129 | } 130 | } 131 | return result 132 | } 133 | 134 | // Will return the first N chars of provided string 135 | func LastNCharacters(s string, n int) string { 136 | return string(s[len(s)-n:]) 137 | } 138 | 139 | // Will return the last N chars of provided string 140 | func FirstNCharacters(s string, n int) string { 141 | return string(s[:n]) 142 | } --------------------------------------------------------------------------------