mirror of
https://gitee.com/johng/gf.git
synced 2024-12-01 03:38:35 +08:00
commit
4de6881c89
@ -11,11 +11,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
GoFrame is a modular, loose-coupled, production-ready and most-powerful application development framework of golang. Providing a series of core components and dozens of practical modules, such as: cache, logging, containers, timer, validator, database orm, etc. Supporting web server integrated with router, cookie, session, logger, configure, template, https, hooks, rewrites and many more features.
|
||||
-->
|
||||
|
||||
`GF(GoFrame)` is a modular, loose-coupled, production-ready and most-powerful application development framework of golang. Providing a series of core components and dozens of practical modules, such as: memcache, configure, validator, logging, array/queue/set/map containers, timer/timing tasks, file/memory lock, object pool, database ORM, etc. Supporting web server integrated with router, cookie, session, logger, template, https, hooks, rewrites and many more features.
|
||||
`GF(GoFrame)` is a modular, full-featured and production-ready application development framework of golang. Providing a series of core components and dozens of practical modules, such as: memcache, configure, validator, logging, array/queue/set/map containers, timer/timing tasks, file/memory lock, object pool, database ORM, etc. Supporting web server integrated with router, cookie, session, logger, template, https, hooks, rewrites and many more features.
|
||||
|
||||
|
||||
# Installation
|
||||
|
@ -22,14 +22,14 @@ type IntArray struct {
|
||||
}
|
||||
|
||||
// NewIntArray creates and returns an empty array.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntArray(unsafe...bool) *IntArray {
|
||||
return NewIntArraySize(0, 0, unsafe...)
|
||||
}
|
||||
|
||||
// NewIntArraySize create and returns an array with given size and cap.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntArraySize(size int, cap int, unsafe...bool) *IntArray {
|
||||
return &IntArray{
|
||||
@ -39,7 +39,7 @@ func NewIntArraySize(size int, cap int, unsafe...bool) *IntArray {
|
||||
}
|
||||
|
||||
// NewIntArrayFrom creates and returns an array with given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntArrayFrom(array []int, unsafe...bool) *IntArray {
|
||||
return &IntArray{
|
||||
@ -49,7 +49,7 @@ func NewIntArrayFrom(array []int, unsafe...bool) *IntArray {
|
||||
}
|
||||
|
||||
// NewIntArrayFromCopy creates and returns an array from a copy of given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntArrayFromCopy(array []int, unsafe...bool) *IntArray {
|
||||
newArray := make([]int, len(array))
|
||||
@ -110,7 +110,7 @@ func (a *IntArray) Sum() (sum int) {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The param <reverse> controls whether sort
|
||||
// The parameter <reverse> controls whether sort
|
||||
// in increasing order(default) or decreasing order
|
||||
func (a *IntArray) Sort(reverse...bool) *IntArray {
|
||||
a.mu.Lock()
|
||||
|
@ -22,7 +22,7 @@ type Array struct {
|
||||
}
|
||||
|
||||
// New creates and returns an empty array.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func New(unsafe...bool) *Array {
|
||||
return NewArraySize(0, 0, unsafe...)
|
||||
@ -34,7 +34,7 @@ func NewArray(unsafe...bool) *Array {
|
||||
}
|
||||
|
||||
// NewArraySize create and returns an array with given size and cap.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewArraySize(size int, cap int, unsafe...bool) *Array {
|
||||
return &Array{
|
||||
@ -54,7 +54,7 @@ func NewFromCopy(array []interface{}, unsafe...bool) *Array {
|
||||
}
|
||||
|
||||
// NewArrayFrom creates and returns an array with given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewArrayFrom(array []interface{}, unsafe...bool) *Array {
|
||||
return &Array{
|
||||
@ -64,7 +64,7 @@ func NewArrayFrom(array []interface{}, unsafe...bool) *Array {
|
||||
}
|
||||
|
||||
// NewArrayFromCopy creates and returns an array from a copy of given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewArrayFromCopy(array []interface{}, unsafe...bool) *Array {
|
||||
newArray := make([]interface{}, len(array))
|
||||
|
@ -23,14 +23,14 @@ type StringArray struct {
|
||||
}
|
||||
|
||||
// NewStringArray creates and returns an empty array.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStringArray(unsafe...bool) *StringArray {
|
||||
return NewStringArraySize(0, 0, unsafe...)
|
||||
}
|
||||
|
||||
// NewStringArraySize create and returns an array with given size and cap.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStringArraySize(size int, cap int, unsafe...bool) *StringArray {
|
||||
return &StringArray{
|
||||
@ -40,7 +40,7 @@ func NewStringArraySize(size int, cap int, unsafe...bool) *StringArray {
|
||||
}
|
||||
|
||||
// NewStringArrayFrom creates and returns an array with given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStringArrayFrom(array []string, unsafe...bool) *StringArray {
|
||||
return &StringArray {
|
||||
@ -50,7 +50,7 @@ func NewStringArrayFrom(array []string, unsafe...bool) *StringArray {
|
||||
}
|
||||
|
||||
// NewStringArrayFromCopy creates and returns an array from a copy of given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStringArrayFromCopy(array []string, unsafe...bool) *StringArray {
|
||||
newArray := make([]string, len(array))
|
||||
@ -111,7 +111,7 @@ func (a *StringArray) Sum() (sum int) {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The param <reverse> controls whether sort
|
||||
// The parameter <reverse> controls whether sort
|
||||
// in increasing order(default) or decreasing order
|
||||
func (a *StringArray) Sort(reverse...bool) *StringArray {
|
||||
a.mu.Lock()
|
||||
|
@ -26,14 +26,14 @@ type SortedIntArray struct {
|
||||
}
|
||||
|
||||
// NewSortedIntArray creates and returns an empty sorted array.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedIntArray(unsafe...bool) *SortedIntArray {
|
||||
return NewSortedIntArraySize(0, unsafe...)
|
||||
}
|
||||
|
||||
// NewSortedIntArraySize create and returns an sorted array with given size and cap.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedIntArraySize(cap int, unsafe...bool) *SortedIntArray {
|
||||
return &SortedIntArray {
|
||||
@ -53,7 +53,7 @@ func NewSortedIntArraySize(cap int, unsafe...bool) *SortedIntArray {
|
||||
}
|
||||
|
||||
// NewIntArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedIntArrayFrom(array []int, unsafe...bool) *SortedIntArray {
|
||||
a := NewSortedIntArraySize(0, unsafe...)
|
||||
@ -63,7 +63,7 @@ func NewSortedIntArrayFrom(array []int, unsafe...bool) *SortedIntArray {
|
||||
}
|
||||
|
||||
// NewSortedIntArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedIntArrayFromCopy(array []int, unsafe...bool) *SortedIntArray {
|
||||
newArray := make([]int, len(array))
|
||||
@ -81,7 +81,7 @@ func (a *SortedIntArray) SetArray(array []int) *SortedIntArray {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The param <reverse> controls whether sort
|
||||
// The parameter <reverse> controls whether sort
|
||||
// in increasing order(default) or decreasing order.
|
||||
func (a *SortedIntArray) Sort() *SortedIntArray {
|
||||
a.mu.Lock()
|
||||
|
@ -26,8 +26,8 @@ type SortedArray struct {
|
||||
}
|
||||
|
||||
// NewSortedArray creates and returns an empty sorted array.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety, which is false in default.
|
||||
// The param <comparator> used to compare values to sort in array,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety, which is false in default.
|
||||
// The parameter <comparator> used to compare values to sort in array,
|
||||
// if it returns value < 0, means v1 < v2;
|
||||
// if it returns value = 0, means v1 = v2;
|
||||
// if it returns value > 0, means v1 > v2;
|
||||
@ -36,7 +36,7 @@ func NewSortedArray(comparator func(v1, v2 interface{}) int, unsafe...bool) *Sor
|
||||
}
|
||||
|
||||
// NewSortedArraySize create and returns an sorted array with given size and cap.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedArraySize(cap int, comparator func(v1, v2 interface{}) int, unsafe...bool) *SortedArray {
|
||||
return &SortedArray{
|
||||
@ -48,7 +48,7 @@ func NewSortedArraySize(cap int, comparator func(v1, v2 interface{}) int, unsafe
|
||||
}
|
||||
|
||||
// NewSortedArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedArrayFrom(array []interface{}, comparator func(v1, v2 interface{}) int, unsafe...bool) *SortedArray {
|
||||
a := NewSortedArraySize(0, comparator, unsafe...)
|
||||
@ -60,7 +60,7 @@ func NewSortedArrayFrom(array []interface{}, comparator func(v1, v2 interface{})
|
||||
}
|
||||
|
||||
// NewSortedArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedArrayFromCopy(array []interface{}, comparator func(v1, v2 interface{}) int, unsafe...bool) *SortedArray {
|
||||
newArray := make([]interface{}, len(array))
|
||||
@ -80,7 +80,7 @@ func (a *SortedArray) SetArray(array []interface{}) *SortedArray {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The param <reverse> controls whether sort
|
||||
// The parameter <reverse> controls whether sort
|
||||
// in increasing order(default) or decreasing order
|
||||
func (a *SortedArray) Sort() *SortedArray {
|
||||
a.mu.Lock()
|
||||
|
@ -27,14 +27,14 @@ type SortedStringArray struct {
|
||||
}
|
||||
|
||||
// NewSortedStringArray creates and returns an empty sorted array.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedStringArray(unsafe...bool) *SortedStringArray {
|
||||
return NewSortedStringArraySize(0, unsafe...)
|
||||
}
|
||||
|
||||
// NewSortedStringArraySize create and returns an sorted array with given size and cap.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedStringArraySize(cap int, unsafe...bool) *SortedStringArray {
|
||||
return &SortedStringArray {
|
||||
@ -48,7 +48,7 @@ func NewSortedStringArraySize(cap int, unsafe...bool) *SortedStringArray {
|
||||
}
|
||||
|
||||
// NewSortedStringArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedStringArrayFrom(array []string, unsafe...bool) *SortedStringArray {
|
||||
a := NewSortedStringArraySize(0, unsafe...)
|
||||
@ -58,7 +58,7 @@ func NewSortedStringArrayFrom(array []string, unsafe...bool) *SortedStringArray
|
||||
}
|
||||
|
||||
// NewSortedStringArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedStringArrayFromCopy(array []string, unsafe...bool) *SortedStringArray {
|
||||
newArray := make([]string, len(array))
|
||||
@ -76,7 +76,7 @@ func (a *SortedStringArray) SetArray(array []string) *SortedStringArray {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The param <reverse> controls whether sort
|
||||
// The parameter <reverse> controls whether sort
|
||||
// in increasing order(default) or decreasing order.
|
||||
func (a *SortedStringArray) Sort() *SortedStringArray {
|
||||
a.mu.Lock()
|
||||
|
@ -12,7 +12,7 @@ type Map = AnyAnyMap
|
||||
type HashMap = AnyAnyMap
|
||||
|
||||
// New returns an empty hash map.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func New(unsafe ...bool) *Map {
|
||||
return NewAnyAnyMap(unsafe...)
|
||||
@ -21,14 +21,14 @@ func New(unsafe ...bool) *Map {
|
||||
// NewFrom returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewFrom(data map[interface{}]interface{}, unsafe...bool) *Map {
|
||||
return NewAnyAnyMapFrom(data, unsafe...)
|
||||
}
|
||||
|
||||
// NewHashMap returns an empty hash map.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewHashMap(unsafe ...bool) *Map {
|
||||
return NewAnyAnyMap(unsafe...)
|
||||
@ -37,7 +37,7 @@ func NewHashMap(unsafe ...bool) *Map {
|
||||
// NewHashMapFrom returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewHashMapFrom(data map[interface{}]interface{}, unsafe...bool) *Map {
|
||||
return NewAnyAnyMapFrom(data, unsafe...)
|
||||
|
@ -17,7 +17,7 @@ type AnyAnyMap struct {
|
||||
}
|
||||
|
||||
// NewAnyAnyMap returns an empty hash map.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewAnyAnyMap(unsafe ...bool) *AnyAnyMap {
|
||||
return &AnyAnyMap{
|
||||
|
@ -19,7 +19,7 @@ type IntAnyMap struct {
|
||||
}
|
||||
|
||||
// NewIntAnyMap returns an empty IntAnyMap object.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewIntAnyMap(unsafe...bool) *IntAnyMap {
|
||||
return &IntAnyMap{
|
||||
|
@ -16,7 +16,7 @@ type IntIntMap struct {
|
||||
}
|
||||
|
||||
// NewIntIntMap returns an empty IntIntMap object.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewIntIntMap(unsafe...bool) *IntIntMap {
|
||||
return &IntIntMap{
|
||||
|
@ -17,7 +17,7 @@ type IntStrMap struct {
|
||||
}
|
||||
|
||||
// NewIntStrMap returns an empty IntStrMap object.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewIntStrMap(unsafe ...bool) *IntStrMap {
|
||||
return &IntStrMap{
|
||||
|
@ -19,7 +19,7 @@ type StrAnyMap struct {
|
||||
}
|
||||
|
||||
// NewStrAnyMap returns an empty StrAnyMap object.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewStrAnyMap(unsafe ...bool) *StrAnyMap {
|
||||
return &StrAnyMap{
|
||||
|
@ -18,7 +18,7 @@ type StrIntMap struct {
|
||||
}
|
||||
|
||||
// NewStrIntMap returns an empty StrIntMap object.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewStrIntMap(unsafe ...bool) *StrIntMap {
|
||||
return &StrIntMap{
|
||||
|
@ -17,7 +17,7 @@ type StrStrMap struct {
|
||||
}
|
||||
|
||||
// NewStrStrMap returns an empty StrStrMap object.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewStrStrMap(unsafe...bool) *StrStrMap {
|
||||
return &StrStrMap{
|
||||
|
@ -25,7 +25,7 @@ type gListMapNode struct {
|
||||
|
||||
// NewListMap returns an empty link map.
|
||||
// ListMap is backed by a hash table to store values and doubly-linked list to store ordering.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewListMap(unsafe ...bool) *ListMap {
|
||||
return &ListMap{
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
type TreeMap = gtree.RedBlackTree
|
||||
|
||||
// NewTreeMap instantiates a tree map with the custom comparator.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewTreeMap(comparator func(v1, v2 interface{}) int, unsafe...bool) *TreeMap {
|
||||
return gtree.NewRedBlackTree(comparator, unsafe...)
|
||||
@ -23,7 +23,7 @@ func NewTreeMap(comparator func(v1, v2 interface{}) int, unsafe...bool) *TreeMap
|
||||
// NewTreeMapFrom instantiates a tree map with the custom comparator and <data> map.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewTreeMapFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *TreeMap {
|
||||
return gtree.NewRedBlackTreeFrom(comparator, data, unsafe...)
|
||||
|
92
g/container/gpool/gpool_z_unit_test.go
Normal file
92
g/container/gpool/gpool_z_unit_test.go
Normal file
@ -0,0 +1,92 @@
|
||||
package gpool_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/g/container/gpool"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
var nf gpool.NewFunc = func() (i interface{}, e error) {
|
||||
return "hello", nil
|
||||
}
|
||||
|
||||
var assertIndex int = 0
|
||||
var ef gpool.ExpireFunc = func(i interface{}) {
|
||||
assertIndex++
|
||||
gtest.Assert(i, assertIndex)
|
||||
}
|
||||
|
||||
func Test_Gpool(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
//
|
||||
//expire = 0
|
||||
p1 := gpool.New(0, nf)
|
||||
p1.Put(1)
|
||||
p1.Put(2)
|
||||
time.Sleep(1 * time.Second)
|
||||
//test won't be timeout
|
||||
v1, err1 := p1.Get()
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(v1, 1)
|
||||
//test clear
|
||||
p1.Clear()
|
||||
gtest.Assert(p1.Size(), 0)
|
||||
//test newFunc
|
||||
v1, err1 = p1.Get()
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(v1, "hello")
|
||||
//put data again
|
||||
p1.Put(3)
|
||||
p1.Put(4)
|
||||
v1, err1 = p1.Get()
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(v1, 3)
|
||||
//test close
|
||||
p1.Close()
|
||||
v1, err1 = p1.Get()
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(v1, "hello")
|
||||
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
//
|
||||
//expire > 0
|
||||
p2 := gpool.New(2000, nil, ef)
|
||||
for index := 0; index < 10; index++ {
|
||||
p2.Put(index)
|
||||
}
|
||||
gtest.Assert(p2.Size(), 10)
|
||||
v2, err2 := p2.Get()
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(v2, 0)
|
||||
//test timeout expireFunc
|
||||
time.Sleep(3 * time.Second)
|
||||
v2, err2 = p2.Get()
|
||||
gtest.Assert(err2, errors.New("pool is empty"))
|
||||
gtest.Assert(v2, nil)
|
||||
//test close expireFunc
|
||||
for index := 0; index < 10; index++ {
|
||||
p2.Put(index)
|
||||
}
|
||||
gtest.Assert(p2.Size(), 10)
|
||||
v2, err2 = p2.Get()
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(v2, 0)
|
||||
assertIndex = 0
|
||||
p2.Close()
|
||||
time.Sleep(3 * time.Second)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
//
|
||||
//expire < 0
|
||||
p3 := gpool.New(-1, nil)
|
||||
v3, err3 := p3.Get()
|
||||
gtest.Assert(err3, errors.New("pool is empty"))
|
||||
gtest.Assert(v3, nil)
|
||||
})
|
||||
}
|
@ -19,7 +19,7 @@ type Set struct {
|
||||
}
|
||||
|
||||
// New create and returns a new set, which contains un-repeated items.
|
||||
// The param <unsafe> used to specify whether using set in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using set in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func New(unsafe...bool) *Set {
|
||||
return NewSet(unsafe...)
|
||||
|
@ -19,7 +19,7 @@ type IntSet struct {
|
||||
}
|
||||
|
||||
// New create and returns a new set, which contains un-repeated items.
|
||||
// The param <unsafe> used to specify whether using set in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using set in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntSet(unsafe...bool) *IntSet {
|
||||
return &IntSet{
|
||||
|
@ -19,7 +19,7 @@ type StringSet struct {
|
||||
}
|
||||
|
||||
// New create and returns a new set, which contains un-repeated items.
|
||||
// The param <unsafe> used to specify whether using set in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using set in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStringSet(unsafe...bool) *StringSet {
|
||||
return &StringSet {
|
||||
|
@ -30,7 +30,7 @@ type AVLTreeNode struct {
|
||||
}
|
||||
|
||||
// NewAVLTree instantiates an AVL tree with the custom comparator.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewAVLTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *AVLTree {
|
||||
return &AVLTree{
|
||||
@ -40,7 +40,7 @@ func NewAVLTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *AVLTree
|
||||
}
|
||||
|
||||
// NewAVLTreeFrom instantiates an AVL tree with the custom comparator and data map.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewAVLTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *AVLTree {
|
||||
tree := NewAVLTree(comparator, unsafe...)
|
||||
|
@ -37,7 +37,7 @@ type BTreeEntry struct {
|
||||
}
|
||||
|
||||
// NewBTree instantiates a B-tree with <m> (maximum number of children) and a custom key comparator.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
// Note that the <m> must be greater or equal than 3, or else it panics.
|
||||
func NewBTree(m int, comparator func(v1, v2 interface{}) int, unsafe...bool) *BTree {
|
||||
@ -52,7 +52,7 @@ func NewBTree(m int, comparator func(v1, v2 interface{}) int, unsafe...bool) *BT
|
||||
}
|
||||
|
||||
// NewBTreeFrom instantiates a B-tree with <m> (maximum number of children), a custom key comparator and data map.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewBTreeFrom(m int, comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *BTree {
|
||||
tree := NewBTree(m, comparator, unsafe...)
|
||||
|
@ -37,7 +37,7 @@ type RedBlackTreeNode struct {
|
||||
}
|
||||
|
||||
// NewRedBlackTree instantiates a red-black tree with the custom comparator.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewRedBlackTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *RedBlackTree {
|
||||
return &RedBlackTree {
|
||||
@ -47,7 +47,7 @@ func NewRedBlackTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *Re
|
||||
}
|
||||
|
||||
// NewRedBlackTreeFrom instantiates a red-black tree with the custom comparator and <data> map.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewRedBlackTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *RedBlackTree {
|
||||
tree := NewRedBlackTree(comparator, unsafe...)
|
||||
|
@ -20,7 +20,7 @@ type Var struct {
|
||||
}
|
||||
|
||||
// New returns a new Var with given <value>.
|
||||
// The param <unsafe> used to specify whether using Var in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using Var in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func New(value interface{}, unsafe...bool) *Var {
|
||||
v := &Var{}
|
||||
@ -59,7 +59,7 @@ func (v *Var) Interface() interface{} {
|
||||
}
|
||||
|
||||
// Time converts and returns <v> as time.Time.
|
||||
// The param <format> specifies the format of the time string using gtime,
|
||||
// The parameter <format> specifies the format of the time string using gtime,
|
||||
// eg: Y-m-d H:i:s.
|
||||
func (v *Var) Time(format...string) time.Time {
|
||||
return gconv.Time(v.Val(), format...)
|
||||
@ -72,15 +72,15 @@ func (v *Var) Duration() time.Duration {
|
||||
}
|
||||
|
||||
// GTime converts and returns <v> as *gtime.Time.
|
||||
// The param <format> specifies the format of the time string using gtime,
|
||||
// The parameter <format> specifies the format of the time string using gtime,
|
||||
// eg: Y-m-d H:i:s.
|
||||
func (v *Var) GTime(format...string) *gtime.Time {
|
||||
return gconv.GTime(v.Val(), format...)
|
||||
}
|
||||
|
||||
// Struct maps value of <v> to <objPointer>.
|
||||
// The param <objPointer> should be a pointer to a struct instance.
|
||||
// The param <mapping> is used to specify the key-to-attribute mapping rules.
|
||||
// The parameter <objPointer> should be a pointer to a struct instance.
|
||||
// The parameter <mapping> is used to specify the key-to-attribute mapping rules.
|
||||
func (v *Var) Struct(pointer interface{}, mapping...map[string]string) error {
|
||||
return gconv.Struct(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ var (
|
||||
)
|
||||
|
||||
// New creates ORM DB object with global configurations.
|
||||
// The param <name> specifies the configuration group name,
|
||||
// The parameter <name> specifies the configuration group name,
|
||||
// which is DEFAULT_GROUP_NAME in default.
|
||||
func New(name ...string) (db DB, err error) {
|
||||
group := configs.defaultGroup
|
||||
@ -210,7 +210,7 @@ func New(name ...string) (db DB, err error) {
|
||||
}
|
||||
|
||||
// Instance returns an instance for DB operations.
|
||||
// The param <name> specifies the configuration group name,
|
||||
// The parameter <name> specifies the configuration group name,
|
||||
// which is DEFAULT_GROUP_NAME in default.
|
||||
func Instance(name ...string) (db DB, err error) {
|
||||
group := configs.defaultGroup
|
||||
|
@ -7,133 +7,203 @@
|
||||
package gredis_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/database/gredis"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"time"
|
||||
"github.com/gogf/gf/g/database/gredis"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
redis2 "github.com/gogf/gf/third/github.com/gomodule/redigo/redis"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
config = gredis.Config{
|
||||
Host : "127.0.0.1",
|
||||
Port : 6379,
|
||||
Db : 1,
|
||||
}
|
||||
config = gredis.Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: 6379,
|
||||
Db: 1,
|
||||
}
|
||||
)
|
||||
|
||||
func Test_NewClose(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
gtest.AssertNE(redis, nil)
|
||||
err := redis.Close()
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
gtest.AssertNE(redis, nil)
|
||||
err := redis.Close()
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Do(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
_, err := redis.Do("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
_, err := redis.Do("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
r, err := redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
r, err := redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
|
||||
_, err = redis.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
_, err = redis.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Send(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
err := redis.Send("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
err := redis.Send("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
r, err := redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
})
|
||||
r, err := redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Stats(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
redis.SetMaxIdle(2)
|
||||
redis.SetMaxActive(100)
|
||||
redis.SetIdleTimeout(500*time.Millisecond)
|
||||
redis.SetMaxConnLifetime(500*time.Millisecond)
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
redis.SetMaxIdle(2)
|
||||
redis.SetMaxActive(100)
|
||||
redis.SetIdleTimeout(500 * time.Millisecond)
|
||||
redis.SetMaxConnLifetime(500 * time.Millisecond)
|
||||
|
||||
array := make([]*gredis.Conn, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
array = append(array, redis.Conn())
|
||||
}
|
||||
stats := redis.Stats()
|
||||
gtest.Assert(stats.ActiveCount, 10)
|
||||
gtest.Assert(stats.IdleCount, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
array[i].Close()
|
||||
}
|
||||
stats = redis.Stats()
|
||||
gtest.Assert(stats.ActiveCount, 2)
|
||||
gtest.Assert(stats.IdleCount, 2)
|
||||
//time.Sleep(3000*time.Millisecond)
|
||||
//stats = redis.Stats()
|
||||
//fmt.Println(stats)
|
||||
//gtest.Assert(stats.ActiveCount, 0)
|
||||
//gtest.Assert(stats.IdleCount, 0)
|
||||
})
|
||||
array := make([]*gredis.Conn, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
array = append(array, redis.Conn())
|
||||
}
|
||||
stats := redis.Stats()
|
||||
gtest.Assert(stats.ActiveCount, 10)
|
||||
gtest.Assert(stats.IdleCount, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
array[i].Close()
|
||||
}
|
||||
stats = redis.Stats()
|
||||
gtest.Assert(stats.ActiveCount, 2)
|
||||
gtest.Assert(stats.IdleCount, 2)
|
||||
//time.Sleep(3000*time.Millisecond)
|
||||
//stats = redis.Stats()
|
||||
//fmt.Println(stats)
|
||||
//gtest.Assert(stats.ActiveCount, 0)
|
||||
//gtest.Assert(stats.IdleCount, 0)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Conn(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
conn := redis.Conn()
|
||||
defer conn.Close()
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
conn := redis.Conn()
|
||||
defer conn.Close()
|
||||
|
||||
r, err := conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
|
||||
r, err := conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
|
||||
_, err = conn.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
_, err = conn.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Instance(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
group := "my-test"
|
||||
gredis.SetConfig(config, group)
|
||||
defer gredis.RemoveConfig(group)
|
||||
redis := gredis.Instance(group)
|
||||
defer redis.Close()
|
||||
gtest.Case(t, func() {
|
||||
group := "my-test"
|
||||
gredis.SetConfig(config, group)
|
||||
defer gredis.RemoveConfig(group)
|
||||
redis := gredis.Instance(group)
|
||||
defer redis.Close()
|
||||
|
||||
conn := redis.Conn()
|
||||
defer conn.Close()
|
||||
conn := redis.Conn()
|
||||
defer conn.Close()
|
||||
|
||||
_, err := conn.Do("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
_, err := conn.Do("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
r, err := conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
r, err := conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
|
||||
_, err = conn.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
_, err = conn.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
config1 := gredis.Config{
|
||||
Host: "127.0.0.2",
|
||||
Port: 6379,
|
||||
Db: 1,
|
||||
}
|
||||
redis := gredis.New(config1)
|
||||
_, err := redis.Do("info")
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
config1 = gredis.Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: 6379,
|
||||
Db: 1,
|
||||
Pass: "666666",
|
||||
}
|
||||
redis = gredis.New(config1)
|
||||
_, err = redis.Do("info")
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
config1 = gredis.Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: 6379,
|
||||
Db: 100,
|
||||
}
|
||||
redis = gredis.New(config1)
|
||||
_, err = redis.Do("info")
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
redis = gredis.Instance("gf")
|
||||
gtest.Assert(redis == nil, true)
|
||||
gredis.ClearConfig()
|
||||
|
||||
redis = gredis.New(config)
|
||||
defer redis.Close()
|
||||
_, err = redis.DoVar("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
v, err := redis.DoVar("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v.String(), "v")
|
||||
|
||||
conn := redis.GetConn()
|
||||
_, err = conn.DoVar("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
//v, err = conn.ReceiveVar()
|
||||
//gtest.Assert(err, nil)
|
||||
//gtest.Assert(v.String(), "v")
|
||||
|
||||
psc := redis2.PubSubConn{Conn: conn}
|
||||
psc.Subscribe("gf")
|
||||
redis.DoVar("PUBLISH", "gf", "gf test")
|
||||
go func() {
|
||||
for {
|
||||
v, _ := conn.ReceiveVar()
|
||||
switch obj := v.Val().(type) {
|
||||
case redis2.Message:
|
||||
gtest.Assert(string(obj.Data), "gf test")
|
||||
case redis2.Subscription:
|
||||
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
time.Sleep(time.Second)
|
||||
})
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright 2018-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,
|
||||
@ -7,10 +7,15 @@
|
||||
// Package charset implements character-set conversion functionality.
|
||||
//
|
||||
// Supported Character Set:
|
||||
//
|
||||
// Chinese : GBK/GB18030/GB2312/Big5
|
||||
//
|
||||
// Japanese: EUCJP/ISO2022JP/ShiftJIS
|
||||
//
|
||||
// Korean : EUCKR
|
||||
//
|
||||
// Unicode : UTF-8/UTF-16/UTF-16BE/UTF-16LE
|
||||
//
|
||||
// Other : macintosh/IBM*/Windows*/ISO-*
|
||||
package gcharset
|
||||
|
||||
@ -18,6 +23,7 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/third/golang.org/x/text/encoding"
|
||||
"github.com/gogf/gf/third/golang.org/x/text/encoding/ianaindex"
|
||||
"github.com/gogf/gf/third/golang.org/x/text/transform"
|
||||
"io/ioutil"
|
||||
@ -33,21 +39,22 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Supported returns whether charset <charset> is supported.
|
||||
func Supported(charset string) bool {
|
||||
return getEncoding(charset) != nil
|
||||
}
|
||||
|
||||
// Convert converts <src> charset encoding from <srcCharset> to <dstCharset>,
|
||||
// and returns the converted string.
|
||||
// It returns <src> as <dst> if it fails converting.
|
||||
func Convert(dstCharset string, srcCharset string, src string) (dst string, err error) {
|
||||
if dstCharset == srcCharset {
|
||||
return src, nil
|
||||
}
|
||||
if charset, ok := charsetAlias[dstCharset]; ok {
|
||||
dstCharset = charset
|
||||
}
|
||||
if charset, ok := charsetAlias[srcCharset]; ok {
|
||||
srcCharset = charset
|
||||
}
|
||||
dst = src
|
||||
// Converting <src> to UTF-8.
|
||||
if srcCharset != "UTF-8" {
|
||||
if e, err := ianaindex.MIB.Encoding(srcCharset); err == nil && e != nil {
|
||||
if e := getEncoding(srcCharset); e != nil {
|
||||
tmp, err := ioutil.ReadAll(
|
||||
transform.NewReader(bytes.NewReader([]byte(src)), e.NewDecoder()),
|
||||
)
|
||||
@ -56,13 +63,12 @@ func Convert(dstCharset string, srcCharset string, src string) (dst string, err
|
||||
}
|
||||
src = string(tmp)
|
||||
} else {
|
||||
return src, errors.New(fmt.Sprintf("unsupport srcCharset: %s", srcCharset))
|
||||
return dst, errors.New(fmt.Sprintf("unsupport srcCharset: %s", srcCharset))
|
||||
}
|
||||
}
|
||||
dst = src
|
||||
// Do the converting from UTF-8 to <dstCharset>.
|
||||
if dstCharset != "UTF-8" {
|
||||
if e, err := ianaindex.MIB.Encoding(dstCharset); err == nil && e != nil {
|
||||
if e := getEncoding(dstCharset); e != nil {
|
||||
tmp, err := ioutil.ReadAll(
|
||||
transform.NewReader(bytes.NewReader([]byte(src)), e.NewEncoder()),
|
||||
)
|
||||
@ -71,8 +77,10 @@ func Convert(dstCharset string, srcCharset string, src string) (dst string, err
|
||||
}
|
||||
dst = string(tmp)
|
||||
} else {
|
||||
return src, errors.New(fmt.Sprintf("unsupport dstCharset: %s", dstCharset))
|
||||
return dst, errors.New(fmt.Sprintf("unsupport dstCharset: %s", dstCharset))
|
||||
}
|
||||
} else {
|
||||
dst = src
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
@ -89,3 +97,14 @@ func UTF8To(dstCharset string, src string) (dst string, err error) {
|
||||
return Convert(dstCharset, "UTF-8", src)
|
||||
}
|
||||
|
||||
// getEncoding returns the encoding.Encoding interface object for <charset>.
|
||||
// It returns nil if <charset> is not supported.
|
||||
func getEncoding(charset string) encoding.Encoding {
|
||||
if c, ok := charsetAlias[charset]; ok {
|
||||
charset = c
|
||||
}
|
||||
if e, err := ianaindex.MIB.Encoding(charset); err == nil && e != nil {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
@ -8,6 +8,7 @@ package gcharset_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/encoding/gcharset"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -134,3 +135,31 @@ func TestConvert(t *testing.T) {
|
||||
t.Errorf("unexpected value:%#v (expected %#v)", str, dst)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertErr(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
srcCharset := "big5"
|
||||
dstCharset := "gbk"
|
||||
src := "Hello \xb1`\xa5\u03b0\xea\xa6r\xbc\u0437\u01e6r\xc5\xe9\xaa\xed"
|
||||
|
||||
s1, e1 := gcharset.Convert(srcCharset, srcCharset, src)
|
||||
gtest.Assert(e1, nil)
|
||||
gtest.Assert(s1, src)
|
||||
|
||||
|
||||
s2, e2 := gcharset.Convert(dstCharset, "no this charset", src)
|
||||
gtest.AssertNE(e2, nil)
|
||||
gtest.Assert(s2, src)
|
||||
|
||||
s3, e3 := gcharset.Convert("no this charset", srcCharset, src)
|
||||
gtest.AssertNE(e3, nil)
|
||||
gtest.Assert(s3, src)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSupported(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gcharset.Supported("UTF-8"), true)
|
||||
gtest.Assert(gcharset.Supported("UTF-80"), false)
|
||||
})
|
||||
}
|
||||
|
@ -5,8 +5,6 @@
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gcompress provides kinds of compression algorithms for binary/bytes data.
|
||||
//
|
||||
// 数据压缩/解压.
|
||||
package gcompress
|
||||
|
||||
import (
|
||||
@ -16,19 +14,19 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// 进行zlib压缩
|
||||
// Zlib compresses <data> with zlib algorithm.
|
||||
func Zlib(data []byte) []byte {
|
||||
if data == nil || len(data) < 13 {
|
||||
return data
|
||||
}
|
||||
var in bytes.Buffer
|
||||
w := zlib.NewWriter(&in)
|
||||
w.Write(data)
|
||||
w.Close()
|
||||
w := zlib.NewWriter(&in)
|
||||
_, _ = w.Write(data)
|
||||
_ = w.Close()
|
||||
return in.Bytes()
|
||||
}
|
||||
|
||||
// 进行zlib解压缩
|
||||
// UnZlib decompresses <data> with zlib algorithm.
|
||||
func UnZlib(data []byte) []byte {
|
||||
if data == nil || len(data) < 13 {
|
||||
return data
|
||||
@ -39,32 +37,32 @@ func UnZlib(data []byte) []byte {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
io.Copy(&out, r)
|
||||
_, _ = io.Copy(&out, r)
|
||||
return out.Bytes()
|
||||
}
|
||||
|
||||
//做gzip解压缩
|
||||
func UnGzip(data []byte) []byte {
|
||||
var buf bytes.Buffer
|
||||
content := bytes.NewReader(data)
|
||||
zipdata, err := gzip.NewReader(content)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
io.Copy(&buf, zipdata)
|
||||
zipdata.Close()
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
//做gzip压缩
|
||||
// Gzip compresses <data> with gzip algorithm.
|
||||
func Gzip(data []byte) []byte {
|
||||
var buf bytes.Buffer
|
||||
zip := gzip.NewWriter(&buf)
|
||||
var buf bytes.Buffer
|
||||
zip := gzip.NewWriter(&buf)
|
||||
_, err := zip.Write(data)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
zip.Close()
|
||||
|
||||
_ = zip.Close()
|
||||
return buf.Bytes()
|
||||
}
|
||||
}
|
||||
|
||||
// UnGzip decompresses <data> with gzip algorithm.
|
||||
func UnGzip(data []byte) []byte {
|
||||
var buf bytes.Buffer
|
||||
content := bytes.NewReader(data)
|
||||
zipData, err := gzip.NewReader(content)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, _ = io.Copy(&buf, zipData)
|
||||
_ = zipData.Close()
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
// 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 gcompress_test
|
||||
|
||||
import (
|
||||
@ -18,6 +19,11 @@ func TestZlib(t *testing.T) {
|
||||
gtest.Assert(gcompress.Zlib([]byte(src)), dst)
|
||||
|
||||
gtest.Assert(gcompress.UnZlib(dst), []byte(src))
|
||||
|
||||
gtest.Assert(gcompress.Zlib(nil), nil)
|
||||
gtest.Assert(gcompress.UnZlib(nil), nil)
|
||||
|
||||
gtest.Assert(gcompress.UnZlib(dst[1:]), nil)
|
||||
})
|
||||
|
||||
}
|
||||
@ -36,7 +42,10 @@ func TestGzip(t *testing.T) {
|
||||
0x00, 0x00,
|
||||
}
|
||||
|
||||
gtest.Assert(gcompress.Gzip([]byte(src)), gzip)
|
||||
arr := []byte(src)
|
||||
gtest.Assert(gcompress.Gzip(arr), gzip)
|
||||
|
||||
gtest.Assert(gcompress.UnGzip(gzip), []byte(src))
|
||||
gtest.Assert(gcompress.UnGzip(gzip), arr)
|
||||
|
||||
gtest.Assert(gcompress.UnGzip(gzip[1:]), nil)
|
||||
}
|
||||
|
@ -5,15 +5,13 @@
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package ghash provides some popular hash functions(uint32/uint64) in go.
|
||||
//
|
||||
// 常用的hash函数.
|
||||
package ghash
|
||||
|
||||
|
||||
// BKDR Hash Function
|
||||
func BKDRHash(str []byte) uint32 {
|
||||
var seed uint32 = 131; // 31 131 1313 13131 131313 etc..
|
||||
var hash uint32 = 0;
|
||||
var seed uint32 = 131 // 31 131 1313 13131 131313 etc..
|
||||
var hash uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = hash * seed + uint32(str[i])
|
||||
}
|
||||
@ -22,8 +20,8 @@ func BKDRHash(str []byte) uint32 {
|
||||
|
||||
// BKDR Hash Function 64
|
||||
func BKDRHash64(str []byte) uint64 {
|
||||
var seed uint64 = 131; // 31 131 1313 13131 131313 etc..
|
||||
var hash uint64 = 0;
|
||||
var seed uint64 = 131 // 31 131 1313 13131 131313 etc..
|
||||
var hash uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = hash * seed + uint64(str[i])
|
||||
}
|
||||
@ -32,78 +30,78 @@ func BKDRHash64(str []byte) uint64 {
|
||||
|
||||
// SDBM Hash
|
||||
func SDBMHash(str []byte) uint32 {
|
||||
var hash uint32 = 0;
|
||||
var hash uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
// equivalent to: hash = 65599*hash + uint32(str[i]);
|
||||
hash = uint32(str[i]) + (hash << 6) + (hash << 16) - hash;
|
||||
hash = uint32(str[i]) + (hash << 6) + (hash << 16) - hash
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// SDBM Hash 64
|
||||
func SDBMHash64(str []byte) uint64 {
|
||||
var hash uint64 = 0;
|
||||
var hash uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
// equivalent to: hash = 65599*hash + uint32(str[i]);
|
||||
hash = uint64(str[i]) + (hash << 6) + (hash << 16) - hash;
|
||||
// equivalent to: hash = 65599*hash + uint32(str[i])
|
||||
hash = uint64(str[i]) + (hash << 6) + (hash << 16) - hash
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// RS Hash Function
|
||||
func RSHash(str []byte) uint32 {
|
||||
var b uint32 = 378551;
|
||||
var a uint32 = 63689;
|
||||
var hash uint32 = 0;
|
||||
var b uint32 = 378551
|
||||
var a uint32 = 63689
|
||||
var hash uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = hash * a + uint32(str[i]);
|
||||
a *= b;
|
||||
hash = hash * a + uint32(str[i])
|
||||
a *= b
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// RS Hash Function 64
|
||||
func RSHash64(str []byte) uint64 {
|
||||
var b uint64 = 378551;
|
||||
var a uint64 = 63689;
|
||||
var hash uint64 = 0;
|
||||
var b uint64 = 378551
|
||||
var a uint64 = 63689
|
||||
var hash uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = hash * a + uint64(str[i]);
|
||||
a *= b;
|
||||
hash = hash * a + uint64(str[i])
|
||||
a *= b;
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// JS Hash Function
|
||||
func JSHash(str []byte) uint32 {
|
||||
var hash uint32 = 1315423911;
|
||||
var hash uint32 = 1315423911
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash ^= ((hash << 5) + uint32(str[i]) + (hash >> 2));
|
||||
hash ^= (hash << 5) + uint32(str[i]) + (hash >> 2)
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// JS Hash Function 64
|
||||
func JSHash64(str []byte) uint64 {
|
||||
var hash uint64 = 1315423911;
|
||||
var hash uint64 = 1315423911
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash ^= ((hash << 5) + uint64(str[i]) + (hash >> 2));
|
||||
hash ^= (hash << 5) + uint64(str[i]) + (hash >> 2)
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// P. J. Weinberger Hash Function
|
||||
func PJWHash(str []byte) uint32 {
|
||||
var BitsInUnignedInt uint32 = (4 * 8);
|
||||
var ThreeQuarters uint32 = ((BitsInUnignedInt * 3) / 4);
|
||||
var OneEighth uint32 = (BitsInUnignedInt / 8);
|
||||
var HighBits uint32 = (0xFFFFFFFF) << (BitsInUnignedInt - OneEighth);
|
||||
var hash uint32 = 0;
|
||||
var test uint32 = 0;
|
||||
var BitsInUnignedInt uint32 = 4 * 8
|
||||
var ThreeQuarters uint32 = (BitsInUnignedInt * 3) / 4
|
||||
var OneEighth uint32 = BitsInUnignedInt / 8
|
||||
var HighBits uint32 = (0xFFFFFFFF) << (BitsInUnignedInt - OneEighth)
|
||||
var hash uint32 = 0
|
||||
var test uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = (hash << OneEighth) + uint32(str[i]);
|
||||
hash = (hash << OneEighth) + uint32(str[i])
|
||||
if test = hash & HighBits; test != 0 {
|
||||
hash = ((hash ^ (test >> ThreeQuarters)) & (^HighBits + 1));
|
||||
hash = (hash ^ (test >> ThreeQuarters)) & (^HighBits + 1)
|
||||
}
|
||||
}
|
||||
return hash
|
||||
@ -111,16 +109,16 @@ func PJWHash(str []byte) uint32 {
|
||||
|
||||
// P. J. Weinberger Hash Function 64
|
||||
func PJWHash64(str []byte) uint64 {
|
||||
var BitsInUnignedInt uint64 = (4 * 8);
|
||||
var ThreeQuarters uint64 = ((BitsInUnignedInt * 3) / 4);
|
||||
var OneEighth uint64 = (BitsInUnignedInt / 8);
|
||||
var HighBits uint64 = (0xFFFFFFFFFFFFFFFF) << (BitsInUnignedInt - OneEighth);
|
||||
var hash uint64 = 0;
|
||||
var test uint64 = 0;
|
||||
var BitsInUnignedInt uint64 = 4 * 8
|
||||
var ThreeQuarters uint64 = (BitsInUnignedInt * 3) / 4
|
||||
var OneEighth uint64 = BitsInUnignedInt / 8
|
||||
var HighBits uint64 = (0xFFFFFFFFFFFFFFFF) << (BitsInUnignedInt - OneEighth)
|
||||
var hash uint64 = 0
|
||||
var test uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = (hash << OneEighth) + uint64(str[i]);
|
||||
hash = (hash << OneEighth) + uint64(str[i])
|
||||
if test = hash & HighBits; test != 0 {
|
||||
hash = ((hash ^ (test >> ThreeQuarters)) & (^HighBits + 1));
|
||||
hash = (hash ^ (test >> ThreeQuarters)) & (^HighBits + 1)
|
||||
}
|
||||
}
|
||||
return hash
|
||||
@ -128,13 +126,13 @@ func PJWHash64(str []byte) uint64 {
|
||||
|
||||
// ELF Hash Function
|
||||
func ELFHash(str []byte) uint32 {
|
||||
var hash uint32 = 0;
|
||||
var x uint32 = 0;
|
||||
var hash uint32 = 0
|
||||
var x uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = (hash << 4) + uint32(str[i]);
|
||||
hash = (hash << 4) + uint32(str[i])
|
||||
if x = hash & 0xF0000000; x != 0 {
|
||||
hash ^= (x >> 24);
|
||||
hash &= ^x + 1;
|
||||
hash ^= x >> 24
|
||||
hash &= ^x + 1
|
||||
}
|
||||
}
|
||||
return hash
|
||||
@ -142,13 +140,13 @@ func ELFHash(str []byte) uint32 {
|
||||
|
||||
// ELF Hash Function 64
|
||||
func ELFHash64(str []byte) uint64 {
|
||||
var hash uint64 = 0;
|
||||
var x uint64 = 0;
|
||||
var hash uint64 = 0
|
||||
var x uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = (hash << 4) + uint64(str[i]);
|
||||
hash = (hash << 4) + uint64(str[i])
|
||||
if x = hash & 0xF000000000000000; x != 0 {
|
||||
hash ^= (x >> 24);
|
||||
hash &= ^x + 1;
|
||||
hash ^= x >> 24
|
||||
hash &= ^x + 1
|
||||
}
|
||||
}
|
||||
return hash
|
||||
@ -156,30 +154,30 @@ func ELFHash64(str []byte) uint64 {
|
||||
|
||||
// DJB Hash Function
|
||||
func DJBHash(str []byte) uint32 {
|
||||
var hash uint32 = 5381;
|
||||
var hash uint32 = 5381
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash += (hash << 5) + uint32(str[i]);
|
||||
hash += (hash << 5) + uint32(str[i])
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// DJB Hash Function 64
|
||||
func DJBHash64(str []byte) uint64 {
|
||||
var hash uint64 = 5381;
|
||||
var hash uint64 = 5381
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash += (hash << 5) + uint64(str[i]);
|
||||
hash += (hash << 5) + uint64(str[i])
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// AP Hash Function
|
||||
func APHash(str []byte) uint32 {
|
||||
var hash uint32 = 0;
|
||||
var hash uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
if ((i & 1) == 0) {
|
||||
hash ^= ((hash << 7) ^ uint32(str[i]) ^ (hash >> 3));
|
||||
if (i & 1) == 0 {
|
||||
hash ^= (hash << 7) ^ uint32(str[i]) ^ (hash >> 3)
|
||||
} else {
|
||||
hash ^= (^((hash << 11) ^ uint32(str[i]) ^ (hash >> 5)) + 1);
|
||||
hash ^= ^((hash << 11) ^ uint32(str[i]) ^ (hash >> 5)) + 1
|
||||
}
|
||||
}
|
||||
return hash
|
||||
@ -187,12 +185,12 @@ func APHash(str []byte) uint32 {
|
||||
|
||||
// AP Hash Function 64
|
||||
func APHash64(str []byte) uint64 {
|
||||
var hash uint64 = 0;
|
||||
var hash uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
if ((i & 1) == 0) {
|
||||
hash ^= ((hash << 7) ^ uint64(str[i]) ^ (hash >> 3));
|
||||
if (i & 1) == 0 {
|
||||
hash ^= (hash << 7) ^ uint64(str[i]) ^ (hash >> 3)
|
||||
} else {
|
||||
hash ^= (^((hash << 11) ^ uint64(str[i]) ^ (hash >> 5)) + 1);
|
||||
hash ^= ^((hash << 11) ^ uint64(str[i]) ^ (hash >> 5)) + 1
|
||||
}
|
||||
}
|
||||
return hash
|
||||
|
@ -108,7 +108,11 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error {
|
||||
if len((*pointer).([]interface{})) > valn {
|
||||
if removed && value == nil {
|
||||
// 删除数据元素
|
||||
j.setPointerWithValue(pparent, array[i - 1], append((*pointer).([]interface{})[ : valn], (*pointer).([]interface{})[valn + 1 : ]...))
|
||||
if pparent == nil {
|
||||
*pointer = append((*pointer).([]interface{})[ : valn], (*pointer).([]interface{})[valn + 1 : ]...)
|
||||
} else {
|
||||
j.setPointerWithValue(pparent, array[i - 1], append((*pointer).([]interface{})[ : valn], (*pointer).([]interface{})[valn + 1 : ]...))
|
||||
}
|
||||
} else {
|
||||
(*pointer).([]interface{})[valn] = value
|
||||
}
|
||||
|
@ -7,221 +7,221 @@
|
||||
package gjson_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gjson"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"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) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.New(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.New(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_NewUnsafe(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.NewUnsafe(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.NewUnsafe(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Valid(t *testing.T) {
|
||||
data1 := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
data2 := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]`)
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gjson.Valid(data1), true)
|
||||
gtest.Assert(gjson.Valid(data2), false)
|
||||
})
|
||||
data1 := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
data2 := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]`)
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gjson.Valid(data1), true)
|
||||
gtest.Assert(gjson.Valid(data2), false)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Encode(t *testing.T) {
|
||||
value := g.Slice{1, 2, 3}
|
||||
gtest.Case(t, func() {
|
||||
b, err := gjson.Encode(value)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(b, []byte(`[1,2,3]`))
|
||||
})
|
||||
value := g.Slice{1, 2, 3}
|
||||
gtest.Case(t, func() {
|
||||
b, err := gjson.Encode(value)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(b, []byte(`[1,2,3]`))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Decode(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
v, err := gjson.Decode(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v, g.Map{
|
||||
"n" : 123456789,
|
||||
"a" : g.Slice{1, 2, 3},
|
||||
"m" : g.Map{
|
||||
"k" : "v",
|
||||
},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
var v interface{}
|
||||
err := gjson.DecodeTo(data, &v)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v, g.Map{
|
||||
"n" : 123456789,
|
||||
"a" : g.Slice{1, 2, 3},
|
||||
"m" : g.Map{
|
||||
"k" : "v",
|
||||
},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
v, err := gjson.Decode(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v, g.Map{
|
||||
"n": 123456789,
|
||||
"a": g.Slice{1, 2, 3},
|
||||
"m": g.Map{
|
||||
"k": "v",
|
||||
},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
var v interface{}
|
||||
err := gjson.DecodeTo(data, &v)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v, g.Map{
|
||||
"n": 123456789,
|
||||
"a": g.Slice{1, 2, 3},
|
||||
"m": g.Map{
|
||||
"k": "v",
|
||||
},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SplitChar(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
j.SetSplitChar(byte('#'))
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m#k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a#1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
j.SetSplitChar(byte('#'))
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m#k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a#1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ViolenceCheck(t *testing.T) {
|
||||
data := []byte(`{"m":{"a":[1,2,3], "v1.v2":"4"}}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("m.a.2"), 3)
|
||||
gtest.Assert(j.Get("m.v1.v2"), nil)
|
||||
j.SetViolenceCheck(true)
|
||||
gtest.Assert(j.Get("m.v1.v2"), 4)
|
||||
})
|
||||
data := []byte(`{"m":{"a":[1,2,3], "v1.v2":"4"}}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("m.a.2"), 3)
|
||||
gtest.Assert(j.Get("m.v1.v2"), nil)
|
||||
j.SetViolenceCheck(true)
|
||||
gtest.Assert(j.Get("m.v1.v2"), 4)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetToVar(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
var m map[string]string
|
||||
var n int
|
||||
var a []int
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
var m map[string]string
|
||||
var n int
|
||||
var a []int
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
j.GetToVar("n", &n)
|
||||
j.GetToVar("m", &m)
|
||||
j.GetToVar("a", &a)
|
||||
j.GetToVar("n", &n)
|
||||
j.GetToVar("m", &m)
|
||||
j.GetToVar("a", &a)
|
||||
|
||||
gtest.Assert(n, "123456789")
|
||||
gtest.Assert(m, g.Map{"k" : "v"})
|
||||
gtest.Assert(a, g.Slice{1, 2, 3})
|
||||
})
|
||||
gtest.Assert(n, "123456789")
|
||||
gtest.Assert(m, g.Map{"k": "v"})
|
||||
gtest.Assert(a, g.Slice{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetMap(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.GetMap("n"), nil)
|
||||
gtest.Assert(j.GetMap("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.GetMap("a"), nil)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.GetMap("n"), nil)
|
||||
gtest.Assert(j.GetMap("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.GetMap("a"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetJson(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
j2 := j.GetJson("m")
|
||||
gtest.AssertNE(j2, nil)
|
||||
gtest.Assert(j2.Get("k"), "v")
|
||||
gtest.Assert(j2.Get("a"), nil)
|
||||
gtest.Assert(j2.Get("n"), nil)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
j2 := j.GetJson("m")
|
||||
gtest.AssertNE(j2, nil)
|
||||
gtest.Assert(j2.Get("k"), "v")
|
||||
gtest.Assert(j2.Get("a"), nil)
|
||||
gtest.Assert(j2.Get("n"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetArray(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.GetArray("n"), g.Array{123456789})
|
||||
gtest.Assert(j.GetArray("m"), g.Array{g.Map{"k":"v"}})
|
||||
gtest.Assert(j.GetArray("a"), g.Array{1,2,3})
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.GetArray("n"), g.Array{123456789})
|
||||
gtest.Assert(j.GetArray("m"), g.Array{g.Map{"k": "v"}})
|
||||
gtest.Assert(j.GetArray("a"), g.Array{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetString(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertEQ(j.GetString("n"), "123456789")
|
||||
gtest.AssertEQ(j.GetString("m"), `{"k":"v"}`)
|
||||
gtest.AssertEQ(j.GetString("a"), `[1,2,3]`)
|
||||
gtest.AssertEQ(j.GetString("i"), "")
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertEQ(j.GetString("n"), "123456789")
|
||||
gtest.AssertEQ(j.GetString("m"), `{"k":"v"}`)
|
||||
gtest.AssertEQ(j.GetString("a"), `[1,2,3]`)
|
||||
gtest.AssertEQ(j.GetString("i"), "")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetStrings(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertEQ(j.GetStrings("n"), g.SliceStr{"123456789"})
|
||||
gtest.AssertEQ(j.GetStrings("m"), g.SliceStr{`{"k":"v"}`})
|
||||
gtest.AssertEQ(j.GetStrings("a"), g.SliceStr{"1", "2", "3"})
|
||||
gtest.AssertEQ(j.GetStrings("i"), nil)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertEQ(j.GetStrings("n"), g.SliceStr{"123456789"})
|
||||
gtest.AssertEQ(j.GetStrings("m"), g.SliceStr{`{"k":"v"}`})
|
||||
gtest.AssertEQ(j.GetStrings("a"), g.SliceStr{"1", "2", "3"})
|
||||
gtest.AssertEQ(j.GetStrings("i"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetInterfaces(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertEQ(j.GetInterfaces("n"), g.Array{123456789})
|
||||
gtest.AssertEQ(j.GetInterfaces("m"), g.Array{g.Map{"k":"v"}})
|
||||
gtest.AssertEQ(j.GetInterfaces("a"), g.Array{1,2,3})
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertEQ(j.GetInterfaces("n"), g.Array{123456789})
|
||||
gtest.AssertEQ(j.GetInterfaces("m"), g.Array{g.Map{"k": "v"}})
|
||||
gtest.AssertEQ(j.GetInterfaces("a"), g.Array{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Len(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
p := gjson.New(nil)
|
||||
p.Append("a", 1)
|
||||
p.Append("a", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gjson.New(nil)
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gjson.New(nil)
|
||||
p.Set("a", 1)
|
||||
gtest.Assert(p.Len("a"), -1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gjson.New(nil)
|
||||
p.Append("a", 1)
|
||||
p.Append("a", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gjson.New(nil)
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gjson.New(nil)
|
||||
p.Set("a", 1)
|
||||
gtest.Assert(p.Len("a"), -1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Append(t *testing.T) {
|
||||
@ -236,8 +236,8 @@ func Test_Append(t *testing.T) {
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Get("a"), g.Map{
|
||||
"b" : g.Slice{1},
|
||||
"c" : g.Slice{2},
|
||||
"b": g.Slice{1},
|
||||
"c": g.Slice{2},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
@ -282,21 +282,180 @@ func TestJson_Default(t *testing.T) {
|
||||
gtest.AssertEQ(j.GetUint64("no", 100), uint64(100))
|
||||
gtest.AssertEQ(j.GetFloat32("no", 123.456), float32(123.456))
|
||||
gtest.AssertEQ(j.GetFloat64("no", 123.456), float64(123.456))
|
||||
gtest.AssertEQ(j.GetArray("no", g.Slice{1,2,3}), g.Slice{1,2,3})
|
||||
gtest.AssertEQ(j.GetInts("no", g.Slice{1,2,3}), g.SliceInt{1,2,3})
|
||||
gtest.AssertEQ(j.GetFloats("no", g.Slice{1,2,3}), []float64{1,2,3})
|
||||
gtest.AssertEQ(j.GetMap("no", g.Map{"k":"v"}), g.Map{"k":"v"})
|
||||
gtest.AssertEQ(j.GetArray("no", g.Slice{1, 2, 3}), g.Slice{1, 2, 3})
|
||||
gtest.AssertEQ(j.GetInts("no", g.Slice{1, 2, 3}), g.SliceInt{1, 2, 3})
|
||||
gtest.AssertEQ(j.GetFloats("no", g.Slice{1, 2, 3}), []float64{1, 2, 3})
|
||||
gtest.AssertEQ(j.GetMap("no", g.Map{"k": "v"}), g.Map{"k": "v"})
|
||||
gtest.AssertEQ(j.GetVar("no", 123.456).Float64(), float64(123.456))
|
||||
gtest.AssertEQ(j.GetJson("no", g.Map{"k":"v"}).Get("k"), "v")
|
||||
gtest.AssertEQ(j.GetJson("no", g.Map{"k": "v"}).Get("k"), "v")
|
||||
gtest.AssertEQ(j.GetJsons("no", g.Slice{
|
||||
g.Map{"k1":"v1"},
|
||||
g.Map{"k2":"v2"},
|
||||
g.Map{"k3":"v3"},
|
||||
g.Map{"k1": "v1"},
|
||||
g.Map{"k2": "v2"},
|
||||
g.Map{"k3": "v3"},
|
||||
})[0].Get("k1"), "v1")
|
||||
gtest.AssertEQ(j.GetJsonMap("no", g.Map{
|
||||
"m1" : g.Map{"k1":"v1"},
|
||||
"m2" : g.Map{"k2":"v2"},
|
||||
"m1": g.Map{"k1": "v1"},
|
||||
"m2": g.Map{"k2": "v2"},
|
||||
})["m2"].Get("k2"), "v2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Convert(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.New(`{"name":"gf"}`)
|
||||
arr, err := j.ToXml()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "<name>gf</name>")
|
||||
arr, err = j.ToXmlIndent()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "<name>gf</name>")
|
||||
str, err := j.ToXmlString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(str, "<name>gf</name>")
|
||||
str, err = j.ToXmlIndentString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(str, "<name>gf</name>")
|
||||
|
||||
arr, err = j.ToJsonIndent()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "{\n\t\"name\": \"gf\"\n}")
|
||||
str, err = j.ToJsonIndentString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "{\n\t\"name\": \"gf\"\n}")
|
||||
|
||||
arr, err = j.ToYaml()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "name: gf\n")
|
||||
str, err = j.ToYamlString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "name: gf\n")
|
||||
|
||||
arr, err = j.ToToml()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "name = \"gf\"\n")
|
||||
str, err = j.ToTomlString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "name = \"gf\"\n")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Convert2(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
name := struct {
|
||||
Name string
|
||||
}{}
|
||||
j := gjson.New(`{"name":"gf","time":"2019-06-12"}`)
|
||||
gtest.Assert(j.Value().(g.Map)["name"], "gf")
|
||||
gtest.Assert(j.GetMap("name1"), nil)
|
||||
gtest.Assert(j.GetJson("name1"), nil)
|
||||
gtest.Assert(j.GetJsons("name1"), nil)
|
||||
gtest.Assert(j.GetJsonMap("name1"), nil)
|
||||
gtest.Assert(j.Contains("name1"), false)
|
||||
gtest.Assert(j.GetToVar("name1", &name) == nil, true)
|
||||
gtest.Assert(j.GetToVar("name", &name) == nil, false)
|
||||
gtest.Assert(j.Len("name1"), -1)
|
||||
gtest.Assert(j.GetTime("time").Format("2006-01-02"), "2019-06-12")
|
||||
gtest.Assert(j.GetGTime("time").Format("Y-m-d"), "2019-06-12")
|
||||
gtest.Assert(j.GetDuration("time").String(), "0s")
|
||||
|
||||
err := j.ToStruct(&name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(name.Name, "gf")
|
||||
err = j.Dump()
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
j = gjson.New(`{"person":{"name":"gf"}}`)
|
||||
err = j.GetToStruct("person", &name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(name.Name, "gf")
|
||||
|
||||
j = gjson.New(`{"name":"gf""}`)
|
||||
err = j.Dump()
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
gtest.Assert(len(j.ToArray()), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.New(`{"name":"gf","time":"2019-06-12"}`)
|
||||
j.SetViolenceCheck(true)
|
||||
gtest.Assert(j.Get("").(g.Map)["name"], "gf")
|
||||
gtest.Assert(j.Get("").(g.Map)["name1"], nil)
|
||||
j.SetViolenceCheck(false)
|
||||
gtest.Assert(j.Get("").(g.Map)["name"], "gf")
|
||||
|
||||
err := j.Set("name", "gf1")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("name"), "gf1")
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Set("\"0\".1", 11)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("1"), 11)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Set("11111111111111111111111", 11)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Remove("1")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("0"), 1)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Remove("3")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("0"), 1)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Remove("0.3")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(j.Get("0").([]interface{})), 3)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Remove("0.a")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(j.Get("0").(g.Map)), 0)
|
||||
|
||||
name := struct {
|
||||
Name string
|
||||
}{Name: "gf"}
|
||||
j = gjson.New(name)
|
||||
gtest.Assert(j.Get("Name"), "gf")
|
||||
err = j.Remove("Name")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name"), nil)
|
||||
|
||||
err = j.Set("Name", "gf1")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name"), "gf1")
|
||||
|
||||
j = gjson.New(nil)
|
||||
err = j.Remove("Name")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name"), nil)
|
||||
|
||||
j = gjson.New(name)
|
||||
gtest.Assert(j.Get("Name"), "gf")
|
||||
err = j.Set("Name1", g.Map{"Name": "gf1"})
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name1").(g.Map)["Name"], "gf1")
|
||||
err = j.Set("Name2", g.Slice{1, 2, 3})
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name2").(g.Slice)[0], 1)
|
||||
err = j.Set("Name3", name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name3").(g.Map)["Name"], "gf")
|
||||
err = j.Set("Name4", &name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name4").(g.Map)["Name"], "gf")
|
||||
arr := [3]int{1, 2, 3}
|
||||
err = j.Set("Name5", arr)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name5").(g.Array)[0], 1)
|
||||
|
||||
})
|
||||
}
|
||||
|
@ -7,66 +7,65 @@
|
||||
package gjson_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gjson"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gjson"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
||||
func Test_Load_JSON(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
path := "test.json"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
path := "test.json"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_XML(t *testing.T) {
|
||||
data := []byte(`<doc><a>1</a><a>2</a><a>3</a><m><k>v</k></m><n>123456789</n></doc>`)
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.xml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
data := []byte(`<doc><a>1</a><a>2</a><a>3</a><m><k>v</k></m><n>123456789</n></doc>`)
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.xml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
@ -82,13 +81,13 @@ func Test_Load_XML(t *testing.T) {
|
||||
</Output>`
|
||||
j, err := gjson.LoadContent(xml)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Output.ipageIndex"), "2")
|
||||
gtest.Assert(j.Get("Output.ipageIndex"), "2")
|
||||
gtest.Assert(j.Get("Output.itotalRecords"), "GF框架")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_YAML1(t *testing.T) {
|
||||
data := []byte(`
|
||||
data := []byte(`
|
||||
a:
|
||||
- 1
|
||||
- 2
|
||||
@ -97,78 +96,102 @@ m:
|
||||
k: v
|
||||
"n": 123456789
|
||||
`)
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.yaml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.yaml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_YAML2(t *testing.T) {
|
||||
data := []byte("i : 123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
data := []byte("i : 123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_TOML1(t *testing.T) {
|
||||
data := []byte(`
|
||||
data := []byte(`
|
||||
a = ["1", "2", "3"]
|
||||
n = "123456789"
|
||||
|
||||
[m]
|
||||
k = "v"
|
||||
`)
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.toml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.toml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_TOML2(t *testing.T) {
|
||||
data := []byte("i=123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
data := []byte("i=123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.NewUnsafe()
|
||||
gtest.Assert(j.Value(), nil)
|
||||
_, err := gjson.Decode(nil)
|
||||
gtest.AssertNE(err, nil)
|
||||
_, err = gjson.DecodeToJson(nil)
|
||||
gtest.AssertNE(err, nil)
|
||||
j, err = gjson.LoadContent(nil)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Value(), nil)
|
||||
|
||||
j, err = gjson.LoadContent(`{"name": "gf"}`)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
j, err = gjson.LoadContent(`{"name": "gf"""}`)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
j = gjson.New(&g.Map{"name": "gf"})
|
||||
gtest.Assert(j.GetString("name"), "gf")
|
||||
|
||||
})
|
||||
}
|
||||
|
@ -7,202 +7,314 @@
|
||||
package gparser_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gparser"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gparser"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_New(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
v := j.Value().(g.Map)
|
||||
gtest.Assert(v["n"], 123456789)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_NewUnsafe(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.NewUnsafe(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.NewUnsafe(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Encode(t *testing.T) {
|
||||
value := g.Slice{1, 2, 3}
|
||||
gtest.Case(t, func() {
|
||||
b, err := gparser.VarToJson(value)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(b, []byte(`[1,2,3]`))
|
||||
})
|
||||
value := g.Slice{1, 2, 3}
|
||||
gtest.Case(t, func() {
|
||||
b, err := gparser.VarToJson(value)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(b, []byte(`[1,2,3]`))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Decode(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SplitChar(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
j.SetSplitChar(byte('#'))
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m#k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a#1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
j.SetSplitChar(byte('#'))
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m#k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a#1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ViolenceCheck(t *testing.T) {
|
||||
data := []byte(`{"m":{"a":[1,2,3], "v1.v2":"4"}}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.Get("m.a.2"), 3)
|
||||
gtest.Assert(j.Get("m.v1.v2"), nil)
|
||||
j.SetViolenceCheck(true)
|
||||
gtest.Assert(j.Get("m.v1.v2"), 4)
|
||||
})
|
||||
data := []byte(`{"m":{"a":[1,2,3], "v1.v2":"4"}}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.Get("m.a.2"), 3)
|
||||
gtest.Assert(j.Get("m.v1.v2"), nil)
|
||||
j.SetViolenceCheck(true)
|
||||
gtest.Assert(j.Get("m.v1.v2"), 4)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetToVar(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
var m map[string]string
|
||||
var n int
|
||||
var a []int
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
var m map[string]string
|
||||
var n int
|
||||
var a []int
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
|
||||
j.GetToVar("n", &n)
|
||||
j.GetToVar("m", &m)
|
||||
j.GetToVar("a", &a)
|
||||
j.GetToVar("n", &n)
|
||||
j.GetToVar("m", &m)
|
||||
j.GetToVar("a", &a)
|
||||
|
||||
gtest.Assert(n, "123456789")
|
||||
gtest.Assert(m, g.Map{"k" : "v"})
|
||||
gtest.Assert(a, g.Slice{1, 2, 3})
|
||||
})
|
||||
gtest.Assert(n, "123456789")
|
||||
gtest.Assert(m, g.Map{"k": "v"})
|
||||
gtest.Assert(a, g.Slice{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetMap(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.GetMap("n"), nil)
|
||||
gtest.Assert(j.GetMap("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.GetMap("a"), nil)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.GetMap("n"), nil)
|
||||
gtest.Assert(j.GetMap("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.GetMap("a"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetArray(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.GetArray("n"), g.Array{123456789})
|
||||
gtest.Assert(j.GetArray("m"), g.Array{g.Map{"k":"v"}})
|
||||
gtest.Assert(j.GetArray("a"), g.Array{1,2,3})
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.GetArray("n"), g.Array{123456789})
|
||||
gtest.Assert(j.GetArray("m"), g.Array{g.Map{"k": "v"}})
|
||||
gtest.Assert(j.GetArray("a"), g.Array{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetString(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.AssertEQ(j.GetString("n"), "123456789")
|
||||
gtest.AssertEQ(j.GetString("m"), `{"k":"v"}`)
|
||||
gtest.AssertEQ(j.GetString("a"), `[1,2,3]`)
|
||||
gtest.AssertEQ(j.GetString("i"), "")
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.AssertEQ(j.GetString("n"), "123456789")
|
||||
gtest.AssertEQ(j.GetString("m"), `{"k":"v"}`)
|
||||
gtest.AssertEQ(j.GetString("a"), `[1,2,3]`)
|
||||
gtest.AssertEQ(j.GetString("i"), "")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetStrings(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.AssertEQ(j.GetStrings("n"), g.SliceStr{"123456789"})
|
||||
gtest.AssertEQ(j.GetStrings("m"), g.SliceStr{`{"k":"v"}`})
|
||||
gtest.AssertEQ(j.GetStrings("a"), g.SliceStr{"1", "2", "3"})
|
||||
gtest.AssertEQ(j.GetStrings("i"), nil)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.AssertEQ(j.GetStrings("n"), g.SliceStr{"123456789"})
|
||||
gtest.AssertEQ(j.GetStrings("m"), g.SliceStr{`{"k":"v"}`})
|
||||
gtest.AssertEQ(j.GetStrings("a"), g.SliceStr{"1", "2", "3"})
|
||||
gtest.AssertEQ(j.GetStrings("i"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetInterfaces(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.AssertEQ(j.GetInterfaces("n"), g.Array{123456789})
|
||||
gtest.AssertEQ(j.GetInterfaces("m"), g.Array{g.Map{"k":"v"}})
|
||||
gtest.AssertEQ(j.GetInterfaces("a"), g.Array{1,2,3})
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.AssertEQ(j.GetInterfaces("n"), g.Array{123456789})
|
||||
gtest.AssertEQ(j.GetInterfaces("m"), g.Array{g.Map{"k": "v"}})
|
||||
gtest.AssertEQ(j.GetInterfaces("a"), g.Array{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Len(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a", 1)
|
||||
p.Append("a", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Set("a", 1)
|
||||
gtest.Assert(p.Len("a"), -1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a", 1)
|
||||
p.Append("a", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Set("a", 1)
|
||||
gtest.Assert(p.Len("a"), -1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Append(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a", 1)
|
||||
p.Append("a", 2)
|
||||
gtest.Assert(p.Get("a"), g.Slice{1, 2})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Get("a"), g.Map{
|
||||
"b" : g.Slice{1},
|
||||
"c" : g.Slice{2},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Set("a", 1)
|
||||
err := p.Append("a", 2)
|
||||
gtest.AssertNE(err, nil)
|
||||
gtest.Assert(p.Get("a"), 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a", 1)
|
||||
p.Append("a", 2)
|
||||
gtest.Assert(p.Get("a"), g.Slice{1, 2})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Get("a"), g.Map{
|
||||
"b": g.Slice{1},
|
||||
"c": g.Slice{2},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Set("a", 1)
|
||||
err := p.Append("a", 2)
|
||||
gtest.AssertNE(err, nil)
|
||||
gtest.Assert(p.Get("a"), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Convert(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(`{"name":"gf","bool":true,"int":1,"float":1,"ints":[1,2],"floats":[1,2],"time":"2019-06-12","person": {"name": "gf"}}`)
|
||||
gtest.Assert(p.GetVar("name").String(), "gf")
|
||||
gtest.Assert(p.GetString("name"), "gf")
|
||||
gtest.Assert(p.GetBool("bool"), true)
|
||||
gtest.Assert(p.GetInt("int"), 1)
|
||||
gtest.Assert(p.GetInt8("int"), 1)
|
||||
gtest.Assert(p.GetInt16("int"), 1)
|
||||
gtest.Assert(p.GetInt32("int"), 1)
|
||||
gtest.Assert(p.GetInt64("int"), 1)
|
||||
gtest.Assert(p.GetUint("int"), 1)
|
||||
gtest.Assert(p.GetUint8("int"), 1)
|
||||
gtest.Assert(p.GetUint16("int"), 1)
|
||||
gtest.Assert(p.GetUint32("int"), 1)
|
||||
gtest.Assert(p.GetUint64("int"), 1)
|
||||
gtest.Assert(p.GetInts("ints")[0], 1)
|
||||
gtest.Assert(p.GetFloat32("float"), 1)
|
||||
gtest.Assert(p.GetFloat64("float"), 1)
|
||||
gtest.Assert(p.GetFloats("floats")[0], 1)
|
||||
gtest.Assert(p.GetTime("time").Format("2006-01-02"), "2019-06-12")
|
||||
gtest.Assert(p.GetGTime("time").Format("Y-m-d"), "2019-06-12")
|
||||
gtest.Assert(p.GetDuration("time").String(), "0s")
|
||||
name := struct {
|
||||
Name string
|
||||
}{}
|
||||
err := p.GetToStruct("person", &name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(name.Name, "gf")
|
||||
gtest.Assert(p.ToMap()["name"], "gf")
|
||||
err = p.ToStruct(&name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(name.Name, "gf")
|
||||
p.Dump()
|
||||
|
||||
p = gparser.New(`[0,1,2]`)
|
||||
gtest.Assert(p.ToArray()[0], 0)
|
||||
|
||||
err = gparser.VarToStruct(`{"name":"gf"}`, &name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(name.Name, "gf")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Convert2(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
xmlArr := []byte{60, 114, 111, 111, 116, 47, 62}
|
||||
p := gparser.New(`<root></root>`)
|
||||
arr, err := p.ToXml("root")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, xmlArr)
|
||||
arr, err = gparser.VarToXml(`<root></root>`, "root")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, xmlArr)
|
||||
|
||||
arr, err = p.ToXmlIndent("root")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, xmlArr)
|
||||
arr, err = gparser.VarToXmlIndent(`<root></root>`, "root")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, xmlArr)
|
||||
|
||||
p = gparser.New(`{"name":"gf"}`)
|
||||
str, err := p.ToJsonString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(str, `{"name":"gf"}`)
|
||||
str, err = gparser.VarToJsonString(`{"name":"gf"}`)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(str, `{"name":"gf"}`)
|
||||
|
||||
jsonIndentArr := []byte{123, 10, 9, 34, 110, 97, 109, 101, 34, 58, 32, 34, 103, 102, 34, 10, 125}
|
||||
arr, err = p.ToJsonIndent()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, jsonIndentArr)
|
||||
arr, err = gparser.VarToJsonIndent(`{"name":"gf"}`)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, jsonIndentArr)
|
||||
|
||||
str, err = p.ToJsonIndentString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(str, "{\n\t\"name\": \"gf\"\n}")
|
||||
str, err = gparser.VarToJsonIndentString(`{"name":"gf"}`)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(str, "{\n\t\"name\": \"gf\"\n}")
|
||||
|
||||
yamlArr := []byte{124, 50, 10, 10, 32, 32, 110, 97, 109, 101, 58, 103, 102, 10}
|
||||
p = gparser.New(`
|
||||
name:gf
|
||||
`)
|
||||
arr, err = p.ToYaml()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, yamlArr)
|
||||
arr, err = gparser.VarToYaml(`
|
||||
name:gf
|
||||
`)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, yamlArr)
|
||||
|
||||
tomlArr := []byte{110, 97, 109, 101, 32, 61, 32, 34, 103, 102, 34, 10}
|
||||
p = gparser.New(`
|
||||
name= "gf"
|
||||
`)
|
||||
arr, err = p.ToToml()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, tomlArr)
|
||||
arr, err = gparser.VarToToml(`
|
||||
name= "gf"
|
||||
`)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, tomlArr)
|
||||
})
|
||||
}
|
||||
|
@ -11,62 +11,62 @@ import (
|
||||
"github.com/gogf/gf/g/encoding/gparser"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
||||
func Test_Load_JSON(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
path := "test.json"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
path := "test.json"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_XML(t *testing.T) {
|
||||
data := []byte(`<doc><a>1</a><a>2</a><a>3</a><m><k>v</k></m><n>123456789</n></doc>`)
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.xml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
data := []byte(`<doc><a>1</a><a>2</a><a>3</a><m><k>v</k></m><n>123456789</n></doc>`)
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.xml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
@ -82,13 +82,13 @@ func Test_Load_XML(t *testing.T) {
|
||||
</Output>`
|
||||
j, err := gparser.LoadContent(xml)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Output.ipageIndex"), "2")
|
||||
gtest.Assert(j.Get("Output.ipageIndex"), "2")
|
||||
gtest.Assert(j.Get("Output.itotalRecords"), "GF框架")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_YAML1(t *testing.T) {
|
||||
data := []byte(`
|
||||
data := []byte(`
|
||||
a:
|
||||
- 1
|
||||
- 2
|
||||
@ -97,78 +97,93 @@ m:
|
||||
k: v
|
||||
"n": 123456789
|
||||
`)
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.yaml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.yaml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_YAML2(t *testing.T) {
|
||||
data := []byte("i : 123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
data := []byte("i : 123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_TOML1(t *testing.T) {
|
||||
data := []byte(`
|
||||
data := []byte(`
|
||||
a = ["1", "2", "3"]
|
||||
n = "123456789"
|
||||
|
||||
[m]
|
||||
k = "v"
|
||||
`)
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.toml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.toml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_TOML2(t *testing.T) {
|
||||
data := []byte("i=123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
data := []byte("i=123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_Nil(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.NewUnsafe()
|
||||
gtest.Assert(p.Value(), nil)
|
||||
file := "test22222.json"
|
||||
filePath := gfile.Pwd() + gfile.Separator + file
|
||||
ioutil.WriteFile(filePath, []byte("{"), 0644)
|
||||
defer gfile.Remove(filePath)
|
||||
_, err := gparser.Load(file)
|
||||
gtest.AssertNE(err, nil)
|
||||
_, err = gparser.LoadContent("{")
|
||||
gtest.AssertNE(err, nil)
|
||||
})
|
||||
}
|
||||
|
@ -61,13 +61,13 @@ func SetIfNotExist(key string, value interface{}) bool {
|
||||
}
|
||||
|
||||
// View returns an instance of View with default settings.
|
||||
// The param <name> is the name for the instance.
|
||||
// The parameter <name> is the name for the instance.
|
||||
func View(name ...string) *gview.View {
|
||||
return gview.Instance(name ...)
|
||||
}
|
||||
|
||||
// Config returns an instance of View with default settings.
|
||||
// The param <name> is the name for the instance.
|
||||
// The parameter <name> is the name for the instance.
|
||||
func Config(name ...string) *gcfg.Config {
|
||||
return gcfg.Instance(name ...)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package cmdenv provides access to certain variable for both command options and environment.
|
||||
package cmdenv
|
||||
|
||||
import (
|
||||
@ -18,7 +19,12 @@ var (
|
||||
cmdOptions = make(map[string]string)
|
||||
)
|
||||
|
||||
func init() {
|
||||
func init() {
|
||||
doInit()
|
||||
}
|
||||
|
||||
// doInit does the initialization for this package.
|
||||
func doInit() {
|
||||
reg := regexp.MustCompile(`\-\-{0,1}(.+?)=(.+)`)
|
||||
for i := 0; i < len(os.Args); i++ {
|
||||
result := reg.FindStringSubmatch(os.Args[i])
|
||||
@ -28,10 +34,13 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取指定名称的命令行参数,当不存在时获取环境变量参数,皆不存在时,返回给定的默认值。
|
||||
// 规则:
|
||||
// 1、命令行参数以小写字母格式,使用: gf.包名.变量名 传递;
|
||||
// 2、环境变量参数以大写字母格式,使用: GF_包名_变量名 传递;
|
||||
// Get returns the command line argument of the specified <key>.
|
||||
// If the argument does not exist, then it returns the environment variable with specified <key>.
|
||||
// It returns the default value <def> if none of them exists.
|
||||
//
|
||||
// Fetching Rules:
|
||||
// 1. Command line arguments are in lowercase format, eg: gf.<package name>.<variable name>;
|
||||
// 2. Environment arguments are in uppercase format, eg: GF_<package name>_<variable name>;
|
||||
func Get(key string, def...interface{}) *gvar.Var {
|
||||
value := interface{}(nil)
|
||||
if len(def) > 0 {
|
||||
|
29
g/internal/cmdenv/cmdenv_test.go
Normal file
29
g/internal/cmdenv/cmdenv_test.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
// go test *.go -bench=".*" -benchmem
|
||||
|
||||
package cmdenv
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Get(t *testing.T) {
|
||||
os.Args = []string{"--gf.test.value1=111"}
|
||||
os.Setenv("GF_TEST_VALUE1", "222")
|
||||
os.Setenv("GF_TEST_VALUE2", "333")
|
||||
doInit()
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(Get("gf.test.value1").String(), "111")
|
||||
gtest.Assert(Get("gf.test.value2").String(), "333")
|
||||
gtest.Assert(Get("gf.test.value3").String(), "")
|
||||
gtest.Assert(Get("gf.test.value3", 1).String(), "1")
|
||||
})
|
||||
}
|
||||
|
@ -4,15 +4,16 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package empty provides checks for empty variables.
|
||||
package empty
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// 判断给定的变量是否为空。
|
||||
// 整型为0, 布尔为false, slice/map长度为0, 其他为nil的情况,都为空。
|
||||
// 为空时返回true,否则返回false。
|
||||
// IsEmpty checks whether given <value> empty.
|
||||
// It returns true if <value> is in: 0, nil, false, "", len(slice/map/chan) == 0.
|
||||
// Or else it returns true.
|
||||
func IsEmpty(value interface{}) bool {
|
||||
if value == nil {
|
||||
return true
|
||||
|
@ -4,11 +4,11 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package mutex provides switch for sync.Mutex for concurrent safe feature.
|
||||
package mutex
|
||||
|
||||
import "sync"
|
||||
|
||||
// Mutex的封装,支持对并发安全开启/关闭的控制。
|
||||
type Mutex struct {
|
||||
sync.Mutex
|
||||
safe bool
|
||||
|
@ -4,6 +4,7 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package rwmutex provides switch for sync.RWMutex for concurrent safe feature.
|
||||
package rwmutex
|
||||
|
||||
import "sync"
|
||||
|
@ -45,7 +45,7 @@ func GetServer(name...interface{}) *Server {
|
||||
}
|
||||
|
||||
// NewServer creates and returns a new normal TCP server.
|
||||
// The param <name> is optional, which is used to specify the instance name of the server.
|
||||
// The parameter <name> is optional, which is used to specify the instance name of the server.
|
||||
func NewServer(address string, handler func (*Conn), name...string) *Server {
|
||||
s := &Server{
|
||||
address : address,
|
||||
@ -58,7 +58,7 @@ func NewServer(address string, handler func (*Conn), name...string) *Server {
|
||||
}
|
||||
|
||||
// NewServerTLS creates and returns a new TCP server with TLS support.
|
||||
// The param <name> is optional, which is used to specify the instance name of the server.
|
||||
// The parameter <name> is optional, which is used to specify the instance name of the server.
|
||||
func NewServerTLS(address string, tlsConfig *tls.Config, handler func (*Conn), name...string) *Server {
|
||||
s := NewServer(address, handler, name...)
|
||||
s.SetTLSConfig(tlsConfig)
|
||||
@ -66,7 +66,7 @@ func NewServerTLS(address string, tlsConfig *tls.Config, handler func (*Conn), n
|
||||
}
|
||||
|
||||
// NewServerKeyCrt creates and returns a new TCP server with TLS support.
|
||||
// The param <name> is optional, which is used to specify the instance name of the server.
|
||||
// The parameter <name> is optional, which is used to specify the instance name of the server.
|
||||
func NewServerKeyCrt(address, crtFile, keyFile string, handler func (*Conn), name...string) *Server {
|
||||
s := NewServer(address, handler, name...)
|
||||
if err := s.SetTLSKeyCrt(crtFile, keyFile); err != nil {
|
||||
|
@ -7,81 +7,100 @@
|
||||
// Package gcache provides high performance and concurrent-safe in-memory cache for process.
|
||||
package gcache
|
||||
|
||||
// 全局缓存管理对象
|
||||
// Default cache object.
|
||||
var cache = New()
|
||||
|
||||
// (使用全局KV缓存对象)设置kv缓存键值对,过期时间单位为**毫秒**
|
||||
|
||||
// Set sets cache with <key>-<value> pair, which is expired after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
func Set(key interface{}, value interface{}, expire int) {
|
||||
cache.Set(key, value, expire)
|
||||
}
|
||||
|
||||
// 当键名不存在时写入,并返回true;否则返回false。
|
||||
// 常用来做对并发性要求不高的内存锁。
|
||||
// SetIfNotExist sets cache with <key>-<value> pair if <key> does not exist in the cache,
|
||||
// which is expired after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
func SetIfNotExist(key interface{}, value interface{}, expire int) bool {
|
||||
return cache.SetIfNotExist(key, value, expire)
|
||||
}
|
||||
|
||||
// (使用全局KV缓存对象)批量设置kv缓存键值对,过期时间单位为**毫秒**
|
||||
// Sets batch sets cache with key-value pairs by <data>, which is expired after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
func Sets(data map[interface{}]interface{}, expire int) {
|
||||
cache.Sets(data, expire)
|
||||
}
|
||||
|
||||
// (使用全局KV缓存对象)获取指定键名的值
|
||||
// Get returns the value of <key>.
|
||||
// It returns nil if it does not exist or its value is nil.
|
||||
func Get(key interface{}) interface{} {
|
||||
return cache.Get(key)
|
||||
}
|
||||
|
||||
// 当键名存在时返回其键值,否则写入指定的键值
|
||||
// GetOrSet returns the value of <key>,
|
||||
// or sets <key>-<value> pair and returns <value> if <key> does not exist in the cache.
|
||||
// The key-value pair expires after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
func GetOrSet(key interface{}, value interface{}, expire int) interface{} {
|
||||
return cache.GetOrSet(key, value, expire)
|
||||
}
|
||||
|
||||
// 当键名存在时返回其键值,否则写入指定的键值,键值由指定的函数生成
|
||||
|
||||
// GetOrSetFunc returns the value of <key>,
|
||||
// or sets <key> with result of function <f> and returns its result
|
||||
// if <key> does not exist in the cache.
|
||||
// The key-value pair expires after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
func GetOrSetFunc(key interface{}, f func() interface{}, expire int) interface{} {
|
||||
return cache.GetOrSetFunc(key, f, expire)
|
||||
}
|
||||
|
||||
// 与GetOrSetFunc不同的是,f是在写锁机制内执行
|
||||
// GetOrSetFuncLock returns the value of <key>,
|
||||
// or sets <key> with result of function <f> and returns its result
|
||||
// if <key> does not exist in the cache.
|
||||
// The key-value pair expires after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
//
|
||||
// Note that the function <f> is executed within writing mutex lock.
|
||||
func GetOrSetFuncLock(key interface{}, f func() interface{}, expire int) interface{} {
|
||||
return cache.GetOrSetFuncLock(key, f, expire)
|
||||
}
|
||||
|
||||
// 是否存在指定的键名,true表示存在,false表示不存在。
|
||||
// Contains returns true if <key> exists in the cache, or else returns false.
|
||||
func Contains(key interface{}) bool {
|
||||
return cache.Contains(key)
|
||||
}
|
||||
|
||||
// (使用全局KV缓存对象)删除指定键值对
|
||||
// Remove deletes the <key> in the cache, and returns its value.
|
||||
func Remove(key interface{}) interface{} {
|
||||
return cache.Remove(key)
|
||||
}
|
||||
|
||||
// (使用全局KV缓存对象)批量删除指定键值对
|
||||
// Removes deletes <keys> in the cache.
|
||||
func Removes(keys []interface{}) {
|
||||
cache.Removes(keys)
|
||||
}
|
||||
|
||||
// 返回缓存的所有数据键值对(不包含已过期数据)
|
||||
// Data returns a copy of all key-value pairs in the cache as map type.
|
||||
func Data() map[interface{}]interface{} {
|
||||
return cache.Data()
|
||||
}
|
||||
|
||||
// 获得所有的键名,组成数组返回
|
||||
// Keys returns all keys in the cache as slice.
|
||||
func Keys() []interface{} {
|
||||
return cache.Keys()
|
||||
}
|
||||
|
||||
// 获得所有的键名,组成字符串数组返回
|
||||
// KeyStrings returns all keys in the cache as string slice.
|
||||
func KeyStrings() []string {
|
||||
return cache.KeyStrings()
|
||||
}
|
||||
|
||||
// 获得所有的值,组成数组返回
|
||||
// Values returns all values in the cache as slice.
|
||||
func Values() []interface{} {
|
||||
return cache.Values()
|
||||
}
|
||||
|
||||
// 获得缓存对象的键值对数量
|
||||
// Size returns the size of the cache.
|
||||
func Size() int {
|
||||
return cache.Size()
|
||||
}
|
||||
|
@ -13,13 +13,12 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// 缓存对象。
|
||||
// 底层只有一个缓存对象,如果需要提高并发性能,可新增缓存对象无锁哈希表,用键名做固定分区。
|
||||
// Cache struct.
|
||||
type Cache struct {
|
||||
*memCache
|
||||
}
|
||||
|
||||
// Cache对象按照缓存键名首字母做了分组
|
||||
// New creates and returns a new cache object.
|
||||
func New(lruCap...int) *Cache {
|
||||
c := &Cache {
|
||||
memCache : newMemCache(lruCap...),
|
||||
@ -28,10 +27,10 @@ func New(lruCap...int) *Cache {
|
||||
return c
|
||||
}
|
||||
|
||||
// 清空缓存中的所有数据
|
||||
// Clear clears all data of the cache.
|
||||
func (c *Cache) Clear() {
|
||||
// 使用原子操作替换缓存对象
|
||||
// atomic swap to ensure atomicity.
|
||||
old := atomic.SwapPointer((*unsafe.Pointer)(unsafe.Pointer(&c.memCache)), unsafe.Pointer(newMemCache()))
|
||||
// 关闭旧的缓存对象
|
||||
// close the old cache object.
|
||||
(*memCache)(old).Close()
|
||||
}
|
@ -18,41 +18,46 @@ import (
|
||||
)
|
||||
|
||||
|
||||
// 缓存对象
|
||||
// Internal cache object.
|
||||
type memCache struct {
|
||||
dataMu sync.RWMutex
|
||||
expireTimeMu sync.RWMutex
|
||||
expireSetMu sync.RWMutex
|
||||
|
||||
cap int // 控制缓存池大小,超过大小则按照LRU算法进行缓存过期处理(默认为0表示不进行限制)
|
||||
data map[interface{}]memCacheItem // 缓存数据(所有的缓存数据存放哈希表)
|
||||
expireTimes map[interface{}]int64 // 键名对应的分组过期时间(用于相同键名过期时间快速更新),键值为1秒级时间戳
|
||||
expireSets map[int64]*gset.Set // 分组过期时间对应的键名列表(用于自动过期快速删除),键值为1秒级时间戳
|
||||
// <cap> limits the size of the cache pool.
|
||||
// If the size of the cache exceeds the <cap>,
|
||||
// the cache expiration process is performed according to the LRU algorithm.
|
||||
// It is 0 in default which means no limits.
|
||||
cap int
|
||||
data map[interface{}]memCacheItem // Underlying cache data which is stored in a hash table.
|
||||
expireTimes map[interface{}]int64 // Expiring key mapping to its timestamp, which is used for quick indexing and deleting.
|
||||
expireSets map[int64]*gset.Set // Expiring timestamp mapping to its key set, which is used for quick indexing and deleting.
|
||||
|
||||
lru *memCacheLru // LRU缓存限制(只有限定cap池大小时才启用)
|
||||
lruGetList *glist.List // Get操作的LRU记录
|
||||
eventList *glist.List // 异步处理队列
|
||||
closed *gtype.Bool // 关闭事件通知
|
||||
lru *memCacheLru // LRU object, which is enabled when <cap> > 0.
|
||||
lruGetList *glist.List // LRU history according with Get function.
|
||||
eventList *glist.List // Asynchronous event list for internal data synchronization.
|
||||
closed *gtype.Bool // Is this cache closed or not.
|
||||
}
|
||||
|
||||
// 缓存数据项
|
||||
// Internal cache item.
|
||||
type memCacheItem struct {
|
||||
v interface{} // 键值
|
||||
e int64 // 过期时间
|
||||
v interface{} // Value.
|
||||
e int64 // Expire time in milliseconds.
|
||||
}
|
||||
|
||||
// 异步队列数据项
|
||||
// Internal event item.
|
||||
type memCacheEvent struct {
|
||||
k interface{} // 键名
|
||||
e int64 // 过期时间
|
||||
k interface{} // Key.
|
||||
e int64 // Expire time in milliseconds.
|
||||
}
|
||||
|
||||
const (
|
||||
// 当数据不过期时,默认设置的过期属性值,相当于:math.MaxInt64/1000000
|
||||
// Default expire time for no expiring items.
|
||||
// It equals to math.MaxInt64/1000000.
|
||||
gDEFAULT_MAX_EXPIRE = 9223372036854
|
||||
)
|
||||
|
||||
// 创建底层的缓存对象
|
||||
// newMemCache creates and returns a new memory cache object.
|
||||
func newMemCache(lruCap...int) *memCache {
|
||||
c := &memCache {
|
||||
lruGetList : glist.New(),
|
||||
@ -69,12 +74,12 @@ func newMemCache(lruCap...int) *memCache {
|
||||
return c
|
||||
}
|
||||
|
||||
// 计算过期缓存的键名(将毫秒换算成秒的整数毫秒,按照1秒进行分组)
|
||||
// makeExpireKey groups the <expire> in milliseconds to its according seconds.
|
||||
func (c *memCache) makeExpireKey(expire int64) int64 {
|
||||
return int64(math.Ceil(float64(expire/1000) + 1)*1000)
|
||||
}
|
||||
|
||||
// 获取一个过期键名存放Set, 如果没有则返回nil
|
||||
// getExpireSet returns the expire set for given <expire> in seconds.
|
||||
func (c *memCache) getExpireSet(expire int64) (expireSet *gset.Set) {
|
||||
c.expireSetMu.RLock()
|
||||
expireSet, _ = c.expireSets[expire]
|
||||
@ -82,23 +87,19 @@ func (c *memCache) getExpireSet(expire int64) (expireSet *gset.Set) {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取或者创建一个过期键名存放Set(由于是异步单线程执行,因此不会出现创建set时的覆盖问题)
|
||||
// getOrNewExpireSet returns the expire set for given <expire> in seconds.
|
||||
// It creates and returns a new set for <expire> if it does not exist.
|
||||
func (c *memCache) getOrNewExpireSet(expire int64) (expireSet *gset.Set) {
|
||||
if expireSet = c.getExpireSet(expire); expireSet == nil {
|
||||
expireSet = gset.New()
|
||||
c.expireSetMu.Lock()
|
||||
// 写锁二次检索确认
|
||||
if es, ok := c.expireSets[expire]; ok {
|
||||
expireSet = es
|
||||
} else {
|
||||
c.expireSets[expire] = expireSet
|
||||
}
|
||||
c.expireSets[expire] = gset.New()
|
||||
c.expireSetMu.Unlock()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 设置kv缓存键值对,过期时间单位为毫秒,expire<=0表示不过期
|
||||
// Set sets cache with <key>-<value> pair, which is expired after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
func (c *memCache) Set(key interface{}, value interface{}, expire int) {
|
||||
expireTime := c.getInternalExpire(expire)
|
||||
c.dataMu.Lock()
|
||||
@ -107,8 +108,12 @@ func (c *memCache) Set(key interface{}, value interface{}, expire int) {
|
||||
c.eventList.PushBack(&memCacheEvent{k : key, e : expireTime})
|
||||
}
|
||||
|
||||
// 设置kv缓存键值对,内部会对键名的存在性使用写锁进行二次检索确认,如果存在则不再写入;返回键名对应的键值。
|
||||
// 在高并发下有用,防止数据写入的并发逻辑错误。
|
||||
// doSetWithLockCheck sets cache with <key>-<value> pair if <key> does not exist in the cache,
|
||||
// which is expired after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
//
|
||||
// It doubly checks the <key> whether exists in the cache using mutex writing lock
|
||||
// before setting it to the cache.
|
||||
func (c *memCache) doSetWithLockCheck(key interface{}, value interface{}, expire int) interface{} {
|
||||
expireTimestamp := c.getInternalExpire(expire)
|
||||
c.dataMu.Lock()
|
||||
@ -128,7 +133,7 @@ func (c *memCache) doSetWithLockCheck(key interface{}, value interface{}, expire
|
||||
return value
|
||||
}
|
||||
|
||||
// 根据给定expire参数计算内部使用的expire过期时间
|
||||
// getInternalExpire returns the expire time with given expire duration in milliseconds.
|
||||
func (c *memCache) getInternalExpire(expire int) int64 {
|
||||
if expire != 0 {
|
||||
return gtime.Millisecond() + int64(expire)
|
||||
@ -137,7 +142,9 @@ func (c *memCache) getInternalExpire(expire int) int64 {
|
||||
}
|
||||
}
|
||||
|
||||
// 当键名不存在时写入,并返回true;否则返回false。
|
||||
// SetIfNotExist sets cache with <key>-<value> pair if <key> does not exist in the cache,
|
||||
// which is expired after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
func (c *memCache) SetIfNotExist(key interface{}, value interface{}, expire int) bool {
|
||||
if !c.Contains(key) {
|
||||
c.doSetWithLockCheck(key, value, expire)
|
||||
@ -146,7 +153,8 @@ func (c *memCache) SetIfNotExist(key interface{}, value interface{}, expire int)
|
||||
return false
|
||||
}
|
||||
|
||||
// 批量设置
|
||||
// Sets batch sets cache with key-value pairs by <data>, which is expired after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
func (c *memCache) Sets(data map[interface{}]interface{}, expire int) {
|
||||
expireTime := c.getInternalExpire(expire)
|
||||
for k, v := range data {
|
||||
@ -157,13 +165,14 @@ func (c *memCache) Sets(data map[interface{}]interface{}, expire int) {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取指定键名的值
|
||||
// Get returns the value of <key>.
|
||||
// It returns nil if it does not exist or its value is nil.
|
||||
func (c *memCache) Get(key interface{}) interface{} {
|
||||
c.dataMu.RLock()
|
||||
item, ok := c.data[key]
|
||||
c.dataMu.RUnlock()
|
||||
if ok && !item.IsExpired() {
|
||||
// 增加LRU(Least Recently Used)操作记录
|
||||
// Adding to LRU history if LRU feature is enbaled.
|
||||
if c.cap > 0 {
|
||||
c.lruGetList.PushBack(key)
|
||||
}
|
||||
@ -172,7 +181,10 @@ func (c *memCache) Get(key interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 当键名存在时返回其键值,否则写入指定的键值
|
||||
// GetOrSet returns the value of <key>,
|
||||
// or sets <key>-<value> pair and returns <value> if <key> does not exist in the cache.
|
||||
// The key-value pair expires after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
func (c *memCache) GetOrSet(key interface{}, value interface{}, expire int) interface{} {
|
||||
if v := c.Get(key); v == nil {
|
||||
return c.doSetWithLockCheck(key, value, expire)
|
||||
@ -181,17 +193,26 @@ func (c *memCache) GetOrSet(key interface{}, value interface{}, expire int) inte
|
||||
}
|
||||
}
|
||||
|
||||
// 当键名存在时返回其键值,否则写入指定的键值,键值由指定的函数生成
|
||||
// GetOrSetFunc returns the value of <key>,
|
||||
// or sets <key> with result of function <f> and returns its result
|
||||
// if <key> does not exist in the cache.
|
||||
// The key-value pair expires after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
func (c *memCache) GetOrSetFunc(key interface{}, f func() interface{}, expire int) interface{} {
|
||||
if v := c.Get(key); v == nil {
|
||||
// 可能存在多个goroutine被阻塞在这里,f可能是并发运行
|
||||
return c.doSetWithLockCheck(key, f(), expire)
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// 与GetOrSetFunc不同的是,f是在写锁机制内执行
|
||||
// GetOrSetFuncLock returns the value of <key>,
|
||||
// or sets <key> with result of function <f> and returns its result
|
||||
// if <key> does not exist in the cache.
|
||||
// The key-value pair expires after <expire> milliseconds.
|
||||
// If <expire> <=0 means it does not expire.
|
||||
//
|
||||
// Note that the function <f> is executed within writing mutex lock.
|
||||
func (c *memCache) GetOrSetFuncLock(key interface{}, f func() interface{}, expire int) interface{} {
|
||||
if v := c.Get(key); v == nil {
|
||||
return c.doSetWithLockCheck(key, f, expire)
|
||||
@ -200,12 +221,12 @@ func (c *memCache) GetOrSetFuncLock(key interface{}, f func() interface{}, expir
|
||||
}
|
||||
}
|
||||
|
||||
// 是否存在指定的键名,true表示存在,false表示不存在。
|
||||
// Contains returns true if <key> exists in the cache, or else returns false.
|
||||
func (c *memCache) Contains(key interface{}) bool {
|
||||
return c.Get(key) != nil
|
||||
}
|
||||
|
||||
// 删除指定键值对,并返回被删除的键值
|
||||
// Remove deletes the <key> in the cache, and returns its value.
|
||||
func (c *memCache) Remove(key interface{}) (value interface{}) {
|
||||
c.dataMu.RLock()
|
||||
item, ok := c.data[key]
|
||||
@ -220,14 +241,14 @@ func (c *memCache) Remove(key interface{}) (value interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
// 批量删除键值对,并返回被删除的键值对数据
|
||||
// Removes deletes <keys> in the cache.
|
||||
func (c *memCache) Removes(keys []interface{}) {
|
||||
for _, key := range keys {
|
||||
c.Remove(key)
|
||||
}
|
||||
}
|
||||
|
||||
// 返回缓存的所有数据键值对(不包含已过期数据)
|
||||
// Data returns a copy of all key-value pairs in the cache as map type.
|
||||
func (c *memCache) Data() map[interface{}]interface{} {
|
||||
m := make(map[interface{}]interface{})
|
||||
c.dataMu.RLock()
|
||||
@ -240,7 +261,7 @@ func (c *memCache) Data() map[interface{}]interface{} {
|
||||
return m
|
||||
}
|
||||
|
||||
// 获得所有的键名,组成数组返回
|
||||
// Keys returns all keys in the cache as slice.
|
||||
func (c *memCache) Keys() []interface{} {
|
||||
keys := make([]interface{}, 0)
|
||||
c.dataMu.RLock()
|
||||
@ -253,12 +274,12 @@ func (c *memCache) Keys() []interface{} {
|
||||
return keys
|
||||
}
|
||||
|
||||
// 获得所有的键名,组成字符串数组返回
|
||||
// KeyStrings returns all keys in the cache as string slice.
|
||||
func (c *memCache) KeyStrings() []string {
|
||||
return gconv.Strings(c.Keys())
|
||||
}
|
||||
|
||||
// 获得所有的值,组成数组返回
|
||||
// Values returns all values in the cache as slice.
|
||||
func (c *memCache) Values() []interface{} {
|
||||
values := make([]interface{}, 0)
|
||||
c.dataMu.RLock()
|
||||
@ -271,7 +292,7 @@ func (c *memCache) Values() []interface{} {
|
||||
return values
|
||||
}
|
||||
|
||||
// 获得缓存对象的键值对数量
|
||||
// Size returns the size of the cache.
|
||||
func (c *memCache) Size() (size int) {
|
||||
c.dataMu.RLock()
|
||||
size = len(c.data)
|
||||
@ -279,7 +300,7 @@ func (c *memCache) Size() (size int) {
|
||||
return
|
||||
}
|
||||
|
||||
// 删除缓存对象
|
||||
// Close closes the cache.
|
||||
func (c *memCache) Close() {
|
||||
if c.cap > 0 {
|
||||
c.lru.Close()
|
||||
@ -287,9 +308,10 @@ func (c *memCache) Close() {
|
||||
c.closed.Set(true)
|
||||
}
|
||||
|
||||
// 数据异步任务循环:
|
||||
// 1、将事件列表中的数据异步处理,并同步结果到expireTimes和expireSets属性中;
|
||||
// 2、清理过期键值对数据;
|
||||
// Asynchronous task loop:
|
||||
// 1. asynchronously process the data in the event list,
|
||||
// and synchronize the results to the <expireTimes> and <expireSets> properties.
|
||||
// 2. clean up the expired key-value pair data.
|
||||
func (c *memCache) syncEventAndClearExpired() {
|
||||
event := (*memCacheEvent)(nil)
|
||||
oldExpireTime := int64(0)
|
||||
@ -299,7 +321,7 @@ func (c *memCache) syncEventAndClearExpired() {
|
||||
return
|
||||
}
|
||||
// ========================
|
||||
// 数据同步处理
|
||||
// Data Synchronization.
|
||||
// ========================
|
||||
for {
|
||||
v := c.eventList.PopFront()
|
||||
@ -307,28 +329,28 @@ func (c *memCache) syncEventAndClearExpired() {
|
||||
break
|
||||
}
|
||||
event = v.(*memCacheEvent)
|
||||
// 获得旧的过期时间分组
|
||||
// Fetching the old expire set.
|
||||
c.expireTimeMu.RLock()
|
||||
oldExpireTime = c.expireTimes[event.k]
|
||||
c.expireTimeMu.RUnlock()
|
||||
// 计算新的过期时间分组
|
||||
// Calculating the new expire set.
|
||||
newExpireTime = c.makeExpireKey(event.e)
|
||||
if newExpireTime != oldExpireTime {
|
||||
c.getOrNewExpireSet(newExpireTime).Add(event.k)
|
||||
if oldExpireTime != 0 {
|
||||
c.getOrNewExpireSet(oldExpireTime).Remove(event.k)
|
||||
}
|
||||
// 重新设置对应键名的过期时间
|
||||
// Updating the expire time for <event.k>.
|
||||
c.expireTimeMu.Lock()
|
||||
c.expireTimes[event.k] = newExpireTime
|
||||
c.expireTimeMu.Unlock()
|
||||
}
|
||||
// 写入操作也会增加到LRU(Least Recently Used)操作记录
|
||||
// Adding the key the LRU history by writing operations.
|
||||
if c.cap > 0 {
|
||||
c.lru.Push(event.k)
|
||||
}
|
||||
}
|
||||
// 异步处理读取操作的LRU列表
|
||||
// Processing expired keys from LRU.
|
||||
if c.cap > 0 && c.lruGetList.Len() > 0 {
|
||||
for {
|
||||
if v := c.lruGetList.PopFront(); v != nil {
|
||||
@ -339,18 +361,18 @@ func (c *memCache) syncEventAndClearExpired() {
|
||||
}
|
||||
}
|
||||
// ========================
|
||||
// 缓存过期处理
|
||||
// Data Cleaning up.
|
||||
// ========================
|
||||
ek := c.makeExpireKey(gtime.Millisecond())
|
||||
eks := []int64{ek - 1000, ek - 2000, ek - 3000, ek - 4000, ek - 5000}
|
||||
for _, expireTime := range eks {
|
||||
if expireSet := c.getExpireSet(expireTime); expireSet != nil {
|
||||
// 遍历Set,执行数据过期删除
|
||||
// Iterating the set to delete all keys in it.
|
||||
expireSet.Iterator(func(key interface{}) bool {
|
||||
c.clearByKey(key)
|
||||
return true
|
||||
})
|
||||
// Set数据处理完之后删除该Set
|
||||
// Deleting the set after all of its keys are deleted.
|
||||
c.expireSetMu.Lock()
|
||||
delete(c.expireSets, expireTime)
|
||||
c.expireSetMu.Unlock()
|
||||
@ -358,22 +380,22 @@ func (c *memCache) syncEventAndClearExpired() {
|
||||
}
|
||||
}
|
||||
|
||||
// 删除对应键名的缓存数据
|
||||
// clearByKey deletes the key-value pair with given <key>.
|
||||
// The parameter <force> specifies whether doing this deleting forcely.
|
||||
func (c *memCache) clearByKey(key interface{}, force...bool) {
|
||||
// 删除缓存数据
|
||||
c.dataMu.Lock()
|
||||
// 删除核对,真正的过期才删除
|
||||
// Doubly check before really deleting it from cache.
|
||||
if item, ok := c.data[key]; (ok && item.IsExpired()) || (len(force) > 0 && force[0]) {
|
||||
delete(c.data, key)
|
||||
}
|
||||
c.dataMu.Unlock()
|
||||
|
||||
// 删除异步处理数据项
|
||||
// Deleting its expire time from <expireTimes>.
|
||||
c.expireTimeMu.Lock()
|
||||
delete(c.expireTimes, key)
|
||||
c.expireTimeMu.Unlock()
|
||||
|
||||
// 删除LRU管理对象中指定键名
|
||||
// Deleting it from LRU.
|
||||
if c.cap > 0 {
|
||||
c.lru.Remove(key)
|
||||
}
|
||||
|
@ -8,9 +8,10 @@ package gcache
|
||||
|
||||
import "github.com/gogf/gf/g/os/gtime"
|
||||
|
||||
// 判断缓存项是否已过期
|
||||
// IsExpired checks whether <item> is expired.
|
||||
func (item *memCacheItem) IsExpired() bool {
|
||||
// 注意这里应当包含等于,试想一下缓存时间只有最小粒度为1毫秒的情况
|
||||
// Note that it should use greater than or equal judgement here
|
||||
// imagining that the cache time is only 1 millisecond.
|
||||
if item.e >= gtime.Millisecond() {
|
||||
return false
|
||||
}
|
||||
|
@ -7,24 +7,24 @@
|
||||
package gcache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/container/glist"
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"github.com/gogf/gf/g/os/gtimer"
|
||||
"time"
|
||||
"github.com/gogf/gf/g/container/glist"
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"github.com/gogf/gf/g/os/gtimer"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LRU算法实现对象,底层双向链表使用了标准库的list.List
|
||||
// LRU cache object.
|
||||
// It uses list.List from stdlib for its underlying doubly linked list.
|
||||
type memCacheLru struct {
|
||||
cache *memCache // 所属Cache对象
|
||||
data *gmap.Map // 记录键名与链表中的位置项指针
|
||||
list *glist.List // 键名历史记录链表
|
||||
rawList *glist.List // 事件列表
|
||||
closed *gtype.Bool // 是否关闭
|
||||
cache *memCache // Parent cache object.
|
||||
data *gmap.Map // Key mapping to the item of the list.
|
||||
list *glist.List // Key list.
|
||||
rawList *glist.List // History for key adding.
|
||||
closed *gtype.Bool // Closed or not.
|
||||
}
|
||||
|
||||
// 创建LRU管理对象
|
||||
// newMemCacheLru creates and returns a new LRU object.
|
||||
func newMemCacheLru(cache *memCache) *memCacheLru {
|
||||
lru := &memCacheLru {
|
||||
cache : cache,
|
||||
@ -37,12 +37,12 @@ func newMemCacheLru(cache *memCache) *memCacheLru {
|
||||
return lru
|
||||
}
|
||||
|
||||
// 关闭LRU对象
|
||||
// Close closes the LRU object.
|
||||
func (lru *memCacheLru) Close() {
|
||||
lru.closed.Set(true)
|
||||
}
|
||||
|
||||
// 删除指定数据项
|
||||
// Remove deletes the <key> FROM <lru>.
|
||||
func (lru *memCacheLru) Remove(key interface{}) {
|
||||
if v := lru.data.Get(key); v != nil {
|
||||
lru.data.Remove(key)
|
||||
@ -50,17 +50,17 @@ func (lru *memCacheLru) Remove(key interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// 当前LRU数据大小
|
||||
// Size returns the size of <lru>.
|
||||
func (lru *memCacheLru) Size() int {
|
||||
return lru.data.Size()
|
||||
}
|
||||
|
||||
// 添加LRU数据项
|
||||
// Push pushes <key> to the tail of <lru>.
|
||||
func (lru *memCacheLru) Push(key interface{}) {
|
||||
lru.rawList.PushBack(key)
|
||||
}
|
||||
|
||||
// 从链表尾删除LRU数据项,并返回对应数据
|
||||
// Pop deletes and returns the key from tail of <lru>.
|
||||
func (lru *memCacheLru) Pop() interface{} {
|
||||
if v := lru.list.PopBack(); v != nil {
|
||||
lru.data.Remove(v)
|
||||
@ -69,34 +69,36 @@ func (lru *memCacheLru) Pop() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 从链表头打印LRU链表值
|
||||
func (lru *memCacheLru) Print() {
|
||||
for _, v := range lru.list.FrontAll() {
|
||||
fmt.Printf("%v ", v)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
// Print is used for test only.
|
||||
//func (lru *memCacheLru) Print() {
|
||||
// for _, v := range lru.list.FrontAll() {
|
||||
// fmt.Printf("%v ", v)
|
||||
// }
|
||||
// fmt.Println()
|
||||
//}
|
||||
|
||||
// 异步执行协程,将queue中的数据同步到list中
|
||||
// SyncAndClear synchronizes the keys from <rawList> to <list> and <data>
|
||||
// using Least Recently Used algorithm.
|
||||
func (lru *memCacheLru) SyncAndClear() {
|
||||
if lru.closed.Val() {
|
||||
gtimer.Exit()
|
||||
return
|
||||
}
|
||||
// 数据同步
|
||||
// Data synchronization.
|
||||
for {
|
||||
if v := lru.rawList.PopFront(); v != nil {
|
||||
// 删除对应链表项
|
||||
// Deleting the key from list.
|
||||
if v := lru.data.Get(v); v != nil {
|
||||
lru.list.Remove(v.(*glist.Element))
|
||||
}
|
||||
// 将数据插入到链表头,并记录对应的链表项到哈希表中,便于检索
|
||||
// Pushing key to the head of the list
|
||||
// and setting its list item to hash table for quick indexing.
|
||||
lru.data.Set(v, lru.list.PushFront(v))
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
// 数据清理
|
||||
// Data cleaning up.
|
||||
for i := lru.Size() - lru.cache.cap; i > 0; i-- {
|
||||
if s := lru.Pop(); s != nil {
|
||||
lru.cache.clearByKey(s, true)
|
||||
|
@ -40,7 +40,7 @@ type Config struct {
|
||||
}
|
||||
|
||||
// New returns a new configuration management object.
|
||||
// The param <file> specifies the default configuration file name for reading.
|
||||
// The parameter <file> specifies the default configuration file name for reading.
|
||||
func New(file...string) *Config {
|
||||
name := DEFAULT_CONFIG_FILE
|
||||
if len(file) > 0 {
|
||||
@ -57,7 +57,9 @@ func New(file...string) *Config {
|
||||
if gfile.Exists(envPath) {
|
||||
_ = c.SetPath(envPath)
|
||||
} else {
|
||||
glog.Errorf("Configuration directory path does not exist: %s", envPath)
|
||||
if errorPrint() {
|
||||
glog.Errorf("Configuration directory path does not exist: %s", envPath)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Dir path of working dir.
|
||||
@ -97,13 +99,15 @@ func (c *Config) filePath(file...string) (path string) {
|
||||
} else {
|
||||
buffer.WriteString(fmt.Sprintf("[gcfg] cannot find config file \"%s\" with no path set/add", name))
|
||||
}
|
||||
glog.Error(buffer.String())
|
||||
if errorPrint() {
|
||||
glog.Error(buffer.String())
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// SetPath sets the configuration directory path for file search.
|
||||
// The param <path> can be absolute or relative path,
|
||||
// The parameter <path> can be absolute or relative path,
|
||||
// but absolute path is strongly recommended.
|
||||
func (c *Config) SetPath(path string) error {
|
||||
// Absolute path.
|
||||
@ -133,13 +137,17 @@ func (c *Config) SetPath(path string) error {
|
||||
buffer.WriteString(fmt.Sprintf(`[gcfg] SetPath failed: path "%s" does not exist`, path))
|
||||
}
|
||||
err := errors.New(buffer.String())
|
||||
glog.Error(err)
|
||||
if errorPrint() {
|
||||
glog.Error(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
// Should be a directory.
|
||||
if !gfile.IsDir(realPath) {
|
||||
err := errors.New(fmt.Sprintf(`[gcfg] SetPath failed: path "%s" should be directory type`, path))
|
||||
glog.Error(err)
|
||||
if errorPrint() {
|
||||
glog.Error(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
// Repeated path check.
|
||||
@ -191,12 +199,16 @@ func (c *Config) AddPath(path string) error {
|
||||
buffer.WriteString(fmt.Sprintf(`[gcfg] AddPath failed: path "%s" does not exist`, path))
|
||||
}
|
||||
err := errors.New(buffer.String())
|
||||
glog.Error(err)
|
||||
if errorPrint() {
|
||||
glog.Error(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if !gfile.IsDir(realPath) {
|
||||
err := errors.New(fmt.Sprintf(`[gcfg] AddPath failed: path "%s" should be directory type`, path))
|
||||
glog.Error(err)
|
||||
if errorPrint() {
|
||||
glog.Error(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
// Repeated path check.
|
||||
@ -269,17 +281,19 @@ func (c *Config) getJson(file...string) *gjson.Json {
|
||||
// Add monitor for this configuration file,
|
||||
// any changes of this file will refresh its cache in Config object.
|
||||
if filePath != "" {
|
||||
gfsnotify.Add(filePath, func(event *gfsnotify.Event) {
|
||||
_, _ = gfsnotify.Add(filePath, func(event *gfsnotify.Event) {
|
||||
c.jsons.Remove(name)
|
||||
})
|
||||
}
|
||||
return j
|
||||
} else {
|
||||
if filePath != "" {
|
||||
glog.Criticalf(`[gcfg] Load config file "%s" failed: %s`, filePath, err.Error())
|
||||
} else {
|
||||
glog.Criticalf(`[gcfg] Load configuration failed: %s`, err.Error())
|
||||
}
|
||||
if errorPrint() {
|
||||
if filePath != "" {
|
||||
glog.Criticalf(`[gcfg] Load config file "%s" failed: %s`, filePath, err.Error())
|
||||
} else {
|
||||
glog.Criticalf(`[gcfg] Load configuration failed: %s`, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
22
g/os/gcfg/gcfg_error.go
Normal file
22
g/os/gcfg/gcfg_error.go
Normal file
@ -0,0 +1,22 @@
|
||||
// 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 gcfg
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/internal/cmdenv"
|
||||
)
|
||||
|
||||
const (
|
||||
// gERROR_PRINT_KEY is used to specify the key controlling error printing to stdout.
|
||||
// This error is designed not to be returned by functions.
|
||||
gERROR_PRINT_KEY = "gf.gcfg.errorprint"
|
||||
)
|
||||
|
||||
// errorPrint checks whether printing error to stdout.
|
||||
func errorPrint() bool {
|
||||
return cmdenv.Get(gERROR_PRINT_KEY, true).Bool()
|
||||
}
|
@ -20,7 +20,7 @@ var (
|
||||
)
|
||||
|
||||
// Instance returns an instance of Config with default settings.
|
||||
// The param <name> is the name for the instance.
|
||||
// The parameter <name> is the name for the instance.
|
||||
func Instance(name...string) *Config {
|
||||
key := DEFAULT_GROUP_NAME
|
||||
if len(name) > 0 {
|
||||
|
@ -9,14 +9,22 @@
|
||||
package gcfg_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/gcfg"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gjson"
|
||||
"github.com/gogf/gf/g/os/gcfg"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func init() {
|
||||
os.Setenv("GF_GCFG_ERRORPRINT", "false")
|
||||
}
|
||||
|
||||
func Test_Basic(t *testing.T) {
|
||||
config := `
|
||||
config := `
|
||||
v1 = 1
|
||||
v2 = "true"
|
||||
v3 = "off"
|
||||
@ -26,58 +34,58 @@ array = [1,2,3]
|
||||
disk = "127.0.0.1:6379,0"
|
||||
cache = "127.0.0.1:6379,1"
|
||||
`
|
||||
gtest.Case(t, func() {
|
||||
path := gcfg.DEFAULT_CONFIG_FILE
|
||||
err := gfile.PutContents(path, config)
|
||||
gtest.Assert(err, nil)
|
||||
defer gfile.Remove(path)
|
||||
gtest.Case(t, func() {
|
||||
path := gcfg.DEFAULT_CONFIG_FILE
|
||||
err := gfile.PutContents(path, config)
|
||||
gtest.Assert(err, nil)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
c := gcfg.New()
|
||||
gtest.Assert(c.Get("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt8("v1"), int8(1))
|
||||
gtest.AssertEQ(c.GetInt16("v1"), int16(1))
|
||||
gtest.AssertEQ(c.GetInt32("v1"), int32(1))
|
||||
gtest.AssertEQ(c.GetInt64("v1"), int64(1))
|
||||
gtest.AssertEQ(c.GetUint("v1"), uint(1))
|
||||
gtest.AssertEQ(c.GetUint8("v1"), uint8(1))
|
||||
gtest.AssertEQ(c.GetUint16("v1"), uint16(1))
|
||||
gtest.AssertEQ(c.GetUint32("v1"), uint32(1))
|
||||
gtest.AssertEQ(c.GetUint64("v1"), uint64(1))
|
||||
c := gcfg.New()
|
||||
gtest.Assert(c.Get("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt8("v1"), int8(1))
|
||||
gtest.AssertEQ(c.GetInt16("v1"), int16(1))
|
||||
gtest.AssertEQ(c.GetInt32("v1"), int32(1))
|
||||
gtest.AssertEQ(c.GetInt64("v1"), int64(1))
|
||||
gtest.AssertEQ(c.GetUint("v1"), uint(1))
|
||||
gtest.AssertEQ(c.GetUint8("v1"), uint8(1))
|
||||
gtest.AssertEQ(c.GetUint16("v1"), uint16(1))
|
||||
gtest.AssertEQ(c.GetUint32("v1"), uint32(1))
|
||||
gtest.AssertEQ(c.GetUint64("v1"), uint64(1))
|
||||
|
||||
gtest.AssertEQ(c.GetVar("v1").String(), "1")
|
||||
gtest.AssertEQ(c.GetVar("v1").Bool(), true)
|
||||
gtest.AssertEQ(c.GetVar("v2").String(), "true")
|
||||
gtest.AssertEQ(c.GetVar("v2").Bool(), true)
|
||||
gtest.AssertEQ(c.GetVar("v1").String(), "1")
|
||||
gtest.AssertEQ(c.GetVar("v1").Bool(), true)
|
||||
gtest.AssertEQ(c.GetVar("v2").String(), "true")
|
||||
gtest.AssertEQ(c.GetVar("v2").Bool(), true)
|
||||
|
||||
gtest.AssertEQ(c.GetString("v1"), "1")
|
||||
gtest.AssertEQ(c.GetFloat32("v4"), float32(1.23))
|
||||
gtest.AssertEQ(c.GetFloat64("v4"), float64(1.23))
|
||||
gtest.AssertEQ(c.GetString("v2"), "true")
|
||||
gtest.AssertEQ(c.GetBool("v2"), true)
|
||||
gtest.AssertEQ(c.GetBool("v3"), false)
|
||||
gtest.AssertEQ(c.GetString("v1"), "1")
|
||||
gtest.AssertEQ(c.GetFloat32("v4"), float32(1.23))
|
||||
gtest.AssertEQ(c.GetFloat64("v4"), float64(1.23))
|
||||
gtest.AssertEQ(c.GetString("v2"), "true")
|
||||
gtest.AssertEQ(c.GetBool("v2"), true)
|
||||
gtest.AssertEQ(c.GetBool("v3"), false)
|
||||
|
||||
gtest.AssertEQ(c.Contains("v1"), true)
|
||||
gtest.AssertEQ(c.Contains("v2"), true)
|
||||
gtest.AssertEQ(c.Contains("v3"), true)
|
||||
gtest.AssertEQ(c.Contains("v4"), true)
|
||||
gtest.AssertEQ(c.Contains("v5"), false)
|
||||
gtest.AssertEQ(c.Contains("v1"), true)
|
||||
gtest.AssertEQ(c.Contains("v2"), true)
|
||||
gtest.AssertEQ(c.Contains("v3"), true)
|
||||
gtest.AssertEQ(c.Contains("v4"), true)
|
||||
gtest.AssertEQ(c.Contains("v5"), false)
|
||||
|
||||
gtest.AssertEQ(c.GetInts("array"), []int{1,2,3})
|
||||
gtest.AssertEQ(c.GetStrings("array"), []string{"1","2","3"})
|
||||
gtest.AssertEQ(c.GetArray("array"), []interface{}{"1","2","3"})
|
||||
gtest.AssertEQ(c.GetInterfaces("array"), []interface{}{"1","2","3"})
|
||||
gtest.AssertEQ(c.GetMap("redis"), map[string]interface{}{
|
||||
"disk" : "127.0.0.1:6379,0",
|
||||
"cache" : "127.0.0.1:6379,1",
|
||||
})
|
||||
gtest.AssertEQ(c.FilePath(), gfile.Pwd() + gfile.Separator + path)
|
||||
gtest.AssertEQ(c.GetInts("array"), []int{1, 2, 3})
|
||||
gtest.AssertEQ(c.GetStrings("array"), []string{"1", "2", "3"})
|
||||
gtest.AssertEQ(c.GetArray("array"), []interface{}{"1", "2", "3"})
|
||||
gtest.AssertEQ(c.GetInterfaces("array"), []interface{}{"1", "2", "3"})
|
||||
gtest.AssertEQ(c.GetMap("redis"), map[string]interface{}{
|
||||
"disk": "127.0.0.1:6379,0",
|
||||
"cache": "127.0.0.1:6379,1",
|
||||
})
|
||||
gtest.AssertEQ(c.FilePath(), gfile.Pwd()+gfile.Separator+path)
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Content(t *testing.T) {
|
||||
content := `
|
||||
content := `
|
||||
v1 = 1
|
||||
v2 = "true"
|
||||
v3 = "off"
|
||||
@ -87,54 +95,54 @@ array = [1,2,3]
|
||||
disk = "127.0.0.1:6379,0"
|
||||
cache = "127.0.0.1:6379,1"
|
||||
`
|
||||
gcfg.SetContent(content)
|
||||
defer gcfg.ClearContent()
|
||||
gcfg.SetContent(content)
|
||||
defer gcfg.ClearContent()
|
||||
|
||||
gtest.Case(t, func() {
|
||||
c := gcfg.New()
|
||||
gtest.Assert(c.Get("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt8("v1"), int8(1))
|
||||
gtest.AssertEQ(c.GetInt16("v1"), int16(1))
|
||||
gtest.AssertEQ(c.GetInt32("v1"), int32(1))
|
||||
gtest.AssertEQ(c.GetInt64("v1"), int64(1))
|
||||
gtest.AssertEQ(c.GetUint("v1"), uint(1))
|
||||
gtest.AssertEQ(c.GetUint8("v1"), uint8(1))
|
||||
gtest.AssertEQ(c.GetUint16("v1"), uint16(1))
|
||||
gtest.AssertEQ(c.GetUint32("v1"), uint32(1))
|
||||
gtest.AssertEQ(c.GetUint64("v1"), uint64(1))
|
||||
gtest.Case(t, func() {
|
||||
c := gcfg.New()
|
||||
gtest.Assert(c.Get("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt8("v1"), int8(1))
|
||||
gtest.AssertEQ(c.GetInt16("v1"), int16(1))
|
||||
gtest.AssertEQ(c.GetInt32("v1"), int32(1))
|
||||
gtest.AssertEQ(c.GetInt64("v1"), int64(1))
|
||||
gtest.AssertEQ(c.GetUint("v1"), uint(1))
|
||||
gtest.AssertEQ(c.GetUint8("v1"), uint8(1))
|
||||
gtest.AssertEQ(c.GetUint16("v1"), uint16(1))
|
||||
gtest.AssertEQ(c.GetUint32("v1"), uint32(1))
|
||||
gtest.AssertEQ(c.GetUint64("v1"), uint64(1))
|
||||
|
||||
gtest.AssertEQ(c.GetVar("v1").String(), "1")
|
||||
gtest.AssertEQ(c.GetVar("v1").Bool(), true)
|
||||
gtest.AssertEQ(c.GetVar("v2").String(), "true")
|
||||
gtest.AssertEQ(c.GetVar("v2").Bool(), true)
|
||||
gtest.AssertEQ(c.GetVar("v1").String(), "1")
|
||||
gtest.AssertEQ(c.GetVar("v1").Bool(), true)
|
||||
gtest.AssertEQ(c.GetVar("v2").String(), "true")
|
||||
gtest.AssertEQ(c.GetVar("v2").Bool(), true)
|
||||
|
||||
gtest.AssertEQ(c.GetString("v1"), "1")
|
||||
gtest.AssertEQ(c.GetFloat32("v4"), float32(1.23))
|
||||
gtest.AssertEQ(c.GetFloat64("v4"), float64(1.23))
|
||||
gtest.AssertEQ(c.GetString("v2"), "true")
|
||||
gtest.AssertEQ(c.GetBool("v2"), true)
|
||||
gtest.AssertEQ(c.GetBool("v3"), false)
|
||||
gtest.AssertEQ(c.GetString("v1"), "1")
|
||||
gtest.AssertEQ(c.GetFloat32("v4"), float32(1.23))
|
||||
gtest.AssertEQ(c.GetFloat64("v4"), float64(1.23))
|
||||
gtest.AssertEQ(c.GetString("v2"), "true")
|
||||
gtest.AssertEQ(c.GetBool("v2"), true)
|
||||
gtest.AssertEQ(c.GetBool("v3"), false)
|
||||
|
||||
gtest.AssertEQ(c.Contains("v1"), true)
|
||||
gtest.AssertEQ(c.Contains("v2"), true)
|
||||
gtest.AssertEQ(c.Contains("v3"), true)
|
||||
gtest.AssertEQ(c.Contains("v4"), true)
|
||||
gtest.AssertEQ(c.Contains("v5"), false)
|
||||
gtest.AssertEQ(c.Contains("v1"), true)
|
||||
gtest.AssertEQ(c.Contains("v2"), true)
|
||||
gtest.AssertEQ(c.Contains("v3"), true)
|
||||
gtest.AssertEQ(c.Contains("v4"), true)
|
||||
gtest.AssertEQ(c.Contains("v5"), false)
|
||||
|
||||
gtest.AssertEQ(c.GetInts("array"), []int{1,2,3})
|
||||
gtest.AssertEQ(c.GetStrings("array"), []string{"1","2","3"})
|
||||
gtest.AssertEQ(c.GetArray("array"), []interface{}{"1","2","3"})
|
||||
gtest.AssertEQ(c.GetInterfaces("array"), []interface{}{"1","2","3"})
|
||||
gtest.AssertEQ(c.GetMap("redis"), map[string]interface{}{
|
||||
"disk" : "127.0.0.1:6379,0",
|
||||
"cache" : "127.0.0.1:6379,1",
|
||||
})
|
||||
})
|
||||
gtest.AssertEQ(c.GetInts("array"), []int{1, 2, 3})
|
||||
gtest.AssertEQ(c.GetStrings("array"), []string{"1", "2", "3"})
|
||||
gtest.AssertEQ(c.GetArray("array"), []interface{}{"1", "2", "3"})
|
||||
gtest.AssertEQ(c.GetInterfaces("array"), []interface{}{"1", "2", "3"})
|
||||
gtest.AssertEQ(c.GetMap("redis"), map[string]interface{}{
|
||||
"disk": "127.0.0.1:6379,0",
|
||||
"cache": "127.0.0.1:6379,1",
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SetFileName(t *testing.T) {
|
||||
config := `
|
||||
config := `
|
||||
{
|
||||
"array": [
|
||||
1,
|
||||
@ -151,59 +159,59 @@ func Test_SetFileName(t *testing.T) {
|
||||
"v4": "1.234"
|
||||
}
|
||||
`
|
||||
gtest.Case(t, func() {
|
||||
path := "config.json"
|
||||
err := gfile.PutContents(path, config)
|
||||
gtest.Assert(err, nil)
|
||||
defer gfile.Remove(path)
|
||||
gtest.Case(t, func() {
|
||||
path := "config.json"
|
||||
err := gfile.PutContents(path, config)
|
||||
gtest.Assert(err, nil)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
c := gcfg.New()
|
||||
c.SetFileName(path)
|
||||
gtest.Assert(c.Get("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt8("v1"), int8(1))
|
||||
gtest.AssertEQ(c.GetInt16("v1"), int16(1))
|
||||
gtest.AssertEQ(c.GetInt32("v1"), int32(1))
|
||||
gtest.AssertEQ(c.GetInt64("v1"), int64(1))
|
||||
gtest.AssertEQ(c.GetUint("v1"), uint(1))
|
||||
gtest.AssertEQ(c.GetUint8("v1"), uint8(1))
|
||||
gtest.AssertEQ(c.GetUint16("v1"), uint16(1))
|
||||
gtest.AssertEQ(c.GetUint32("v1"), uint32(1))
|
||||
gtest.AssertEQ(c.GetUint64("v1"), uint64(1))
|
||||
c := gcfg.New()
|
||||
c.SetFileName(path)
|
||||
gtest.Assert(c.Get("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt8("v1"), int8(1))
|
||||
gtest.AssertEQ(c.GetInt16("v1"), int16(1))
|
||||
gtest.AssertEQ(c.GetInt32("v1"), int32(1))
|
||||
gtest.AssertEQ(c.GetInt64("v1"), int64(1))
|
||||
gtest.AssertEQ(c.GetUint("v1"), uint(1))
|
||||
gtest.AssertEQ(c.GetUint8("v1"), uint8(1))
|
||||
gtest.AssertEQ(c.GetUint16("v1"), uint16(1))
|
||||
gtest.AssertEQ(c.GetUint32("v1"), uint32(1))
|
||||
gtest.AssertEQ(c.GetUint64("v1"), uint64(1))
|
||||
|
||||
gtest.AssertEQ(c.GetVar("v1").String(), "1")
|
||||
gtest.AssertEQ(c.GetVar("v1").Bool(), true)
|
||||
gtest.AssertEQ(c.GetVar("v2").String(), "true")
|
||||
gtest.AssertEQ(c.GetVar("v2").Bool(), true)
|
||||
gtest.AssertEQ(c.GetVar("v1").String(), "1")
|
||||
gtest.AssertEQ(c.GetVar("v1").Bool(), true)
|
||||
gtest.AssertEQ(c.GetVar("v2").String(), "true")
|
||||
gtest.AssertEQ(c.GetVar("v2").Bool(), true)
|
||||
|
||||
gtest.AssertEQ(c.GetString("v1"), "1")
|
||||
gtest.AssertEQ(c.GetFloat32("v4"), float32(1.234))
|
||||
gtest.AssertEQ(c.GetFloat64("v4"), float64(1.234))
|
||||
gtest.AssertEQ(c.GetString("v2"), "true")
|
||||
gtest.AssertEQ(c.GetBool("v2"), true)
|
||||
gtest.AssertEQ(c.GetBool("v3"), false)
|
||||
gtest.AssertEQ(c.GetString("v1"), "1")
|
||||
gtest.AssertEQ(c.GetFloat32("v4"), float32(1.234))
|
||||
gtest.AssertEQ(c.GetFloat64("v4"), float64(1.234))
|
||||
gtest.AssertEQ(c.GetString("v2"), "true")
|
||||
gtest.AssertEQ(c.GetBool("v2"), true)
|
||||
gtest.AssertEQ(c.GetBool("v3"), false)
|
||||
|
||||
gtest.AssertEQ(c.Contains("v1"), true)
|
||||
gtest.AssertEQ(c.Contains("v2"), true)
|
||||
gtest.AssertEQ(c.Contains("v3"), true)
|
||||
gtest.AssertEQ(c.Contains("v4"), true)
|
||||
gtest.AssertEQ(c.Contains("v5"), false)
|
||||
gtest.AssertEQ(c.Contains("v1"), true)
|
||||
gtest.AssertEQ(c.Contains("v2"), true)
|
||||
gtest.AssertEQ(c.Contains("v3"), true)
|
||||
gtest.AssertEQ(c.Contains("v4"), true)
|
||||
gtest.AssertEQ(c.Contains("v5"), false)
|
||||
|
||||
gtest.AssertEQ(c.GetInts("array"), []int{1,2,3})
|
||||
gtest.AssertEQ(c.GetStrings("array"), []string{"1","2","3"})
|
||||
gtest.AssertEQ(c.GetArray("array"), []interface{}{"1","2","3"})
|
||||
gtest.AssertEQ(c.GetInterfaces("array"), []interface{}{"1","2","3"})
|
||||
gtest.AssertEQ(c.GetMap("redis"), map[string]interface{}{
|
||||
"disk" : "127.0.0.1:6379,0",
|
||||
"cache" : "127.0.0.1:6379,1",
|
||||
})
|
||||
gtest.AssertEQ(c.FilePath(), gfile.Pwd() + gfile.Separator + path)
|
||||
gtest.AssertEQ(c.GetInts("array"), []int{1, 2, 3})
|
||||
gtest.AssertEQ(c.GetStrings("array"), []string{"1", "2", "3"})
|
||||
gtest.AssertEQ(c.GetArray("array"), []interface{}{"1", "2", "3"})
|
||||
gtest.AssertEQ(c.GetInterfaces("array"), []interface{}{"1", "2", "3"})
|
||||
gtest.AssertEQ(c.GetMap("redis"), map[string]interface{}{
|
||||
"disk": "127.0.0.1:6379,0",
|
||||
"cache": "127.0.0.1:6379,1",
|
||||
})
|
||||
gtest.AssertEQ(c.FilePath(), gfile.Pwd()+gfile.Separator+path)
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Instance(t *testing.T) {
|
||||
config := `
|
||||
config := `
|
||||
{
|
||||
"array": [
|
||||
1,
|
||||
@ -220,52 +228,183 @@ func Test_Instance(t *testing.T) {
|
||||
"v4": "1.234"
|
||||
}
|
||||
`
|
||||
gtest.Case(t, func() {
|
||||
path := gcfg.DEFAULT_CONFIG_FILE
|
||||
err := gfile.PutContents(path, config)
|
||||
gtest.Assert(err, nil)
|
||||
defer gfile.Remove(path)
|
||||
gtest.Case(t, func() {
|
||||
path := gcfg.DEFAULT_CONFIG_FILE
|
||||
err := gfile.PutContents(path, config)
|
||||
gtest.Assert(err, nil)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
c := gcfg.Instance()
|
||||
gtest.Assert(c.Get("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt8("v1"), int8(1))
|
||||
gtest.AssertEQ(c.GetInt16("v1"), int16(1))
|
||||
gtest.AssertEQ(c.GetInt32("v1"), int32(1))
|
||||
gtest.AssertEQ(c.GetInt64("v1"), int64(1))
|
||||
gtest.AssertEQ(c.GetUint("v1"), uint(1))
|
||||
gtest.AssertEQ(c.GetUint8("v1"), uint8(1))
|
||||
gtest.AssertEQ(c.GetUint16("v1"), uint16(1))
|
||||
gtest.AssertEQ(c.GetUint32("v1"), uint32(1))
|
||||
gtest.AssertEQ(c.GetUint64("v1"), uint64(1))
|
||||
c := gcfg.Instance()
|
||||
gtest.Assert(c.Get("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt("v1"), 1)
|
||||
gtest.AssertEQ(c.GetInt8("v1"), int8(1))
|
||||
gtest.AssertEQ(c.GetInt16("v1"), int16(1))
|
||||
gtest.AssertEQ(c.GetInt32("v1"), int32(1))
|
||||
gtest.AssertEQ(c.GetInt64("v1"), int64(1))
|
||||
gtest.AssertEQ(c.GetUint("v1"), uint(1))
|
||||
gtest.AssertEQ(c.GetUint8("v1"), uint8(1))
|
||||
gtest.AssertEQ(c.GetUint16("v1"), uint16(1))
|
||||
gtest.AssertEQ(c.GetUint32("v1"), uint32(1))
|
||||
gtest.AssertEQ(c.GetUint64("v1"), uint64(1))
|
||||
|
||||
gtest.AssertEQ(c.GetVar("v1").String(), "1")
|
||||
gtest.AssertEQ(c.GetVar("v1").Bool(), true)
|
||||
gtest.AssertEQ(c.GetVar("v2").String(), "true")
|
||||
gtest.AssertEQ(c.GetVar("v2").Bool(), true)
|
||||
gtest.AssertEQ(c.GetVar("v1").String(), "1")
|
||||
gtest.AssertEQ(c.GetVar("v1").Bool(), true)
|
||||
gtest.AssertEQ(c.GetVar("v2").String(), "true")
|
||||
gtest.AssertEQ(c.GetVar("v2").Bool(), true)
|
||||
|
||||
gtest.AssertEQ(c.GetString("v1"), "1")
|
||||
gtest.AssertEQ(c.GetFloat32("v4"), float32(1.234))
|
||||
gtest.AssertEQ(c.GetFloat64("v4"), float64(1.234))
|
||||
gtest.AssertEQ(c.GetString("v2"), "true")
|
||||
gtest.AssertEQ(c.GetBool("v2"), true)
|
||||
gtest.AssertEQ(c.GetBool("v3"), false)
|
||||
gtest.AssertEQ(c.GetString("v1"), "1")
|
||||
gtest.AssertEQ(c.GetFloat32("v4"), float32(1.234))
|
||||
gtest.AssertEQ(c.GetFloat64("v4"), float64(1.234))
|
||||
gtest.AssertEQ(c.GetString("v2"), "true")
|
||||
gtest.AssertEQ(c.GetBool("v2"), true)
|
||||
gtest.AssertEQ(c.GetBool("v3"), false)
|
||||
|
||||
gtest.AssertEQ(c.Contains("v1"), true)
|
||||
gtest.AssertEQ(c.Contains("v2"), true)
|
||||
gtest.AssertEQ(c.Contains("v3"), true)
|
||||
gtest.AssertEQ(c.Contains("v4"), true)
|
||||
gtest.AssertEQ(c.Contains("v5"), false)
|
||||
gtest.AssertEQ(c.Contains("v1"), true)
|
||||
gtest.AssertEQ(c.Contains("v2"), true)
|
||||
gtest.AssertEQ(c.Contains("v3"), true)
|
||||
gtest.AssertEQ(c.Contains("v4"), true)
|
||||
gtest.AssertEQ(c.Contains("v5"), false)
|
||||
|
||||
gtest.AssertEQ(c.GetInts("array"), []int{1,2,3})
|
||||
gtest.AssertEQ(c.GetStrings("array"), []string{"1","2","3"})
|
||||
gtest.AssertEQ(c.GetArray("array"), []interface{}{"1","2","3"})
|
||||
gtest.AssertEQ(c.GetInterfaces("array"), []interface{}{"1","2","3"})
|
||||
gtest.AssertEQ(c.GetMap("redis"), map[string]interface{}{
|
||||
"disk" : "127.0.0.1:6379,0",
|
||||
"cache" : "127.0.0.1:6379,1",
|
||||
})
|
||||
gtest.AssertEQ(c.FilePath(), gfile.Pwd() + gfile.Separator + path)
|
||||
gtest.AssertEQ(c.GetInts("array"), []int{1, 2, 3})
|
||||
gtest.AssertEQ(c.GetStrings("array"), []string{"1", "2", "3"})
|
||||
gtest.AssertEQ(c.GetArray("array"), []interface{}{"1", "2", "3"})
|
||||
gtest.AssertEQ(c.GetInterfaces("array"), []interface{}{"1", "2", "3"})
|
||||
gtest.AssertEQ(c.GetMap("redis"), map[string]interface{}{
|
||||
"disk": "127.0.0.1:6379,0",
|
||||
"cache": "127.0.0.1:6379,1",
|
||||
})
|
||||
gtest.AssertEQ(c.FilePath(), gfile.Pwd()+gfile.Separator+path)
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCfg_New(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
os.Setenv("GF_GCFG_PATH", "config")
|
||||
c := gcfg.New("config.yml")
|
||||
gtest.Assert(c.Get("name"), nil)
|
||||
gtest.Assert(c.GetFileName(), "config.yml")
|
||||
|
||||
configPath := gfile.Pwd() + gfile.Separator + "config"
|
||||
gfile.Mkdir(configPath)
|
||||
defer gfile.Remove(configPath)
|
||||
c = gcfg.New("config.yml")
|
||||
gtest.Assert(c.Get("name"), nil)
|
||||
|
||||
os.Unsetenv("GF_GCFG_PATH")
|
||||
c = gcfg.New("config.yml")
|
||||
gtest.Assert(c.Get("name"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCfg_SetPath(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
c := gcfg.New("config.yml")
|
||||
err := c.SetPath("tmp")
|
||||
gtest.AssertNE(err, nil)
|
||||
err = c.SetPath("gcfg.go")
|
||||
gtest.AssertNE(err, nil)
|
||||
gtest.Assert(c.Get("name"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCfg_SetViolenceCheck(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
c := gcfg.New("config.yml")
|
||||
c.SetViolenceCheck(true)
|
||||
gtest.Assert(c.Get("name"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCfg_AddPath(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
c := gcfg.New("config.yml")
|
||||
err := c.AddPath("tmp")
|
||||
gtest.AssertNE(err, nil)
|
||||
err = c.AddPath("gcfg.go")
|
||||
gtest.AssertNE(err, nil)
|
||||
gtest.Assert(c.Get("name"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCfg_FilePath(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
c := gcfg.New("config.yml")
|
||||
path := c.FilePath("tmp")
|
||||
gtest.Assert(path, "")
|
||||
path = c.GetFilePath("tmp")
|
||||
gtest.Assert(path, "")
|
||||
})
|
||||
}
|
||||
|
||||
func TestCfg_Get(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
configPath := gfile.Pwd() + gfile.Separator + "config"
|
||||
gfile.Mkdir(configPath)
|
||||
defer gfile.Remove(configPath)
|
||||
ioutil.WriteFile(configPath+gfile.Separator+"config.yml", []byte("wrong config"), 0644)
|
||||
c := gcfg.New("config.yml")
|
||||
gtest.Assert(c.Get("name"), nil)
|
||||
gtest.Assert(c.GetVar("name").Val(), nil)
|
||||
gtest.Assert(c.Contains("name"), false)
|
||||
gtest.Assert(c.GetMap("name"), nil)
|
||||
gtest.Assert(c.GetArray("name"), nil)
|
||||
gtest.Assert(c.GetString("name"), "")
|
||||
gtest.Assert(c.GetStrings("name"), nil)
|
||||
gtest.Assert(c.GetInterfaces("name"), nil)
|
||||
gtest.Assert(c.GetBool("name"), false)
|
||||
gtest.Assert(c.GetFloat32("name"), 0)
|
||||
gtest.Assert(c.GetFloat64("name"), 0)
|
||||
gtest.Assert(c.GetFloats("name"), nil)
|
||||
gtest.Assert(c.GetInt("name"), 0)
|
||||
gtest.Assert(c.GetInt8("name"), 0)
|
||||
gtest.Assert(c.GetInt16("name"), 0)
|
||||
gtest.Assert(c.GetInt32("name"), 0)
|
||||
gtest.Assert(c.GetInt64("name"), 0)
|
||||
gtest.Assert(c.GetInts("name"), nil)
|
||||
gtest.Assert(c.GetUint("name"), 0)
|
||||
gtest.Assert(c.GetUint8("name"), 0)
|
||||
gtest.Assert(c.GetUint16("name"), 0)
|
||||
gtest.Assert(c.GetUint32("name"), 0)
|
||||
gtest.Assert(c.GetUint64("name"), 0)
|
||||
gtest.Assert(c.GetTime("name").Format("2006-01-02"), "0001-01-01")
|
||||
gtest.Assert(c.GetGTime("name"), nil)
|
||||
gtest.Assert(c.GetDuration("name").String(), "0s")
|
||||
name := struct {
|
||||
Name string
|
||||
}{}
|
||||
gtest.Assert(c.GetToStruct("name", &name) == nil, false)
|
||||
|
||||
c.Reload()
|
||||
c.Clear()
|
||||
|
||||
arr, _ := gjson.Encode(g.Map{"name": "gf", "time": "2019-06-12", "person": g.Map{"name": "gf"}, "floats": g.Slice{1, 2, 3}})
|
||||
ioutil.WriteFile(configPath+gfile.Separator+"config.yml", arr, 0644)
|
||||
gtest.Assert(c.GetTime("time").Format("2006-01-02"), "2019-06-12")
|
||||
gtest.Assert(c.GetGTime("time").Format("Y-m-d"), "2019-06-12")
|
||||
gtest.Assert(c.GetDuration("time").String(), "0s")
|
||||
//t.Log(c.GetString("person"))
|
||||
err := c.GetToStruct("person", &name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(name.Name, "gf")
|
||||
gtest.Assert(c.GetFloats("floats") == nil, false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCfg_Instance(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gcfg.Instance("gf") != nil, true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCfg_Config(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
gcfg.SetContent("gf", "config.yml")
|
||||
gtest.Assert(gcfg.GetContent("config.yml"), "gf")
|
||||
gcfg.SetContent("gf1", "config.yml")
|
||||
gtest.Assert(gcfg.GetContent("config.yml"), "gf1")
|
||||
gcfg.RemoveConfig("config.yml")
|
||||
gcfg.ClearContent()
|
||||
gtest.Assert(gcfg.GetContent("name"), "")
|
||||
})
|
||||
}
|
||||
|
@ -24,13 +24,19 @@ type gCmdOption struct {
|
||||
options map[string]string
|
||||
}
|
||||
|
||||
var Value = &gCmdValue{} // Console values.
|
||||
var Option = &gCmdOption{} // Console options.
|
||||
var Value = &gCmdValue{} // Console values.
|
||||
var Option = &gCmdOption{} // Console options.
|
||||
var cmdFuncMap = make(map[string]func()) // Registered callback functions.
|
||||
|
||||
func init() {
|
||||
reg := regexp.MustCompile(`\-\-{0,1}(.+?)=(.+)`)
|
||||
doInit()
|
||||
}
|
||||
|
||||
// doInit does the initialization for this package.
|
||||
func doInit() {
|
||||
Value.values = Value.values[:0]
|
||||
Option.options = make(map[string]string)
|
||||
reg := regexp.MustCompile(`\-\-{0,1}(.+?)=(.+)`)
|
||||
for i := 0; i < len(os.Args); i++ {
|
||||
result := reg.FindStringSubmatch(os.Args[i])
|
||||
if len(result) > 1 {
|
||||
|
28
g/os/gcmd/gcmd_z_unit_test.go
Normal file
28
g/os/gcmd/gcmd_z_unit_test.go
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
// go test *.go -bench=".*" -benchmem
|
||||
|
||||
package gcmd
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
||||
func Test_ValueAndOption(t *testing.T) {
|
||||
os.Args = []string{"v1", "v2", "--o1=111", "-o2=222"}
|
||||
doInit()
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(Value.GetAll(), []string{"v1", "v2"})
|
||||
gtest.Assert(Value.Get(0), "v1")
|
||||
gtest.Assert(Value.Get(1), "v2")
|
||||
gtest.Assert(Value.Get(2), "")
|
||||
})
|
||||
}
|
||||
|
@ -5,29 +5,33 @@
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package genv provides operations for environment variables of system.
|
||||
//
|
||||
// 环境变量管理
|
||||
package genv
|
||||
|
||||
import "os"
|
||||
|
||||
// All returns a copy of strings representing the environment,
|
||||
// in the form "key=value".
|
||||
func All() []string {
|
||||
return os.Environ()
|
||||
}
|
||||
|
||||
// 获取环境变量,并可以指定当环境变量不存在时的默认值
|
||||
func Get(k string, def...string) string {
|
||||
v, ok := os.LookupEnv(k)
|
||||
// Get returns the value of the environment variable named by the <key>.
|
||||
// It returns given <def> if the variable does not exist in the environment.
|
||||
func Get(key string, def...string) string {
|
||||
v, ok := os.LookupEnv(key)
|
||||
if !ok && len(def) > 0 {
|
||||
return def[0]
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func Set(k, v string) error {
|
||||
return os.Setenv(k, v)
|
||||
// Set sets the value of the environment variable named by the <key>.
|
||||
// It returns an error, if any.
|
||||
func Set(key, value string) error {
|
||||
return os.Setenv(key, value)
|
||||
}
|
||||
|
||||
func Remove(k string) error {
|
||||
return os.Unsetenv(k)
|
||||
// Remove deletes a single environment variable.
|
||||
func Remove(key string) error {
|
||||
return os.Unsetenv(key)
|
||||
}
|
@ -5,8 +5,6 @@
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gfcache provides reading and caching for file contents.
|
||||
//
|
||||
// 文件缓存.
|
||||
package gfcache
|
||||
|
||||
import (
|
||||
@ -17,21 +15,25 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// 默认的缓存超时时间(60秒)
|
||||
// Default expire time for file content caching in seconds.
|
||||
gDEFAULT_CACHE_EXPIRE = 60
|
||||
)
|
||||
|
||||
var (
|
||||
// 默认的缓存时间(秒)
|
||||
// Default expire time for file content caching in seconds.
|
||||
cacheExpire = cmdenv.Get("gf.gfcache.expire", gDEFAULT_CACHE_EXPIRE).Int()*1000
|
||||
)
|
||||
|
||||
// 获得文件内容 string,expire参数为缓存过期时间,单位为秒。
|
||||
// GetContents returns string content of given file by <path> from cache.
|
||||
// If there's no content in the cache, it will read it from disk file specified by <path>.
|
||||
// The parameter <expire> specifies the caching time for this file content in seconds.
|
||||
func GetContents(path string, expire...int) string {
|
||||
return string(GetBinContents(path, expire...))
|
||||
}
|
||||
|
||||
// 获得文件内容 []byte,expire参数为缓存过期时间,单位为秒。
|
||||
// GetBinContents returns []byte content of given file by <path> from cache.
|
||||
// If there's no content in the cache, it will read it from disk file specified by <path>.
|
||||
// The parameter <expire> specifies the caching time for this file content in seconds.
|
||||
func GetBinContents(path string, expire...int) []byte {
|
||||
k := cacheKey(path)
|
||||
e := cacheExpire
|
||||
@ -41,8 +43,9 @@ func GetBinContents(path string, expire...int) []byte {
|
||||
r := gcache.GetOrSetFuncLock(k, func() interface{} {
|
||||
b := gfile.GetBinContents(path)
|
||||
if b != nil {
|
||||
// 添加文件监控,如果文件有任何变化,立即清空缓存
|
||||
gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
// Adding this <path> to gfsnotify,
|
||||
// it will clear its cache if there's any changes of the file.
|
||||
_, _ = gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
gcache.Remove(k)
|
||||
gfsnotify.Exit()
|
||||
})
|
||||
|
@ -4,9 +4,7 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gflock implements a thread-safe sync.Locker interface for file locking.
|
||||
//
|
||||
// 文件锁.
|
||||
// Package gflock implements a concurrent-safe sync.Locker interface for file locking.
|
||||
package gflock
|
||||
|
||||
import (
|
||||
@ -15,17 +13,18 @@ import (
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
)
|
||||
|
||||
// 文件锁
|
||||
// File locker.
|
||||
type Locker struct {
|
||||
mu sync.RWMutex // 用于外部接口调用的互斥锁(阻塞机制)
|
||||
flock *flock.Flock // 底层文件锁对象
|
||||
}
|
||||
|
||||
// 创建文件锁
|
||||
// New creates and returns a new file locker with given <file>.
|
||||
// The parameter <file> usually is a absolute file path.
|
||||
func New(file string) *Locker {
|
||||
dir := gfile.TempDir() + gfile.Separator + "gflock"
|
||||
if !gfile.Exists(dir) {
|
||||
gfile.Mkdir(dir)
|
||||
_ = gfile.Mkdir(dir)
|
||||
}
|
||||
path := dir + gfile.Separator + file
|
||||
lock := flock.NewFlock(path)
|
||||
@ -34,16 +33,18 @@ func New(file string) *Locker {
|
||||
}
|
||||
}
|
||||
|
||||
// Path returns the file path of the locker.
|
||||
func (l *Locker) Path() string {
|
||||
return l.flock.Path()
|
||||
}
|
||||
|
||||
// 当前文件锁是否处于锁定状态(Lock)
|
||||
// IsLocked returns whether the locker is locked.
|
||||
func (l *Locker) IsLocked() bool {
|
||||
return l.flock.Locked()
|
||||
}
|
||||
|
||||
// 尝试Lock文件,如果失败立即返回
|
||||
// TryLock tries get the writing lock of the locker.
|
||||
// It returns true if success, or else returns false immediately.
|
||||
func (l *Locker) TryLock() bool {
|
||||
ok, _ := l.flock.TryLock()
|
||||
if ok {
|
||||
@ -52,7 +53,8 @@ func (l *Locker) TryLock() bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// 尝试RLock文件,如果失败立即返回
|
||||
// TryRLock tries get the reading lock of the locker.
|
||||
// It returns true if success, or else returns false immediately.
|
||||
func (l *Locker) TryRLock() bool {
|
||||
ok, _ := l.flock.TryRLock()
|
||||
if ok {
|
||||
@ -61,22 +63,26 @@ func (l *Locker) TryRLock() bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
func (l *Locker) Lock() {
|
||||
func (l *Locker) Lock() (err error) {
|
||||
l.mu.Lock()
|
||||
l.flock.Lock()
|
||||
err = l.flock.Lock()
|
||||
return
|
||||
}
|
||||
|
||||
func (l *Locker) UnLock() {
|
||||
l.flock.Unlock()
|
||||
func (l *Locker) UnLock() (err error) {
|
||||
err = l.flock.Unlock()
|
||||
l.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (l *Locker) RLock() {
|
||||
func (l *Locker) RLock() (err error) {
|
||||
l.mu.RLock()
|
||||
l.flock.RLock()
|
||||
err = l.flock.RLock()
|
||||
return
|
||||
}
|
||||
|
||||
func (l *Locker) RUnlock() {
|
||||
l.flock.Unlock()
|
||||
func (l *Locker) RUnlock() (err error) {
|
||||
err = l.flock.Unlock()
|
||||
l.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ func newFilePool(p *Pool, path string, flag int, perm os.FileMode, expire int) *
|
||||
path : path,
|
||||
}, nil
|
||||
}, func(i interface{}) {
|
||||
i.(*File).File.Close()
|
||||
_ = i.(*File).File.Close()
|
||||
})
|
||||
return pool
|
||||
}
|
||||
@ -136,7 +136,7 @@ func (p *Pool) File() (*File, error) {
|
||||
// 优先使用 !p.inited.Val() 原子读取操作判断,保证判断操作的效率;
|
||||
// p.inited.Set(true) == false 使用原子写入操作,保证该操作的原子性;
|
||||
if !p.inited.Val() && p.inited.Set(true) == false {
|
||||
gfsnotify.Add(f.path, func(event *gfsnotify.Event) {
|
||||
_, _ = gfsnotify.Add(f.path, func(event *gfsnotify.Event) {
|
||||
// 如果文件被删除或者重命名,立即重建指针池
|
||||
if event.IsRemove() || event.IsRename() {
|
||||
// 原有的指针都不要了
|
||||
|
@ -3,8 +3,6 @@
|
||||
// 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.
|
||||
//
|
||||
// @author john, zseeker
|
||||
|
||||
// Package glog implements powerful and easy-to-use levelled logging functionality.
|
||||
package glog
|
||||
|
@ -7,13 +7,13 @@
|
||||
package glog
|
||||
|
||||
// Print prints <v> with newline using fmt.Sprintln.
|
||||
// The param <v> can be multiple variables.
|
||||
// The parameter <v> can be multiple variables.
|
||||
func Print(v ...interface{}) {
|
||||
logger.Print(v ...)
|
||||
}
|
||||
|
||||
// Printf prints <v> with format <format> using fmt.Sprintf.
|
||||
// The param <v> can be multiple variables.
|
||||
// The parameter <v> can be multiple variables.
|
||||
func Printf(format string, v ...interface{}) {
|
||||
logger.Printf(format, v ...)
|
||||
}
|
||||
|
@ -10,6 +10,11 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// Expose returns the default logger of glog.
|
||||
func Expose() *Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
// To is a chaining function,
|
||||
// which redirects current logging content output to the sepecified <writer>.
|
||||
func To(writer io.Writer) *Logger {
|
||||
@ -69,7 +74,7 @@ func Header(enabled...bool) *Logger {
|
||||
|
||||
// Line is a chaining function,
|
||||
// which enables/disables printing its caller file along with its line number.
|
||||
// The param <long> specified whether print the long absolute file path, eg: /a/b/c/d.go:23.
|
||||
// The parameter <long> specified whether print the long absolute file path, eg: /a/b/c/d.go:23.
|
||||
func Line(long...bool) *Logger {
|
||||
return logger.Line(long...)
|
||||
}
|
||||
|
@ -12,13 +12,13 @@ import (
|
||||
)
|
||||
|
||||
// Print prints <v> with newline using fmt.Sprintln.
|
||||
// The param <v> can be multiple variables.
|
||||
// The parameter <v> can be multiple variables.
|
||||
func (l *Logger) Print(v...interface{}) {
|
||||
l.printStd("", v...)
|
||||
}
|
||||
|
||||
// Printf prints <v> with format <format> using fmt.Sprintf.
|
||||
// The param <v> can be multiple variables.
|
||||
// The parameter <v> can be multiple variables.
|
||||
func (l *Logger) Printf(format string, v...interface{}) {
|
||||
l.printStd(l.format(format, v...))
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ func (l *Logger) Header(enabled...bool) *Logger {
|
||||
|
||||
// Line is a chaining function,
|
||||
// which enables/disables printing its caller file path along with its line number.
|
||||
// The param <long> specified whether print the long absolute file path, eg: /a/b/c/d.go:23,
|
||||
// The parameter <long> specified whether print the long absolute file path, eg: /a/b/c/d.go:23,
|
||||
// or else short one: d.go:23.
|
||||
func (l *Logger) Line(long...bool) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
|
@ -6,9 +6,11 @@
|
||||
|
||||
package glog
|
||||
|
||||
import "bytes"
|
||||
|
||||
// Write implements the io.Writer interface.
|
||||
// It just prints the content using Print.
|
||||
func (l *Logger) Write(p []byte) (n int, err error) {
|
||||
l.Header(false).Print(string(p))
|
||||
l.Header(false).Print(string(bytes.TrimRight(p, "\r\n")))
|
||||
return len(p), nil
|
||||
}
|
@ -24,7 +24,7 @@ type Pool struct {
|
||||
var pool = New()
|
||||
|
||||
// New creates and returns a new goroutine pool object.
|
||||
// The param <limit> is used to limit the max goroutine count,
|
||||
// The parameter <limit> is used to limit the max goroutine count,
|
||||
// which is not limited in default.
|
||||
func New(limit...int) *Pool {
|
||||
p := &Pool {
|
||||
|
@ -19,9 +19,6 @@ import (
|
||||
|
||||
// 递归添加目录下的文件
|
||||
func (sp *SPath) updateCacheByPath(path string) {
|
||||
if sp.cache == nil {
|
||||
return
|
||||
}
|
||||
sp.addToCache(path, path)
|
||||
}
|
||||
|
||||
@ -58,9 +55,6 @@ func (sp *SPath) parseCacheValue(value string) (filePath string, isDir bool) {
|
||||
|
||||
// 添加path到缓存中(递归)
|
||||
func (sp *SPath) addToCache(filePath, rootPath string) {
|
||||
if sp.cache == nil {
|
||||
return
|
||||
}
|
||||
// 首先添加自身
|
||||
idDir := gfile.IsDir(filePath)
|
||||
sp.cache.SetIfNotExist(sp.nameFromPath(filePath, rootPath), sp.makeCacheValue(filePath, idDir))
|
||||
@ -83,7 +77,7 @@ func (sp *SPath) addMonitorByPath(path string) {
|
||||
if sp.cache == nil {
|
||||
return
|
||||
}
|
||||
gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
_, _ = gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
//glog.Debug(event.String())
|
||||
switch {
|
||||
case event.IsRemove():
|
||||
@ -105,5 +99,5 @@ func (sp *SPath) removeMonitorByPath(path string) {
|
||||
if sp.cache == nil {
|
||||
return
|
||||
}
|
||||
gfsnotify.Remove(path)
|
||||
_ = gfsnotify.Remove(path)
|
||||
}
|
@ -69,7 +69,9 @@ func New(path...string) *View {
|
||||
if gfile.Exists(envPath) {
|
||||
view.SetPath(envPath)
|
||||
} else {
|
||||
glog.Errorf("Template directory path does not exist: %s", envPath)
|
||||
if errorPrint() {
|
||||
glog.Errorf("Template directory path does not exist: %s", envPath)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Dir path of working dir.
|
||||
@ -117,7 +119,7 @@ func New(path...string) *View {
|
||||
}
|
||||
|
||||
// SetPath sets the template directory path for template file search.
|
||||
// The param <path> can be absolute or relative path, but absolute path is suggested.
|
||||
// The parameter <path> can be absolute or relative path, but absolute path is suggested.
|
||||
func (view *View) SetPath(path string) error {
|
||||
// Absolute path.
|
||||
realPath := gfile.RealPath(path)
|
||||
@ -146,13 +148,17 @@ func (view *View) SetPath(path string) error {
|
||||
buffer.WriteString(fmt.Sprintf(`[gview] SetPath failed: path "%s" does not exist`, path))
|
||||
}
|
||||
err := errors.New(buffer.String())
|
||||
glog.Error(err)
|
||||
if errorPrint() {
|
||||
glog.Error(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
// Should be a directory.
|
||||
if !gfile.IsDir(realPath) {
|
||||
err := errors.New(fmt.Sprintf(`[gview] SetPath failed: path "%s" should be directory type`, path))
|
||||
glog.Error(err)
|
||||
if errorPrint() {
|
||||
glog.Error(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
// Repeated path check.
|
||||
@ -194,13 +200,17 @@ func (view *View) AddPath(path string) error {
|
||||
buffer.WriteString(fmt.Sprintf(`[gview] AddPath failed: path "%s" does not exist`, path))
|
||||
}
|
||||
err := errors.New(buffer.String())
|
||||
glog.Error(err)
|
||||
if errorPrint() {
|
||||
glog.Error(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
// realPath should be type of folder.
|
||||
if !gfile.IsDir(realPath) {
|
||||
err := errors.New(fmt.Sprintf(`[gview] AddPath failed: path "%s" should be directory type`, path))
|
||||
glog.Error(err)
|
||||
if errorPrint() {
|
||||
glog.Error(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
// Repeated path check.
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/encoding/ghash"
|
||||
"github.com/gogf/gf/g/os/gfcache"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/os/gfsnotify"
|
||||
@ -18,6 +19,7 @@ import (
|
||||
"github.com/gogf/gf/g/os/gmlock"
|
||||
"github.com/gogf/gf/g/os/gspath"
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
@ -28,6 +30,7 @@ const (
|
||||
|
||||
var (
|
||||
// Templates cache map for template folder.
|
||||
// TODO Note that there's no expiring logic for this map.
|
||||
templates = gmap.NewStrAnyMap()
|
||||
)
|
||||
|
||||
@ -88,7 +91,9 @@ func (view *View) searchFile(file string) (path string, folder string, err error
|
||||
} else {
|
||||
buffer.WriteString(fmt.Sprintf("[gview] cannot find template file \"%s\" with no path set/add", file))
|
||||
}
|
||||
glog.Error(buffer.String())
|
||||
if errorPrint() {
|
||||
glog.Error(buffer.String())
|
||||
}
|
||||
err = errors.New(fmt.Sprintf(`template file "%s" not found`, file))
|
||||
}
|
||||
return
|
||||
@ -160,7 +165,8 @@ func (view *View) ParseContent(content string, params...Params) (string, error)
|
||||
return template.New(gCONTENT_TEMPLATE_NAME).Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
|
||||
}).(*template.Template)
|
||||
// Using memory lock to ensure concurrent safety for content parsing.
|
||||
gmlock.LockFunc("gview-parsing:content", func() {
|
||||
hash := gconv.String(ghash.DJBHash64([]byte(content)))
|
||||
gmlock.LockFunc("gview-parsing-content:" + hash, func() {
|
||||
tpl, err = tpl.Parse(content)
|
||||
})
|
||||
if err != nil {
|
||||
|
22
g/os/gview/gview_error.go
Normal file
22
g/os/gview/gview_error.go
Normal file
@ -0,0 +1,22 @@
|
||||
// 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 gview
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/internal/cmdenv"
|
||||
)
|
||||
|
||||
const (
|
||||
// gERROR_PRINT_KEY is used to specify the key controlling error printing to stdout.
|
||||
// This error is designed not to be returned by functions.
|
||||
gERROR_PRINT_KEY = "gf.gview.errorprint"
|
||||
)
|
||||
|
||||
// errorPrint checks whether printing error to stdout.
|
||||
func errorPrint() bool {
|
||||
return cmdenv.Get(gERROR_PRINT_KEY, true).Bool()
|
||||
}
|
@ -18,7 +18,7 @@ var (
|
||||
)
|
||||
|
||||
// Instance returns an instance of View with default settings.
|
||||
// The param <name> is the name for the instance.
|
||||
// The parameter <name> is the name for the instance.
|
||||
func Instance(name ...string) *View {
|
||||
key := DEFAULT_INSTANCE_NAME
|
||||
if len(name) > 0 {
|
||||
|
@ -11,6 +11,10 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func init() {
|
||||
os.Setenv("GF_GVIEW_ERRORPRINT", "false")
|
||||
}
|
||||
|
||||
func TestView_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
str := `hello {{.name}},version:{{.version}};hello {{GetName}},version:{{GetVersion}};{{.other}}`
|
||||
@ -199,25 +203,25 @@ func TestView_SetPath(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
view := gview.Instance("addpath")
|
||||
err := view.AddPath("tmp")
|
||||
gtest.Assert(err == nil, false)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
err = view.AddPath("gview.go")
|
||||
gtest.Assert(err == nil, false)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
os.Setenv("GF_GVIEW_PATH", "tmp")
|
||||
view = gview.Instance("setpath")
|
||||
err = view.SetPath("tmp")
|
||||
gtest.Assert(err == nil, false)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
err = view.SetPath("gview.go")
|
||||
gtest.Assert(err == nil, false)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
view = gview.New(gfile.Pwd())
|
||||
err = view.SetPath("tmp")
|
||||
gtest.Assert(err == nil, false)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
err = view.SetPath("gview.go")
|
||||
gtest.Assert(err == nil, false)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
os.Setenv("GF_GVIEW_PATH", "template")
|
||||
gfile.Mkdir(gfile.Pwd() + gfile.Separator + "template")
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
)
|
||||
|
||||
// Case creates an unit test case.
|
||||
// The param <t> is the pointer to testing.T of stdlib (*testing.T).
|
||||
// The param <f> is the callback function for unit test case.
|
||||
// The parameter <t> is the pointer to testing.T of stdlib (*testing.T).
|
||||
// The parameter <f> is the callback function for unit test case.
|
||||
func Case(t *testing.T, f func()) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
@ -297,7 +297,7 @@ func compareMap(value, expect interface{}) error {
|
||||
}
|
||||
|
||||
// getBacktrace returns the caller backtrace content from getBacktrace.
|
||||
// The param <skip> indicates the skip count of the caller backtrace from getBacktrace.
|
||||
// The parameter <skip> indicates the skip count of the caller backtrace from getBacktrace.
|
||||
func getBacktrace(skip...int) string {
|
||||
customSkip := 0
|
||||
if len(skip) > 0 {
|
||||
|
@ -13,6 +13,8 @@ import (
|
||||
|
||||
var (
|
||||
regexMu = sync.RWMutex{}
|
||||
// Cache for regex object.
|
||||
// TODO There's no expiring logic for this map.
|
||||
regexMap = make(map[string]*regexp.Regexp)
|
||||
)
|
||||
|
||||
|
@ -241,9 +241,6 @@ func Int64(i interface{}) int64 {
|
||||
if i == nil {
|
||||
return 0
|
||||
}
|
||||
if v, ok := i.(int64); ok {
|
||||
return v
|
||||
}
|
||||
switch value := i.(type) {
|
||||
case int: return int64(value)
|
||||
case int8: return int64(value)
|
||||
|
@ -5,8 +5,6 @@
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gpage provides useful paging functionality for web pages.
|
||||
//
|
||||
// 分页管理.
|
||||
package gpage
|
||||
|
||||
import (
|
||||
|
@ -24,5 +24,7 @@ func main() {
|
||||
glog.SetWriter(&MyWriter{
|
||||
logger: glog.New(),
|
||||
})
|
||||
glog.Debug("DEBUG")
|
||||
glog.Fatal("FATAL ERROR")
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
<<<<<<< HEAD
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a1:=[]string{"a", "d", "c","b"}
|
||||
|
||||
s1 :=garray.NewSortedStringArrayFromCopy(a1,true)
|
||||
|
||||
gtest.Assert(s1.Slice(),[]string{"a", "b", "c","d"})
|
||||
var i float64 = 0
|
||||
for index := 0; index < 10; index++ {
|
||||
i += 0.1
|
||||
fmt.Println(i)
|
||||
}
|
||||
}
|
||||
=======
|
||||
"github.com/gogf/gf/g/encoding/gjson"
|
||||
)
|
||||
|
||||
func main() {
|
||||
j := gjson.New(`[1,2,3]`)
|
||||
j.Remove("1")
|
||||
j.Dump()
|
||||
}
|
||||
>>>>>>> master
|
||||
|
Loading…
Reference in New Issue
Block a user