├── LICENSE ├── README.md ├── contains.go ├── file.go ├── golang-gopher-utils.png ├── num_conversions.go ├── singleton.go ├── types.go ├── utils.go └── utils_test.go /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Lex Sheehan, LLC 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | 4 | 5 | This utility software package contains functions and objects to help you write better Golang code faster. 6 | 7 | ## Installation 8 | 9 | go get github.com/go-goodies/go_utils 10 | 11 | ### License 12 | This project is licensed under a Simplified BSD license. Please read the [LICENSE file](LICENSE). -------------------------------------------------------------------------------- /contains.go: -------------------------------------------------------------------------------- 1 | package go_utils 2 | 3 | // Check whether the expected (e) string is in the slice (s) of stings 4 | func StringSliceContains(e string, s []string) bool { 5 | for _, a := range s { if a == e { return true } } 6 | return false 7 | } 8 | 9 | // Check whether the expected (e) int is in the slice (s) of ints 10 | func IntSliceContains(e int, s []int) bool { 11 | for _, a := range s { if a == e { return true } } 12 | return false 13 | } 14 | 15 | // Check whether the expected (e) string is in the slice (s) of stings 16 | func Float64SliceContains(e float64, s []float64) bool { 17 | for _, a := range s { if a == e { return true } } 18 | return false 19 | } 20 | 21 | // ---------------------- 22 | // Custom Types 23 | // ---------------------- 24 | 25 | type Widget struct { 26 | Name string `json:"name,omitempty"` // the field is omitted from the object if its value is empty 27 | Count int64 `json:"count,omitempty"` // the field is omitted from the object if its value is empty 28 | } 29 | 30 | // Check whether the expected (e) widget is in the slice (s) of widgets 31 | func ContainsWidget(e *Widget, widgets []*Widget) bool { 32 | for _, d := range widgets { 33 | if d.Name == e.Name && 34 | d.Count == e.Count { 35 | return true 36 | } 37 | } 38 | return false 39 | } 40 | -------------------------------------------------------------------------------- /file.go: -------------------------------------------------------------------------------- 1 | package go_utils 2 | 3 | import "os" 4 | 5 | // FileExists returns true if the file exists 6 | func FileExists(file string) bool { 7 | if _, err := os.Stat(file); err != nil { 8 | return false 9 | } 10 | return true 11 | } 12 | -------------------------------------------------------------------------------- /golang-gopher-utils.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-goodies/go_utils/8080b1735a88ccb3a2bb26f32bad85315797ddf2/golang-gopher-utils.png -------------------------------------------------------------------------------- /num_conversions.go: -------------------------------------------------------------------------------- 1 | package go_utils 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | type Float64ConversionError struct { 8 | } 9 | 10 | func (e Float64ConversionError) Error() string { 11 | return "Conversion Error: Could not convert num to float64." 12 | } 13 | 14 | func ConvNumToFloat64(a interface{}) (float64, error) { 15 | switch t := a.(type) { 16 | case int: 17 | return float64(t), nil 18 | case uint: 19 | return float64(t), nil 20 | case int8: 21 | return float64(t), nil 22 | case int16: 23 | return float64(t), nil 24 | case int32: 25 | return float64(t), nil 26 | case int64: 27 | return float64(t), nil 28 | case uint8: 29 | return float64(t), nil 30 | case uint16: 31 | return float64(t), nil 32 | case uint32: 33 | return float64(t), nil 34 | case uint64: 35 | return float64(t), nil 36 | case float32: 37 | return float64(t), nil 38 | case float64: 39 | return t, nil 40 | } 41 | return 0, Float64ConversionError{} 42 | } 43 | 44 | 45 | type IntConversionError struct { 46 | } 47 | 48 | func (e IntConversionError) Error() string { 49 | return "Conversion Error: Could not convert num to int." 50 | } 51 | 52 | func ConvNumToInt(a interface{}) (int, error) { 53 | switch t := a.(type) { 54 | case int: 55 | return t, nil 56 | case uint: 57 | return int(t), nil 58 | case int8: 59 | return int(t), nil 60 | case int16: 61 | return int(t), nil 62 | case int32: 63 | return int(t), nil 64 | case int64: 65 | return int(t), nil 66 | case uint8: 67 | return int(t), nil 68 | case uint16: 69 | return int(t), nil 70 | case uint32: 71 | return int(t), nil 72 | case uint64: 73 | return int(t), nil 74 | case float32: 75 | return int(t), nil 76 | case float64: 77 | return int(t), nil 78 | } 79 | return 0, IntConversionError{} 80 | } 81 | 82 | type StringConversionError struct { 83 | } 84 | 85 | func (e StringConversionError) Error() string { 86 | return "Conversion Error: Could not convert sting to int." 87 | } 88 | 89 | func ConvStringToInt(a interface{}) (int, error) { 90 | switch t := a.(type) { 91 | case string: 92 | i, err := strconv.Atoi(t) 93 | if err != nil { 94 | return 0, StringConversionError{} 95 | } 96 | return i, nil 97 | } 98 | return 0, StringConversionError{} 99 | } 100 | -------------------------------------------------------------------------------- /singleton.go: -------------------------------------------------------------------------------- 1 | package go_utils 2 | 3 | type Obj map[string]interface{} 4 | 5 | type Singleton struct { 6 | Data Obj 7 | } 8 | 9 | var instance *Singleton = nil 10 | 11 | // NewSingleton is a singleton object which restricts object creation to only one instance. 12 | // You can use this when you want an application wide in-memory data store, e.g. to store 13 | // application configuration data. 14 | func NewSingleton() *Singleton { 15 | if instance == nil { 16 | instance = &Singleton{}; 17 | instance.Data = make(Obj) 18 | } 19 | return instance; 20 | } 21 | -------------------------------------------------------------------------------- /types.go: -------------------------------------------------------------------------------- 1 | package go_utils 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "reflect" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | //------------------------------------------------ 12 | // Type Conversions 13 | //------------------------------------------------ 14 | 15 | // ToInt64 converts the argument to a int64 16 | // throws panic if argument is non-numeric parameter 17 | func ToInt64(a interface{}) int64 { 18 | switch t := a.(type) { 19 | case string: 20 | if strings.Contains(t, ".") { 21 | fpNum, err := strconv.ParseFloat(t, 64) 22 | if err != nil { 23 | log.Println(StringConversionError{}) 24 | return 0 25 | } 26 | return int64(fpNum) 27 | } else { 28 | num, err := ConvStringToInt(a) 29 | if err != nil { 30 | panic(fmt.Sprintf("Error converting string! Got <%T> %#v", a, a)) 31 | } 32 | return int64(num) 33 | } 34 | } 35 | if IsInteger(a) { 36 | return reflect.ValueOf(a).Int() 37 | } else if IsUnsignedInteger(a) { 38 | return int64(reflect.ValueOf(a).Uint()) 39 | } else if IsFloat(a) { 40 | return int64(reflect.ValueOf(a).Float()) 41 | } else { 42 | panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a)) 43 | } 44 | } 45 | 46 | // ToFloat converts the argument to a float64 47 | // throws panic if argument is non-numeric parameter 48 | func ToFloat(a interface{}) float64 { 49 | if IsInteger(a) { 50 | return float64(reflect.ValueOf(a).Int()) 51 | } else if IsUnsignedInteger(a) { 52 | return float64(reflect.ValueOf(a).Uint()) 53 | } else if IsFloat(a) { 54 | return reflect.ValueOf(a).Float() 55 | } else { 56 | panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a)) 57 | } 58 | } 59 | 60 | // ToUnsignedInteger converts the argument to a uint64 61 | // throws panic if argument is non-numeric parameter 62 | func ToUnsignedInteger(a interface{}) uint64 { 63 | if IsInteger(a) { 64 | return uint64(reflect.ValueOf(a).Int()) 65 | } else if IsUnsignedInteger(a) { 66 | return reflect.ValueOf(a).Uint() 67 | } else if IsFloat(a) { 68 | return uint64(reflect.ValueOf(a).Float()) 69 | } else { 70 | panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a)) 71 | } 72 | } 73 | 74 | //------------------------------------------------ 75 | // Type Equality 76 | //------------------------------------------------ 77 | 78 | func IsArray(a interface{}) bool { 79 | if a == nil { 80 | return false 81 | } 82 | switch reflect.TypeOf(a).Kind() { 83 | case reflect.Array: 84 | return true 85 | default: 86 | return false 87 | } 88 | } 89 | 90 | func IsBool(a interface{}) bool { 91 | return reflect.TypeOf(a).Kind() == reflect.Bool 92 | } 93 | 94 | func IsChan(a interface{}) bool { 95 | if IsNil(a) { 96 | return false 97 | } 98 | return reflect.TypeOf(a).Kind() == reflect.Chan 99 | } 100 | 101 | func IsError(a interface{}) bool { 102 | _, ok := a.(error) 103 | return ok 104 | } 105 | 106 | func IsFloat(a interface{}) bool { 107 | kind := reflect.TypeOf(a).Kind() 108 | return kind >= reflect.Float32 && kind <= reflect.Float64 109 | } 110 | 111 | func IsInteger(a interface{}) bool { 112 | kind := reflect.TypeOf(a).Kind() 113 | return kind >= reflect.Int && kind <= reflect.Int64 114 | } 115 | 116 | func IsInt(a interface{}) bool { 117 | kind := reflect.TypeOf(a).Kind() 118 | return kind == reflect.Int 119 | } 120 | 121 | func IsUint(a interface{}) bool { 122 | kind := reflect.TypeOf(a).Kind() 123 | return kind == reflect.Uint 124 | } 125 | 126 | func IsMap(a interface{}) bool { 127 | if a == nil { 128 | return false 129 | } 130 | return reflect.TypeOf(a).Kind() == reflect.Map 131 | } 132 | 133 | func IsNil(a interface{}) bool { 134 | if a == nil { 135 | return true 136 | } 137 | switch reflect.TypeOf(a).Kind() { 138 | case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: 139 | return reflect.ValueOf(a).IsNil() 140 | } 141 | return false 142 | } 143 | 144 | func IsNumber(a interface{}) bool { 145 | if a == nil { 146 | return false 147 | } 148 | kind := reflect.TypeOf(a).Kind() 149 | return kind >= reflect.Int && kind <= reflect.Float64 150 | } 151 | 152 | func IsSlice(a interface{}) bool { 153 | if a == nil { 154 | return false 155 | } 156 | switch reflect.TypeOf(a).Kind() { 157 | case reflect.Slice: 158 | return true 159 | default: 160 | return false 161 | } 162 | } 163 | 164 | func IsString(a interface{}) bool { 165 | if a == nil { 166 | return false 167 | } 168 | return reflect.TypeOf(a).Kind() == reflect.String 169 | } 170 | 171 | func IsUnsignedInteger(a interface{}) bool { 172 | kind := reflect.TypeOf(a).Kind() 173 | return kind >= reflect.Uint && kind <= reflect.Uint64 174 | } 175 | 176 | //------------------------------------------------ 177 | // Type Helpers 178 | //------------------------------------------------ 179 | 180 | // LengthOf returns the number if items in argument 181 | func LengthOf(a interface{}) int { 182 | if a == nil { 183 | return 0 184 | } 185 | switch reflect.TypeOf(a).Kind() { 186 | case reflect.String, reflect.Slice, reflect.Map, reflect.Chan, reflect.Array: 187 | return reflect.ValueOf(a).Len() 188 | default: 189 | return 0 190 | } 191 | } 192 | 193 | // ToString converts the value to a string 194 | func ToString(a interface{}) string { 195 | ret := "" 196 | if strings.Index(TypeOf(a), "map[string]string") > -1 { 197 | // will return nicely formatted results for this type (map[string]string) of map only 198 | m := a.(map[string]string) 199 | for key, value := range m { 200 | ret = fmt.Sprintf("%s: %v, ", strings.TrimSpace(key), strings.TrimSpace(value)) 201 | } 202 | ret = strings.TrimSuffix(ret, ", ") 203 | 204 | } else { 205 | ret = fmt.Sprint(a) 206 | } 207 | return ret 208 | } 209 | 210 | // TypeOf returns the reflection Type of the value in the interface{}. 211 | // TypeOf(nil) returns nil. 212 | func TypeOf(a interface{}) string { 213 | return fmt.Sprintf("%v", reflect.TypeOf(a)) 214 | } 215 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package go_utils 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/binary" 6 | "errors" 7 | . "fmt" 8 | go_deepcopy "github.com/margnus1/go-deepcopy" 9 | gouuid "github.com/nu7hatch/gouuid" 10 | "net/http" 11 | "reflect" 12 | "strings" 13 | "time" 14 | ) 15 | 16 | const ( 17 | ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 18 | UPPER_A_ORD = 65 19 | UPPER_Z_ORD = 90 20 | LOWER_A_ORD = 97 21 | LOWER_Z_ORD = 122 22 | NOT_FOUND_INDEX = -1 23 | ) 24 | 25 | // Iif_string is and immediate if helper that takes a boolean expression 26 | // and returns a string, true_val if the expression is true else false_val 27 | func Iif_string(expr bool, true_val string, false_val string) string { 28 | return map[bool]string{true: true_val, false: false_val}[expr] 29 | } 30 | 31 | // Concat joins the strings in a slice, delimiting them with a comma, but it 32 | // allows you to pass the delimiter string to create a single string 33 | // Ex: data: []string{"A", "B", "C"}; Join(data) ==> "A,B,C" ; Join(data, "|") ==> "A|B|C" 34 | func Join(slice []string, args ...interface{}) string { 35 | delimiter := "," 36 | for _, arg := range args { 37 | switch t := arg.(type) { 38 | case string: 39 | delimiter = t 40 | default: 41 | panic(Sprintf("ERROR - Invalid argument (%v). Must be a string.", arg)) 42 | } 43 | } 44 | ret := "" 45 | for i, s := range slice { 46 | // append delimiter except at the very end 47 | ret += s + Iif_string((i < len(slice)-1), delimiter, "") 48 | } 49 | return ret 50 | } 51 | 52 | // Substr returns a portion (length characters) of string (s), beginning at a specified position (pos) 53 | func Substr(s string, pos, length int) string { 54 | runes := []rune(s) 55 | l := pos + length 56 | if l > len(runes) { 57 | l = len(runes) 58 | } 59 | return string(runes[pos:l]) 60 | } 61 | 62 | // PadRight pads a string (s) with with a specified string (optional parameter) for padLen characters 63 | // If no string argument is passed, then s will be padded, to the right, with a single space character 64 | func PadRight(s string, padLen int, args ...interface{}) string { 65 | padStr := " " 66 | for _, arg := range args { 67 | switch t := arg.(type) { 68 | case string: 69 | padStr = t 70 | default: 71 | panic("Unknown argument") 72 | } 73 | } 74 | return s + strings.Repeat(padStr, padLen-len(s)) 75 | } 76 | 77 | // PadLeft pads a string (s) with with a specified string (optional parameter) for padLen characters 78 | // If no string argument is passed, then s will be padded, to the left, with a single space character 79 | func PadLeft(s string, padLen int, args ...interface{}) string { 80 | padStr := " " 81 | for _, arg := range args { 82 | switch t := arg.(type) { 83 | case string: 84 | padStr = t 85 | default: 86 | panic("Unknown argument") 87 | } 88 | } 89 | return strings.Repeat(padStr, padLen-len(s)) + s 90 | } 91 | 92 | // reflect doesn't consider 0 or "" to be zero, so we double check those here 93 | // Can handle a struct field (only one level) 94 | func IsEmpty(args ...interface{}) bool { 95 | val := reflect.ValueOf(args[0]) 96 | valType := val.Kind() 97 | switch valType { 98 | case reflect.String: 99 | return val.String() == "" 100 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 101 | return val.Int() == 0 102 | case reflect.Float32, reflect.Float64: 103 | return val.Float() == 0 104 | case reflect.Interface, reflect.Slice, reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func: 105 | if val.IsNil() { 106 | return true 107 | } else if valType == reflect.Slice || valType == reflect.Map { 108 | return val.Len() == 0 109 | } 110 | case reflect.Struct: 111 | return IsEmptyStruct(args[0]) 112 | default: 113 | return false 114 | } 115 | return false 116 | } 117 | 118 | // Assumes the argument is a struct 119 | func IsEmptyStruct(args ...interface{}) bool { 120 | val := reflect.ValueOf(args[0]) 121 | valType := val.Kind() 122 | switch valType { 123 | case reflect.Struct: 124 | // verify that all of the struct's properties are empty 125 | fieldCount := val.NumField() 126 | for i := 0; i < fieldCount; i++ { 127 | field := val.Field(i) 128 | if field.IsValid() && !IsEmptyNonStruct(field) { 129 | return false 130 | } 131 | } 132 | return true 133 | default: 134 | return false 135 | } 136 | } 137 | 138 | // Assumes the argument is not a struct 139 | func IsEmptyNonStruct(args ...interface{}) bool { 140 | val := reflect.ValueOf(args[0]) 141 | valType := val.Kind() 142 | switch valType { 143 | case reflect.String: 144 | return val.String() == "" 145 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 146 | return val.Int() == 0 147 | case reflect.Float32, reflect.Float64: 148 | return val.Float() == 0 149 | case reflect.Interface, reflect.Slice, reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func: 150 | if val.IsNil() { 151 | return true 152 | } else if valType == reflect.Slice || valType == reflect.Map { 153 | return val.Len() == 0 154 | } 155 | default: 156 | return false 157 | } 158 | return false 159 | } 160 | 161 | // Repeat a character (typically used for simple formatting of output) 162 | func Dashes(repeatCount int, args ...interface{}) string { 163 | dashChar := "-" 164 | for _, arg := range args { 165 | switch t := arg.(type) { 166 | case string: 167 | dashChar = t 168 | default: 169 | panic("Unknown argument") 170 | } 171 | } 172 | return strings.Repeat(dashChar, repeatCount) 173 | } 174 | 175 | // A: 65 176 | // B: 66 177 | // . . . 178 | func PrintAlphabet() { 179 | var thisChar string 180 | for _, c := range ALPHABET { 181 | thisChar = Sprintf("%c", c) 182 | Printf("%s: %d\n", thisChar, c) 183 | } 184 | } 185 | 186 | // Find index of search string in target string, starting at startPos 187 | // Ex: domain := email[IndexOf("@", email, 0)+1:] 188 | func IndexOf(search string, target string, startPos int) int { 189 | if startPos < 0 { 190 | startPos = 0 191 | } 192 | if len(target) < startPos { 193 | return NOT_FOUND_INDEX 194 | } 195 | if IsEmpty(target) || IsEmpty(search) { 196 | return NOT_FOUND_INDEX 197 | } 198 | foundPos := strings.Index(target[startPos:len(target)], search) 199 | if foundPos == -1 { 200 | return NOT_FOUND_INDEX 201 | } 202 | return foundPos + startPos 203 | } 204 | 205 | // IndexOfGeneric returns the index of an element in any type of slice 206 | // ints := []int{1, 2, 3} 207 | // strings := []string{"A", "B", "C"} 208 | // IndexOfGeneric(len(ints), func(i int) bool { return ints[i] == 2 }) 209 | // IndexOfGeneric(len(strings), func(i int) bool { return strings[i] == "B" }) 210 | func IndexOfGeneric(maxLen int, findExpr func(i int) bool) int { 211 | for i := 0; i < maxLen; i++ { 212 | if findExpr(i) { 213 | return i 214 | } 215 | } 216 | return -1 217 | } 218 | 219 | // Printf("isLower(\"a\"): %v\n", isLower("a")) // isLower("a"): true 220 | // Printf("isLower(\"A\"): %v\n", isLower("A")) // isLower("A"): false 221 | func IsLower(letter string) bool { 222 | // var thisChar string 223 | var ret bool 224 | for _, c := range letter { 225 | // thisChar = Sprintf("%c", c) 226 | // Printf("%s: %d\n", thisChar, c) 227 | ret = (c >= LOWER_A_ORD && c <= LOWER_Z_ORD) 228 | } 229 | return ret 230 | } 231 | 232 | // Copy makes a recursive deep copy of obj and returns the result. 233 | // Wrap go_deepcopy.Copy (can later swap out implementation w/o breaking clients). 234 | func DeepCopy(obj interface{}) (r interface{}) { 235 | return go_deepcopy.Copy(obj) 236 | } 237 | 238 | func NewUuid() (uuid string, err error) { 239 | uuidPtr, err := gouuid.NewV4() 240 | if err != nil { 241 | err = errors.New("Could not generate UUID") 242 | } else { 243 | uuid = uuidPtr.String() 244 | } 245 | return 246 | } 247 | 248 | // ToCurrency converts the value to a dollar and cents string 249 | func ToCurrencyString(v interface{}) string { 250 | return Sprintf("%.2f", v) 251 | } 252 | 253 | // ToTS converts the value to a timestamp string (accepts both time.Time and *time.Time as argument) 254 | func ToTS(v interface{}) string { 255 | var t time.Time 256 | ret := "" 257 | if TypeOf(v) == "time.Time" { 258 | t = v.(time.Time) 259 | ret = t.Format("2006-01-02 15:04 MST") 260 | } else if TypeOf(v) == "*time.Time" { 261 | ret = Sprintf("%s", time.Time(t).Format("2006-01-02 15:04 MST")) 262 | } 263 | return ret 264 | } 265 | 266 | // Prevent special CSV characters ("," and ";") from splitting a column 267 | func CsvScrub(a interface{}) string { 268 | s := Sprint(a) 269 | commaPos := strings.Index(s, ",") 270 | semicolonPos := strings.Index(s, ";") 271 | if commaPos > -1 || semicolonPos > -1 { 272 | // comma or semicolon found 273 | s = Sprintf("\"%s\"", s) // surround with quotes per IETF RFC 2.6 guideline 274 | } 275 | return s 276 | } 277 | 278 | func Rand32() int32 { 279 | var n int32 280 | binary.Read(rand.Reader, binary.LittleEndian, &n) 281 | return n 282 | } 283 | 284 | // QueryString takes an http request object and returns its query string 285 | func QueryString(req *http.Request) string { 286 | queryParamMap := req.URL.Query() 287 | i := 0 288 | queryParamString := "" 289 | for key, value := range queryParamMap { 290 | if len(value) > 1 { 291 | for _, arrayValue := range value { 292 | if i == 0 { 293 | queryParamString += "?" 294 | } else { 295 | queryParamString += "&" 296 | } 297 | i += 1 298 | queryParamString += key + "=" + arrayValue 299 | } 300 | } else { 301 | if i == 0 { 302 | queryParamString += "?" 303 | } else { 304 | queryParamString += "&" 305 | } 306 | i += 1 307 | queryParamString += key + "=" + queryParamMap.Get(key) 308 | } 309 | } 310 | return queryParamString 311 | } 312 | -------------------------------------------------------------------------------- /utils_test.go: -------------------------------------------------------------------------------- 1 | package go_utils 2 | 3 | import ( 4 | "testing" 5 | "github.com/remogatto/prettytest" 6 | "time" 7 | "errors" 8 | ) 9 | 10 | type mySuite struct { 11 | prettytest.Suite 12 | } 13 | 14 | func TestRunner(t *testing.T) { 15 | prettytest.Run(t, new(mySuite)) 16 | } 17 | 18 | func (s *mySuite) TestIif() { 19 | s.Equal(Iif_string(true, "true", "false"), "true") 20 | } 21 | 22 | func (s *mySuite) TestJoin() { 23 | data := []string{"A", "B", "C"} 24 | s.Equal(Join(data), "A,B,C") 25 | s.Equal(Join(data, "|"), "A|B|C") 26 | } 27 | 28 | func (s *mySuite) TestSubstr() { 29 | data := "ABCD" 30 | s.Equal(Substr(data, 1, 2), "BC") 31 | } 32 | 33 | func (s *mySuite) TestPadRight() { 34 | data := "ABC" 35 | s.Equal(PadRight(data, 2), "ABC ") 36 | } 37 | 38 | func (s *mySuite) TestPadLeft() { 39 | data := "ABC" 40 | s.Equal(PadLeft(data, 3), " ABC")} 41 | 42 | type myType struct { 43 | name string 44 | } 45 | 46 | func (s *mySuite) TestTypeOf() { 47 | s.Equal(TypeOf("1"), "string") 48 | s.Equal(TypeOf(int(1)), "int") 49 | s.Equal(TypeOf(1), "int") 50 | s.Equal(TypeOf(uint8(1)), "uint8") 51 | s.Equal(TypeOf(float64(1)), "float64") 52 | s.Equal(TypeOf(1.0), "float64") 53 | s.Equal(TypeOf(time.Now()), "time.Time") 54 | 55 | t, _ := time.Parse("2006-01-02 15:04", "2011-01-19 22:15") 56 | s.Equal(TypeOf(t), "time.Time") 57 | 58 | mt := new(myType) 59 | mt.name = "alice" 60 | s.Equal(TypeOf(mt), "*go_utils.myType") 61 | } 62 | 63 | func (s *mySuite) TestToString() { 64 | s.Equal(ToString(1), "1") 65 | s.Equal(ToString(true), "true") 66 | 67 | // "2014-01-19 22:15:01 -0500" -> 2014-01-19 22:15:01 -0500 EST ... but 68 | // "2014-08-28 21:30:01 -0500" -> 2014-08-28 21:30:01 -0500 -0500 69 | t, _ := time.Parse("2006-01-02 15:04:05 -0700", "2014-08-28 21:30:01 -0500") 70 | s.Equal(TypeOf(t), "time.Time") 71 | s.Equal(ToString(t), "2014-08-28 21:30:01 -0500 -0500") 72 | } 73 | 74 | func (s *mySuite) TestTypes() { 75 | s.Equal(IsBool(true), true) 76 | s.Equal(IsBool(false), true) 77 | s.Equal(IsBool("true"), false) 78 | 79 | s.Equal(IsNumber(1), true) 80 | s.Equal(IsNumber(1.0), true) 81 | s.Equal(IsNumber("1.0"), false) 82 | s.Equal(IsNumber(ToInt64(1.0)), true) 83 | s.Equal(IsNumber(ToInt64("1")), true) 84 | s.Equal(IsNumber(ToInt64("1.0")), true) 85 | 86 | s.Equal(IsInteger(-1), true) 87 | s.Equal(IsInteger("1"), false) 88 | 89 | s.Equal(IsUnsignedInteger(uint(1)), true) 90 | s.Equal(IsUnsignedInteger(-1), false) 91 | s.Equal(IsInteger("1"), false) 92 | 93 | s.Equal(IsFloat(1.0), true) 94 | 95 | s.Equal(ToInt64("1"), int64(1)) 96 | 97 | s.Equal(ToUnsignedInteger(1), uint64(1)) 98 | 99 | s.Equal(ToFloat(1), float64(1.0)) 100 | 101 | s.Equal(IsError(errors.New("ERROR - List is empty")), true) 102 | 103 | m := make(map[string]string) 104 | m["1"] = "one" 105 | s.Equal(IsMap(m), true) 106 | 107 | var a [1]string 108 | a[0] = "Hello" 109 | s.Equal(IsArray(a), true) 110 | p := []int{2, 3, 5} 111 | s.Equal(IsSlice(p), true) 112 | 113 | s.Equal(IsString("1.0"), true) 114 | s.Equal(IsString(PadLeft("1.0", 2)), true) 115 | 116 | s.Equal(IsString(1.0), false) 117 | 118 | s.Equal(TypeOf(1.0), "float64") 119 | s.Equal(TypeOf("1.0"), "string") 120 | 121 | s.Equal(ToString(1), "1") 122 | 123 | s.Equal(LengthOf(p), 3) 124 | s.Equal(LengthOf("ABC"), 3) 125 | s.Equal(LengthOf(m), 1) 126 | 127 | s.Equal(IsNil(nil), true) 128 | s.Equal(IsEmpty(m["XXX"]), true) 129 | } 130 | 131 | func (s *mySuite) TestContains() { 132 | 133 | s.Equal(StringSliceContains("1", []string{"2", "3", "1"}), true) 134 | s.Equal(StringSliceContains("1", []string{"2", "3", "5"}), false) 135 | 136 | s.Equal(IntSliceContains(1, []int{2, 3, 1}), true) 137 | s.Equal(IntSliceContains(1, []int{2, 3, 5}), false) 138 | 139 | s.Equal(Float64SliceContains(1.0, []float64{2.0, 3.0, 1.0}), true) 140 | s.Equal(Float64SliceContains(1.0, []float64{2.0, 3.0, 5.0}), false) 141 | 142 | widgets := []*Widget{} 143 | widgets = append(widgets, &Widget{"A", 1}) 144 | widgets = append(widgets, &Widget{"B", 2}) 145 | widgets = append(widgets, &Widget{"C", 3}) 146 | 147 | widget := new(Widget) 148 | widget.Name = "B" 149 | widget.Count = 2 150 | s.Equal(ContainsWidget(widget, widgets), true) 151 | widget.Count = 9 152 | s.Equal(ContainsWidget(widget, widgets), false) 153 | } 154 | 155 | 156 | func (s *mySuite) TestSingleton() { 157 | var AppContext *Singleton 158 | AppContext = NewSingleton() 159 | AppContext.Data["username"] = "joesample" 160 | s.Equal(AppContext.Data["username"], "joesample") 161 | } 162 | 163 | func (s *mySuite) TestDashes() { 164 | s.Equal(Dashes(3, "-"), "---") 165 | s.Not(s.Equal(Dashes(30, "-"), "---")) 166 | } 167 | 168 | --------------------------------------------------------------------------------