diff --git a/.travis.yml b/.travis.yml index 5c05fa0a4..d277b54d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ addons: - local before_install: -- pwd + - mysql -e 'CREATE DATABASE IF NOT EXISTS test;' install: - cat /etc/hosts diff --git a/g/encoding/gjson/gjson_api.go b/g/encoding/gjson/gjson_api.go index 29fb1c371..04854860a 100644 --- a/g/encoding/gjson/gjson_api.go +++ b/g/encoding/gjson/gjson_api.go @@ -10,6 +10,8 @@ import ( "fmt" "time" + "github.com/gogf/gf/g/util/gutil" + "github.com/gogf/gf/g/container/gvar" "github.com/gogf/gf/g/os/gtime" "github.com/gogf/gf/g/util/gconv" @@ -22,6 +24,13 @@ func (j *Json) Value() interface{} { return *(j.p) } +// IsNil checks whether the value pointed by is nil. +func (j *Json) IsNil() bool { + j.mu.RLock() + defer j.mu.RUnlock() + return j.p == nil || *(j.p) == nil +} + // Get returns value by specified . // It returns all values of current Json object, if is empty or not specified. // It returns nil if no value found by . @@ -67,11 +76,7 @@ func (j *Json) GetMap(pattern string, def ...interface{}) map[string]interface{} // GetJson gets the value by specified , // and converts it to a un-concurrent-safe Json object. func (j *Json) GetJson(pattern string, def ...interface{}) *Json { - result := j.Get(pattern, def...) - if result != nil { - return New(result, true) - } - return nil + return New(j.Get(pattern, def...), true) } // GetJsons gets the value by specified , @@ -257,6 +262,7 @@ func (j *Json) Append(pattern string, value interface{}) error { // GetToVar gets the value by specified , // and converts it to specified golang variable . // The should be a pointer type. +// Deprecated. func (j *Json) GetToVar(pattern string, pointer interface{}) error { r := j.Get(pattern) if r != nil { @@ -342,13 +348,15 @@ func (j *Json) ToStructsDeep(pointer interface{}) error { } // Dump prints current Json object with more manually readable. -func (j *Json) Dump() error { +func (j *Json) Dump() { j.mu.RLock() defer j.mu.RUnlock() - if b, err := j.ToJsonIndent(); err != nil { - return err - } else { - fmt.Println(string(b)) - } - return nil + gutil.Dump(*j.p) +} + +// Export returns as a string with more manually readable. +func (j *Json) Export() string { + j.mu.RLock() + defer j.mu.RUnlock() + return gutil.Export(*j.p) } diff --git a/g/encoding/gjson/gjson_z_unit_basic_test.go b/g/encoding/gjson/gjson_z_unit_basic_test.go index b65cdba36..8d13d1240 100644 --- a/g/encoding/gjson/gjson_z_unit_basic_test.go +++ b/g/encoding/gjson/gjson_z_unit_basic_test.go @@ -7,10 +7,11 @@ package gjson_test import ( + "testing" + "github.com/gogf/gf/g" "github.com/gogf/gf/g/encoding/gjson" "github.com/gogf/gf/g/test/gtest" - "testing" ) func Test_New(t *testing.T) { @@ -361,7 +362,7 @@ func Test_Convert2(t *testing.T) { err := j.ToStruct(&name) gtest.Assert(err, nil) gtest.Assert(name.Name, "gf") - err = j.Dump() + j.Dump() gtest.Assert(err, nil) j = gjson.New(`{"person":{"name":"gf"}}`) @@ -370,7 +371,7 @@ func Test_Convert2(t *testing.T) { gtest.Assert(name.Name, "gf") j = gjson.New(`{"name":"gf""}`) - err = j.Dump() + j.Dump() gtest.Assert(err, nil) j = gjson.New(`[1,2,3]`) @@ -459,3 +460,10 @@ func Test_Basic(t *testing.T) { }) } + +func Test_IsNil(t *testing.T) { + gtest.Case(t, func() { + j := gjson.New(nil) + gtest.Assert(j.IsNil(), true) + }) +} diff --git a/g/encoding/gparser/gparser_api.go b/g/encoding/gparser/gparser_api.go index 2b5261a09..9be9f3c9b 100644 --- a/g/encoding/gparser/gparser_api.go +++ b/g/encoding/gparser/gparser_api.go @@ -7,9 +7,10 @@ package gparser import ( + "time" + "github.com/gogf/gf/g/container/gvar" "github.com/gogf/gf/g/os/gtime" - "time" ) // Val returns the value. @@ -141,6 +142,7 @@ func (p *Parser) GetGTime(pattern string, format ...string) *gtime.Time { // GetToVar gets the value by specified , // and converts it to specified golang variable . // The should be a pointer type. +// Deprecated. func (p *Parser) GetToVar(pattern string, pointer interface{}) error { return p.json.GetToVar(pattern, pointer) } @@ -216,7 +218,23 @@ func (p *Parser) ToStruct(pointer interface{}) error { return p.json.ToStruct(pointer) } -// Dump prints current Json object with more manually readable. -func (p *Parser) Dump() error { - return p.json.Dump() +func (p *Parser) ToStructDeep(pointer interface{}) error { + return p.json.ToStructDeep(pointer) +} + +func (p *Parser) ToStructs(pointer interface{}) error { + return p.json.ToStructs(pointer) +} + +func (p *Parser) ToStructsDeep(pointer interface{}) error { + return p.json.ToStructsDeep(pointer) +} + +// Dump prints current Json object with more manually readable. +func (p *Parser) Dump() { + p.json.Dump() +} + +func (p *Parser) Export() string { + return p.json.Export() } diff --git a/g/frame/gins/gins_database_test.go b/g/frame/gins/gins_database_test.go index 9f850cf39..32f2fd512 100644 --- a/g/frame/gins/gins_database_test.go +++ b/g/frame/gins/gins_database_test.go @@ -7,7 +7,6 @@ package gins_test import ( - "fmt" "testing" "time" @@ -60,7 +59,7 @@ test = "v=2" time.Sleep(500 * time.Millisecond) gtest.Case(t, func() { - fmt.Println("gins Test_Database", gins.Config().Get("test")) + //fmt.Println("gins Test_Database", gins.Config().Get("test")) dbDefault := gins.Database() dbTest := gins.Database("test") diff --git a/g/internal/strutils/strutils.go b/g/internal/strutils/strutils.go new file mode 100644 index 000000000..9ac598f56 --- /dev/null +++ b/g/internal/strutils/strutils.go @@ -0,0 +1,60 @@ +// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +// Package strutils provides some string functions for internal usage. +package strutils + +import "strings" + +// IsLetterUpper tests whether the given byte b is in upper case. +func IsLetterUpper(b byte) bool { + if b >= byte('A') && b <= byte('Z') { + return true + } + return false +} + +// IsLetterLower tests whether the given byte b is in lower case. +func IsLetterLower(b byte) bool { + if b >= byte('a') && b <= byte('z') { + return true + } + return false +} + +// IsNumeric tests whether the given string s is numeric. +func IsNumeric(s string) bool { + length := len(s) + if length == 0 { + return false + } + for i := 0; i < len(s); i++ { + if s[i] < byte('0') || s[i] > byte('9') { + return false + } + } + return true +} + +// UcFirst returns a copy of the string s with the first letter mapped to its upper case. +func UcFirst(s string) string { + if len(s) == 0 { + return s + } + if IsLetterLower(s[0]) { + return string(s[0]-32) + s[1:] + } + return s +} + +// ReplaceByMap returns a copy of , +// which is replaced by a map in unordered way, case-sensitively. +func ReplaceByMap(origin string, replaces map[string]string) string { + for k, v := range replaces { + origin = strings.Replace(origin, k, v, -1) + } + return origin +} diff --git a/g/os/gtime/gtime_format.go b/g/os/gtime/gtime_format.go index 89915447d..d54edcfd4 100644 --- a/g/os/gtime/gtime_format.go +++ b/g/os/gtime/gtime_format.go @@ -8,10 +8,10 @@ package gtime import ( "bytes" - "github.com/gogf/gf/g/text/gregex" - "github.com/gogf/gf/g/text/gstr" "strconv" "strings" + + "github.com/gogf/gf/g/text/gregex" ) var ( @@ -110,9 +110,15 @@ func (t *Time) Format(format string) string { // 有几个转换的符号需要特殊处理 switch runes[i] { case 'j': - buffer.WriteString(gstr.ReplaceByArray(result, []string{"=j=0", "", "=j=", ""})) + for _, s := range []string{"=j=0", "=j="} { + result = strings.Replace(result, s, "", -1) + } + buffer.WriteString(result) case 'G': - buffer.WriteString(gstr.ReplaceByArray(result, []string{"=G=0", "", "=G=", ""})) + for _, s := range []string{"=G=0", "=G="} { + result = strings.Replace(result, s, "", -1) + } + buffer.WriteString(result) case 'u': buffer.WriteString(strings.Replace(result, "=u=.", "", -1)) case 'w': diff --git a/g/text/gstr/gstr.go b/g/text/gstr/gstr.go index 0a0cdf9ca..7098bc2b8 100644 --- a/g/text/gstr/gstr.go +++ b/g/text/gstr/gstr.go @@ -10,12 +10,17 @@ package gstr import ( "bytes" "fmt" - "github.com/gogf/gf/g/util/grand" "math" "strconv" "strings" "unicode" "unicode/utf8" + + "github.com/gogf/gf/g/internal/strutils" + + "github.com/gogf/gf/g/util/gconv" + + "github.com/gogf/gf/g/util/grand" ) // Replace returns a copy of the string @@ -93,10 +98,7 @@ func ReplaceIByArray(origin string, array []string) string { // ReplaceByMap returns a copy of , // which is replaced by a map in unordered way, case-sensitively. func ReplaceByMap(origin string, replaces map[string]string) string { - for k, v := range replaces { - origin = Replace(origin, k, v) - } - return origin + return strutils.ReplaceByMap(origin, replaces) } // ReplaceIByMap returns a copy of , @@ -120,13 +122,7 @@ func ToUpper(s string) string { // UcFirst returns a copy of the string s with the first letter mapped to its upper case. func UcFirst(s string) string { - if len(s) == 0 { - return s - } - if IsLetterLower(s[0]) { - return string(s[0]-32) + s[1:] - } - return s + return strutils.UcFirst(s) } // LcFirst returns a copy of the string s with the first letter mapped to its lower case. @@ -147,40 +143,25 @@ func UcWords(str string) string { // IsLetterLower tests whether the given byte b is in lower case. func IsLetterLower(b byte) bool { - if b >= byte('a') && b <= byte('z') { - return true - } - return false + return strutils.IsLetterLower(b) } // IsLetterUpper tests whether the given byte b is in upper case. func IsLetterUpper(b byte) bool { - if b >= byte('A') && b <= byte('Z') { - return true - } - return false + return strutils.IsLetterUpper(b) } // IsNumeric tests whether the given string s is numeric. func IsNumeric(s string) bool { - length := len(s) - if length == 0 { - return false - } - for i := 0; i < len(s); i++ { - if s[i] < byte('0') || s[i] > byte('9') { - return false - } - } - return true + return strutils.IsNumeric(s) } // SubStr returns a portion of string specified by the and parameters. func SubStr(str string, start int, length ...int) (substr string) { - // 将字符串的转换成[]rune + // Converting to []rune to support unicode. rs := []rune(str) lth := len(rs) - // 简单的越界判断 + // Simple border checks. if start < 0 { start = 0 } @@ -197,7 +178,6 @@ func SubStr(str string, start int, length ...int) (substr string) { if end > lth { end = lth } - // 返回子串 return string(rs[start:end]) } @@ -468,6 +448,14 @@ func Join(array []string, sep string) string { return strings.Join(array, sep) } +// JoinAny concatenates the elements of a to create a single string. The separator string +// sep is placed between elements in the resulting string. +// +// The parameter can be any type of slice. +func JoinAny(array interface{}, sep string) string { + return strings.Join(gconv.Strings(array), sep) +} + // Explode splits string by a string , to an array. // See http://php.net/manual/en/function.explode.php. func Explode(delimiter, str string) []string { diff --git a/g/util/gconv/gconv_map.go b/g/util/gconv/gconv_map.go index fcc3f691c..1d74da30a 100644 --- a/g/util/gconv/gconv_map.go +++ b/g/util/gconv/gconv_map.go @@ -11,7 +11,7 @@ import ( "strings" "github.com/gogf/gf/g/internal/empty" - "github.com/gogf/gf/g/text/gstr" + "github.com/gogf/gf/g/internal/strutils" ) // Map converts any variable to map[string]interface{}. @@ -116,7 +116,7 @@ func Map(value interface{}, tags ...string) map[string]interface{} { for i := 0; i < rv.NumField(); i++ { // Only convert the public attributes. fieldName := rt.Field(i).Name - if !gstr.IsLetterUpper(fieldName[0]) { + if !strutils.IsLetterUpper(fieldName[0]) { continue } name = "" diff --git a/g/util/gconv/gconv_slice.go b/g/util/gconv/gconv_slice.go index 2b7178bae..c76204889 100644 --- a/g/util/gconv/gconv_slice.go +++ b/g/util/gconv/gconv_slice.go @@ -11,7 +11,7 @@ import ( "fmt" "reflect" - "github.com/gogf/gf/g/text/gstr" + "github.com/gogf/gf/g/internal/strutils" ) // SliceInt is alias of Ints. @@ -357,7 +357,7 @@ func Interfaces(i interface{}) []interface{} { rt := rv.Type() for i := 0; i < rv.NumField(); i++ { // Only public attributes. - if !gstr.IsLetterUpper(rt.Field(i).Name[0]) { + if !strutils.IsLetterUpper(rt.Field(i).Name[0]) { continue } array = append(array, rv.Field(i).Interface()) @@ -447,6 +447,10 @@ func doStructs(params interface{}, pointer interface{}, deep bool, mapping ...ma } switch kind { case reflect.Slice, reflect.Array: + // If is an empty slice, no conversion. + if rv.Len() == 0 { + return nil + } array := reflect.MakeSlice(pointerRt.Elem(), rv.Len(), rv.Len()) itemType := array.Index(0).Type() for i := 0; i < rv.Len(); i++ { diff --git a/g/util/gconv/gconv_struct.go b/g/util/gconv/gconv_struct.go index e3a0f5137..0bcff3644 100644 --- a/g/util/gconv/gconv_struct.go +++ b/g/util/gconv/gconv_struct.go @@ -13,7 +13,7 @@ import ( "strings" "github.com/gogf/gf/g/internal/structs" - "github.com/gogf/gf/g/text/gstr" + "github.com/gogf/gf/g/internal/strutils" ) // Struct maps the params key-value pairs to the corresponding struct object's properties. @@ -92,7 +92,7 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin elemType := elem.Type() for i := 0; i < elem.NumField(); i++ { // Only do converting to public attributes. - if !gstr.IsLetterUpper(elemType.Field(i).Name[0]) { + if !strutils.IsLetterUpper(elemType.Field(i).Name[0]) { continue } attrMap[elemType.Field(i).Name] = struct{}{} @@ -100,8 +100,8 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin for mapK, mapV := range paramsMap { name := "" for _, checkName := range []string{ - gstr.UcFirst(mapK), - gstr.ReplaceByMap(mapK, map[string]string{ + strutils.UcFirst(mapK), + strutils.ReplaceByMap(mapK, map[string]string{ "_": "", "-": "", " ": "", @@ -118,7 +118,7 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin name = value break } - if strings.EqualFold(checkName, gstr.Replace(value, "_", "")) { + if strings.EqualFold(checkName, strings.Replace(value, "_", "", -1)) { name = value break } @@ -159,7 +159,7 @@ func StructDeep(params interface{}, pointer interface{}, mapping ...map[string]s rt := rv.Type() for i := 0; i < rv.NumField(); i++ { // Only do converting to public attributes. - if !gstr.IsLetterUpper(rt.Field(i).Name[0]) { + if !strutils.IsLetterUpper(rt.Field(i).Name[0]) { continue } trv := rv.Field(i) diff --git a/g/util/gconv/gconv_time.go b/g/util/gconv/gconv_time.go index 90282e195..5d12ac48c 100644 --- a/g/util/gconv/gconv_time.go +++ b/g/util/gconv/gconv_time.go @@ -7,9 +7,10 @@ package gconv import ( - "github.com/gogf/gf/g/os/gtime" - "github.com/gogf/gf/g/text/gstr" "time" + + "github.com/gogf/gf/g/internal/strutils" + "github.com/gogf/gf/g/os/gtime" ) // Time converts to time.Time. @@ -22,7 +23,7 @@ func Time(i interface{}, format ...string) time.Time { // If is numeric, then it converts as nanoseconds. func Duration(i interface{}) time.Duration { s := String(i) - if !gstr.IsNumeric(s) { + if !strutils.IsNumeric(s) { d, _ := time.ParseDuration(s) return d } @@ -43,7 +44,7 @@ func GTime(i interface{}, format ...string) *gtime.Time { t, _ := gtime.StrToTimeFormat(s, format[0]) return t } - if gstr.IsNumeric(s) { + if strutils.IsNumeric(s) { return gtime.NewFromTimeStamp(Int64(s)) } else { t, _ := gtime.StrToTime(s)