mirror of
https://gitee.com/johng/gf
synced 2026-06-19 23:02:56 +08:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ea7e2ec5ec | |||
| 237c58f2b0 | |||
| efa23e4a1d | |||
| c109cee7ef | |||
| e111d39c54 | |||
| 66306464e1 | |||
| dd34ac1722 | |||
| 34cb222b33 |
@ -76,6 +76,7 @@ func main() {
|
||||
- [pibigstar](https://github.com/pibigstar)
|
||||
- [qq1054000800](https://gitee.com/qq1054000800)
|
||||
- [qq976739120](https://github.com/qq976739120)
|
||||
- [touzijiao](https://github.com/touzijiao)
|
||||
- [wenzi1](https://gitee.com/wenzi1)
|
||||
- [wxkj001](https://github.com/wxkj001)
|
||||
- [ymrjqyy](https://gitee.com/ymrjqyy)
|
||||
|
||||
@ -94,6 +94,7 @@ func main() {
|
||||
- [pibigstar](https://github.com/pibigstar)
|
||||
- [qq1054000800](https://gitee.com/qq1054000800)
|
||||
- [qq976739120](https://github.com/qq976739120)
|
||||
- [touzijiao](https://github.com/touzijiao)
|
||||
- [wenzi1](https://gitee.com/wenzi1)
|
||||
- [wxkj001](https://github.com/wxkj001)
|
||||
- [ymrjqyy](https://gitee.com/ymrjqyy)
|
||||
|
||||
@ -289,6 +289,10 @@ func (l *List) RemoveAll() {
|
||||
l.mu.Unlock()
|
||||
}
|
||||
|
||||
func (l *List) Clear() {
|
||||
l.RemoveAll()
|
||||
}
|
||||
|
||||
// 读锁操作
|
||||
func (l *List) RLockFunc(f func(list *list.List)) {
|
||||
l.mu.RLock()
|
||||
|
||||
@ -4,14 +4,18 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gqueue provides a dynamic/static concurrent-safe(alternative) queue.
|
||||
// Package gqueue provides a dynamic/static concurrent-safe queue.
|
||||
//
|
||||
// 并发安全动态队列.
|
||||
// Features:
|
||||
//
|
||||
// 1. FIFO queue(data -> list -> chan);
|
||||
//
|
||||
// 2. Fast creation and initialization;
|
||||
//
|
||||
// 3. Support dynamic queue size(unlimited queue size);
|
||||
//
|
||||
// 4. Blocking when reading data from queue;
|
||||
//
|
||||
// 特点:
|
||||
// 1. 动态队列初始化速度快;
|
||||
// 2. 动态的队列大小(不限大小);
|
||||
// 3. 取数据时如果队列为空那么会阻塞等待;
|
||||
package gqueue
|
||||
|
||||
import (
|
||||
@ -19,27 +23,21 @@ import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// 1、这是一个先进先出的队列(chan <-- list);
|
||||
//
|
||||
// 2、当创建Queue对象时限定大小,那么等同于一个同步的chan并发安全队列;
|
||||
//
|
||||
// 3、不限制大小时,list链表用以存储数据,临时chan负责为客户端读取数据,当从chan获取数据时,list往chan中不停补充数据;
|
||||
//
|
||||
// 4、由于功能主体是chan,那么操作仍然像chan那样具有阻塞效果;
|
||||
type Queue struct {
|
||||
limit int // 队列限制大小
|
||||
list *glist.List // 底层数据链表
|
||||
events chan struct{} // 写入事件通知
|
||||
closed chan struct{} // 队列关闭通知
|
||||
C chan interface{} // 队列数据读取
|
||||
limit int // Limit for queue size.
|
||||
list *glist.List // Underlying list structure for data maintaining.
|
||||
events chan struct{} // Events for data writing.
|
||||
closed chan struct{} // Events for queue closing.
|
||||
C chan interface{} // Underlying channel for data reading.
|
||||
}
|
||||
|
||||
const (
|
||||
// 动态队列缓冲区大小
|
||||
// Size for queue buffer.
|
||||
gDEFAULT_QUEUE_SIZE = 10000
|
||||
)
|
||||
|
||||
// 队列大小为非必须参数,默认不限制
|
||||
// New returns a queue object.
|
||||
// Param <limit> is optional and it is not limited by default.
|
||||
func New(limit...int) *Queue {
|
||||
q := &Queue {
|
||||
closed : make(chan struct{}, 0),
|
||||
@ -56,7 +54,8 @@ func New(limit...int) *Queue {
|
||||
return q
|
||||
}
|
||||
|
||||
// 异步list->chan同步队列
|
||||
// startAsyncLoop starts an asynchronous goroutine,
|
||||
// which handles the data synchronization from list <q.list> to channel <q.C>.
|
||||
func (q *Queue) startAsyncLoop() {
|
||||
for {
|
||||
select {
|
||||
@ -84,7 +83,8 @@ func (q *Queue) startAsyncLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
// 将数据压入队列, 队尾
|
||||
// Push pushes the data <v> into the queue.
|
||||
// Note that it would panics if the Push method is called after the queue is closed.
|
||||
func (q *Queue) Push(v interface{}) {
|
||||
if q.limit > 0 {
|
||||
q.C <- v
|
||||
@ -94,19 +94,22 @@ func (q *Queue) Push(v interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// 从队头先进先出地从队列取出一项数据
|
||||
// Pop pops an item from the queue in FIFO way.
|
||||
// Note that it would return nil immediately if the Pop method is called after the queue is closed.
|
||||
func (q *Queue) Pop() interface{} {
|
||||
return <- q.C
|
||||
}
|
||||
|
||||
// 关闭队列(通知所有通过Pop*阻塞的协程退出)
|
||||
// Close closes the queue.
|
||||
// Notice: It would notify all goroutines exit immediately,
|
||||
// which are blocked reading by Pop method).
|
||||
func (q *Queue) Close() {
|
||||
close(q.C)
|
||||
close(q.events)
|
||||
close(q.closed)
|
||||
}
|
||||
|
||||
// 获取当前队列大小
|
||||
// Size returns the length of the queue.
|
||||
func (q *Queue) Size() int {
|
||||
return len(q.C) + q.list.Len()
|
||||
}
|
||||
|
||||
@ -295,4 +295,33 @@ func (set *Set) Sum() (sum int) {
|
||||
sum += gconv.Int(k)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pops randomly pops an item from set.
|
||||
func (set *Set) Pop(size int) interface{} {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
for k, _ := range set.m {
|
||||
return k
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pops randomly pops <size> items from set.
|
||||
func (set *Set) Pops(size int) []interface{} {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
if size > len(set.m) {
|
||||
size = len(set.m)
|
||||
}
|
||||
index := 0
|
||||
array := make([]interface{}, size)
|
||||
for k, _ := range set.m {
|
||||
array[index] = k
|
||||
index++
|
||||
if index == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
@ -289,4 +289,33 @@ func (set *IntSet) Sum() (sum int) {
|
||||
sum += k
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pops randomly pops an item from set.
|
||||
func (set *IntSet) Pop(size int) int {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
for k, _ := range set.m {
|
||||
return k
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Pops randomly pops <size> items from set.
|
||||
func (set *IntSet) Pops(size int) []int {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
if size > len(set.m) {
|
||||
size = len(set.m)
|
||||
}
|
||||
index := 0
|
||||
array := make([]int, size)
|
||||
for k, _ := range set.m {
|
||||
array[index] = k
|
||||
index++
|
||||
if index == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
@ -290,4 +290,33 @@ func (set *StringSet) Sum() (sum int) {
|
||||
sum += gconv.Int(k)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pops randomly pops an item from set.
|
||||
func (set *StringSet) Pop(size int) string {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
for k, _ := range set.m {
|
||||
return k
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Pops randomly pops <size> items from set.
|
||||
func (set *StringSet) Pops(size int) []string {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
if size > len(set.m) {
|
||||
size = len(set.m)
|
||||
}
|
||||
index := 0
|
||||
array := make([]string, size)
|
||||
for k, _ := range set.m {
|
||||
array[index] = k
|
||||
index++
|
||||
if index == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
265
g/container/gvar/gvar_test.go
Normal file
265
g/container/gvar/gvar_test.go
Normal file
@ -0,0 +1,265 @@
|
||||
package gvar_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/container/gvar"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
func TestReadOnly(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
obj := gvar.New(nil, true)
|
||||
var result string
|
||||
|
||||
switch obj.ReadOnly().(type) {
|
||||
case gvar.VarRead:
|
||||
result = "yes"
|
||||
default:
|
||||
result = "no"
|
||||
}
|
||||
|
||||
gtest.Assert(result, "yes")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
objOne := gvar.New("old", true)
|
||||
objOneOld, _ := objOne.Set("new").(string)
|
||||
gtest.Assert(objOneOld, "old")
|
||||
|
||||
objTwo := gvar.New("old", false)
|
||||
objTwoOld, _ := objTwo.Set("new").(string)
|
||||
gtest.Assert(objTwoOld, "old")
|
||||
})
|
||||
}
|
||||
|
||||
func TestVal(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
objOne := gvar.New(1, true)
|
||||
objOneOld, _ := objOne.Val().(int)
|
||||
gtest.Assert(objOneOld, 1)
|
||||
|
||||
objTwo := gvar.New(1, false)
|
||||
objTwoOld, _ := objTwo.Val().(int)
|
||||
gtest.Assert(objTwoOld, 1)
|
||||
})
|
||||
}
|
||||
func TestInterface(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
objOne := gvar.New(1, true)
|
||||
objOneOld, _ := objOne.Interface().(int)
|
||||
gtest.Assert(objOneOld, 1)
|
||||
|
||||
objTwo := gvar.New(1, false)
|
||||
objTwoOld, _ := objTwo.Interface().(int)
|
||||
gtest.Assert(objTwoOld, 1)
|
||||
})
|
||||
}
|
||||
func TestIsNil(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
objOne := gvar.New(nil, true)
|
||||
gtest.Assert(objOne.IsNil(), true)
|
||||
|
||||
objTwo := gvar.New("noNil", false)
|
||||
gtest.Assert(objTwo.IsNil(), false)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestBytes(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
x := int32(1)
|
||||
bytesBuffer := bytes.NewBuffer([]byte{})
|
||||
binary.Write(bytesBuffer, binary.BigEndian, x)
|
||||
|
||||
objOne := gvar.New(bytesBuffer.Bytes(), true)
|
||||
|
||||
bBuf := bytes.NewBuffer(objOne.Bytes())
|
||||
var y int32
|
||||
binary.Read(bBuf, binary.BigEndian, &y)
|
||||
|
||||
gtest.Assert(x, y)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var str string = "hello"
|
||||
objOne := gvar.New(str, true)
|
||||
gtest.Assert(objOne.String(), str)
|
||||
|
||||
})
|
||||
}
|
||||
func TestBool(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var ok bool = true
|
||||
objOne := gvar.New(ok, true)
|
||||
gtest.Assert(objOne.Bool(), ok)
|
||||
|
||||
ok = false
|
||||
objTwo := gvar.New(ok, true)
|
||||
gtest.Assert(objTwo.Bool(), ok)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestInt(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var num int = 1
|
||||
objOne := gvar.New(num, true)
|
||||
gtest.Assert(objOne.Int(), num)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestInt8(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var num int8 = 1
|
||||
objOne := gvar.New(num, true)
|
||||
gtest.Assert(objOne.Int8(), num)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestInt16(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var num int16 = 1
|
||||
objOne := gvar.New(num, true)
|
||||
gtest.Assert(objOne.Int16(), num)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestInt32(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var num int32 = 1
|
||||
objOne := gvar.New(num, true)
|
||||
gtest.Assert(objOne.Int32(), num)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestInt64(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var num int64 = 1
|
||||
objOne := gvar.New(num, true)
|
||||
gtest.Assert(objOne.Int64(), num)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestUint(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var num uint = 1
|
||||
objOne := gvar.New(num, true)
|
||||
gtest.Assert(objOne.Uint(), num)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestUint8(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var num uint8 = 1
|
||||
objOne := gvar.New(num, true)
|
||||
gtest.Assert(objOne.Uint8(), num)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestUint16(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var num uint16 = 1
|
||||
objOne := gvar.New(num, true)
|
||||
gtest.Assert(objOne.Uint16(), num)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestUint32(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var num uint32 = 1
|
||||
objOne := gvar.New(num, true)
|
||||
gtest.Assert(objOne.Uint32(), num)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestUint64(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var num uint64 = 1
|
||||
objOne := gvar.New(num, true)
|
||||
gtest.Assert(objOne.Uint64(), num)
|
||||
|
||||
})
|
||||
}
|
||||
func TestFloat32(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var num float32 = 1.1
|
||||
objOne := gvar.New(num, true)
|
||||
gtest.Assert(objOne.Float32(), num)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestFloat64(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var num float64 = 1.1
|
||||
objOne := gvar.New(num, true)
|
||||
gtest.Assert(objOne.Float64(), num)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestInts(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var arr = []int{1, 2, 3, 4, 5}
|
||||
objOne := gvar.New(arr, true)
|
||||
gtest.Assert(objOne.Ints()[0], arr[0])
|
||||
})
|
||||
}
|
||||
func TestFloats(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var arr = []float64{1, 2, 3, 4, 5}
|
||||
objOne := gvar.New(arr, true)
|
||||
gtest.Assert(objOne.Floats()[0], arr[0])
|
||||
})
|
||||
}
|
||||
func TestStrings(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var arr = []string{"hello", "world"}
|
||||
objOne := gvar.New(arr, true)
|
||||
gtest.Assert(objOne.Strings()[0], arr[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestTime(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var timeUnix int64 = 1556242660
|
||||
objOne := gvar.New(timeUnix, true)
|
||||
gtest.Assert(objOne.Time().Unix(), timeUnix)
|
||||
})
|
||||
}
|
||||
|
||||
type StTest struct {
|
||||
Test int
|
||||
}
|
||||
|
||||
func TestStruct(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
Kv := make(map[string]int, 1)
|
||||
Kv["Test"] = 100
|
||||
|
||||
testObj := &StTest{}
|
||||
|
||||
objOne := gvar.New(Kv, true)
|
||||
|
||||
objOne.Struct(testObj)
|
||||
|
||||
gtest.Assert(testObj.Test, Kv["Test"])
|
||||
})
|
||||
}
|
||||
@ -18,7 +18,6 @@ type View struct {
|
||||
mu sync.RWMutex // 并发互斥锁
|
||||
view *gview.View // 底层视图对象
|
||||
data gview.Params // 视图数据/模板变量
|
||||
fmap gview.FuncMap // 绑定的模板函数
|
||||
response *ghttp.Response // 数据返回对象
|
||||
}
|
||||
|
||||
@ -27,7 +26,6 @@ func NewView(w *ghttp.Response) *View {
|
||||
return &View {
|
||||
view : gins.View(),
|
||||
data : make(gview.Params),
|
||||
fmap : make(gview.FuncMap),
|
||||
response : w,
|
||||
}
|
||||
}
|
||||
@ -48,18 +46,11 @@ func (view *View) Assign(key string, value interface{}) {
|
||||
view.mu.Unlock()
|
||||
}
|
||||
|
||||
// 绑定自定义模板函数
|
||||
func (view *View) BindFunc(name string, function interface{}){
|
||||
view.mu.Lock()
|
||||
view.fmap[name] = function
|
||||
view.mu.Unlock()
|
||||
}
|
||||
|
||||
// 解析模板,并返回解析后的内容
|
||||
func (view *View) Parse(file string) (string, error) {
|
||||
view.mu.RLock()
|
||||
defer view.mu.RUnlock()
|
||||
buffer, err := view.response.ParseTpl(file, view.data, view.fmap)
|
||||
buffer, err := view.response.ParseTpl(file, view.data)
|
||||
return buffer, err
|
||||
}
|
||||
|
||||
@ -67,7 +58,7 @@ func (view *View) Parse(file string) (string, error) {
|
||||
func (view *View) ParseContent(content string) (string, error) {
|
||||
view.mu.RLock()
|
||||
defer view.mu.RUnlock()
|
||||
buffer, err := view.response.ParseTplContent(content, view.data, view.fmap)
|
||||
buffer, err := view.response.ParseTplContent(content, view.data)
|
||||
return buffer, err
|
||||
}
|
||||
|
||||
|
||||
@ -13,13 +13,9 @@ import (
|
||||
)
|
||||
|
||||
// 展示模板,可以给定模板参数,及临时的自定义模板函数
|
||||
func (r *Response) WriteTpl(tpl string, params map[string]interface{}, funcMap...map[string]interface{}) error {
|
||||
fmap := make(gview.FuncMap)
|
||||
if len(funcMap) > 0 {
|
||||
fmap = funcMap[0]
|
||||
}
|
||||
if b, err := r.ParseTpl(tpl, params, fmap); err != nil {
|
||||
r.Write("Tpl Parsing Error: " + err.Error())
|
||||
func (r *Response) WriteTpl(tpl string, params...gview.Params) error {
|
||||
if b, err := r.ParseTpl(tpl, params...); err != nil {
|
||||
r.Write("Template Parsing Error: " + err.Error())
|
||||
return err
|
||||
} else {
|
||||
r.Write(b)
|
||||
@ -28,13 +24,9 @@ func (r *Response) WriteTpl(tpl string, params map[string]interface{}, funcMap..
|
||||
}
|
||||
|
||||
// 展示模板内容,可以给定模板参数,及临时的自定义模板函数
|
||||
func (r *Response) WriteTplContent(content string, params map[string]interface{}, funcMap...map[string]interface{}) error {
|
||||
fmap := make(gview.FuncMap)
|
||||
if len(funcMap) > 0 {
|
||||
fmap = funcMap[0]
|
||||
}
|
||||
if b, err := r.ParseTplContent(content, params, fmap); err != nil {
|
||||
r.Write("Tpl Parsing Error: " + err.Error())
|
||||
func (r *Response) WriteTplContent(content string, params...gview.Params) error {
|
||||
if b, err := r.ParseTplContent(content, params...); err != nil {
|
||||
r.Write("Template Parsing Error: " + err.Error())
|
||||
return err
|
||||
} else {
|
||||
r.Write(b)
|
||||
@ -43,61 +35,27 @@ func (r *Response) WriteTplContent(content string, params map[string]interface{}
|
||||
}
|
||||
|
||||
// 解析模板文件,并返回模板内容
|
||||
func (r *Response) ParseTpl(tpl string, params gview.Params, funcMap...map[string]interface{}) (string, error) {
|
||||
m := make(gview.FuncMap)
|
||||
if len(funcMap) > 0 {
|
||||
m = funcMap[0]
|
||||
}
|
||||
return gins.View().Parse(tpl, r.buildInVars(params), r.buildInFuncs(m))
|
||||
func (r *Response) ParseTpl(tpl string, params...gview.Params) (string, error) {
|
||||
return gins.View().Parse(tpl, r.buildInVars(params...))
|
||||
}
|
||||
|
||||
// 解析并返回模板内容
|
||||
func (r *Response) ParseTplContent(content string, params gview.Params, funcMap...map[string]interface{}) (string, error) {
|
||||
m := make(gview.FuncMap)
|
||||
if len(funcMap) > 0 {
|
||||
m = funcMap[0]
|
||||
}
|
||||
return gins.View().ParseContent(content, r.buildInVars(params), r.buildInFuncs(m))
|
||||
func (r *Response) ParseTplContent(content string, params...gview.Params) (string, error) {
|
||||
return gins.View().ParseContent(content, r.buildInVars(params...))
|
||||
}
|
||||
|
||||
// 内置变量
|
||||
func (r *Response) buildInVars(params map[string]interface{}) map[string]interface{} {
|
||||
if params == nil {
|
||||
params = make(map[string]interface{})
|
||||
}
|
||||
c := gins.Config()
|
||||
if c.GetFilePath() != "" {
|
||||
params["Config"] = c.GetMap("")
|
||||
// 内置变量/对象
|
||||
func (r *Response) buildInVars(params...map[string]interface{}) map[string]interface{} {
|
||||
vars := map[string]interface{}(nil)
|
||||
if len(params) > 0 {
|
||||
vars = params[0]
|
||||
} else {
|
||||
params["Config"] = nil
|
||||
vars = make(map[string]interface{})
|
||||
}
|
||||
params["Cookie"] = r.request.Cookie.Map()
|
||||
params["Session"] = r.request.Session.Data()
|
||||
return params
|
||||
}
|
||||
|
||||
// 内置函数
|
||||
func (r *Response) buildInFuncs(funcMap map[string]interface{}) map[string]interface{} {
|
||||
if funcMap == nil {
|
||||
funcMap = make(map[string]interface{})
|
||||
}
|
||||
funcMap["get"] = r.funcGet
|
||||
funcMap["post"] = r.funcPost
|
||||
funcMap["request"] = r.funcRequest
|
||||
return funcMap
|
||||
}
|
||||
|
||||
// 模板内置函数: get
|
||||
func (r *Response) funcGet(key string, def...string) string {
|
||||
return r.request.GetQueryString(key, def...)
|
||||
}
|
||||
|
||||
// 模板内置函数: post
|
||||
func (r *Response) funcPost(key string, def...string) string {
|
||||
return r.request.GetPostString(key, def...)
|
||||
}
|
||||
|
||||
// 模板内置函数: request
|
||||
func (r *Response) funcRequest(key string, def...string) string {
|
||||
return r.request.Get(key, def...)
|
||||
vars["Config"] = gins.Config().GetMap("")
|
||||
vars["Cookie"] = r.request.Cookie.Map()
|
||||
vars["Session"] = r.request.Session.Map()
|
||||
vars["Get"] = r.request.GetQueryMap()
|
||||
vars["Post"] = r.request.GetPostMap()
|
||||
return vars
|
||||
}
|
||||
@ -15,7 +15,8 @@ import (
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"github.com/gogf/gf/g/os/gcache"
|
||||
"github.com/gogf/gf/g/os/genv"
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"github.com/gogf/gf/g/os/gproc"
|
||||
"github.com/gogf/gf/g/os/gtimer"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
@ -108,9 +109,9 @@ const (
|
||||
HOOK_BEFORE_OUTPUT = "BeforeOutput"
|
||||
HOOK_AFTER_OUTPUT = "AfterOutput"
|
||||
|
||||
// deprecated.
|
||||
// Deprecated.
|
||||
HOOK_BEFORE_CLOSE = "BeforeClose"
|
||||
// deprecated.
|
||||
// Deprecated.
|
||||
HOOK_AFTER_CLOSE = "AfterClose"
|
||||
|
||||
HTTP_METHODS = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
|
||||
@ -188,10 +189,10 @@ func serverProcessInit() {
|
||||
go handleProcessMessage()
|
||||
}
|
||||
|
||||
// 是否处于开发环境
|
||||
//if gfile.MainPkgPath() != "" {
|
||||
// glog.Debug("GF notices that you're in develop environment, so error logs are auto enabled to stdout.")
|
||||
//}
|
||||
// 是否处于开发环境,这里调用该方法初始化main包路径值,
|
||||
// 防止异步服务goroutine获取main包路径失败,
|
||||
// 该方法只有在main协程中才会执行。
|
||||
gfile.MainPkgPath()
|
||||
}
|
||||
|
||||
// 获取/创建一个默认配置的HTTP Server(默认监听端口是80)
|
||||
|
||||
@ -69,7 +69,7 @@ func (s *Session) Id() string {
|
||||
}
|
||||
|
||||
// 获取当前session所有数据
|
||||
func (s *Session) Data() map[string]interface{} {
|
||||
func (s *Session) Map() map[string]interface{} {
|
||||
if len(s.id) > 0 || s.request.Cookie.GetSessionId() != "" {
|
||||
s.init()
|
||||
return s.data.Map()
|
||||
|
||||
@ -440,10 +440,14 @@ func homeWindows() (string, error) {
|
||||
// Available in develop environment.
|
||||
//
|
||||
// 获取入口函数文件所在目录(main包文件目录),
|
||||
// **仅对源码开发环境有效(即仅对生成该可执行文件的系统下有效)**
|
||||
// **仅对源码开发环境有效(即仅对生成该可执行文件的系统下有效)**。
|
||||
// 注意:该方法被第一次调用时,如果是在异步的goroutine中,该方法可能无法获取到main包路径。
|
||||
func MainPkgPath() string {
|
||||
path := mainPkgPath.Val()
|
||||
if path != "" {
|
||||
if path == "-" {
|
||||
return ""
|
||||
}
|
||||
return path
|
||||
}
|
||||
for i := 1; i < 10000; i++ {
|
||||
@ -457,6 +461,8 @@ func MainPkgPath() string {
|
||||
break
|
||||
}
|
||||
}
|
||||
// 找不到,下次不用再检索了
|
||||
mainPkgPath.Set("-")
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
@ -90,6 +90,12 @@ func New(path...string) *View {
|
||||
"version" : gf.VERSION,
|
||||
}
|
||||
// default build-in functions.
|
||||
view.BindFunc("eq", view.funcEq)
|
||||
view.BindFunc("ne", view.funcNe)
|
||||
view.BindFunc("lt", view.funcLt)
|
||||
view.BindFunc("le", view.funcLe)
|
||||
view.BindFunc("gt", view.funcGt)
|
||||
view.BindFunc("ge", view.funcGe)
|
||||
view.BindFunc("text", view.funcText)
|
||||
view.BindFunc("html", view.funcHtmlEncode)
|
||||
view.BindFunc("htmlencode", view.funcHtmlEncode)
|
||||
|
||||
@ -16,6 +16,62 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Build-in template function: eq
|
||||
func (view *View) funcEq(value interface{}, others...interface{}) bool {
|
||||
s := gconv.String(value)
|
||||
for _, v := range others {
|
||||
if strings.Compare(s, gconv.String(v)) != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Build-in template function: ne
|
||||
func (view *View) funcNe(value interface{}, other interface{}) bool {
|
||||
return strings.Compare(gconv.String(value), gconv.String(other)) != 0
|
||||
}
|
||||
|
||||
// Build-in template function: lt
|
||||
func (view *View) funcLt(value interface{}, other interface{}) bool {
|
||||
s1 := gconv.String(value)
|
||||
s2 := gconv.String(other)
|
||||
if gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {
|
||||
return gconv.Int64(value) < gconv.Int64(other)
|
||||
}
|
||||
return strings.Compare(s1, s2) < 0
|
||||
}
|
||||
|
||||
// Build-in template function: le
|
||||
func (view *View) funcLe(value interface{}, other interface{}) bool {
|
||||
s1 := gconv.String(value)
|
||||
s2 := gconv.String(other)
|
||||
if gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {
|
||||
return gconv.Int64(value) <= gconv.Int64(other)
|
||||
}
|
||||
return strings.Compare(s1, s2) <= 0
|
||||
}
|
||||
|
||||
// Build-in template function: gt
|
||||
func (view *View) funcGt(value interface{}, other interface{}) bool {
|
||||
s1 := gconv.String(value)
|
||||
s2 := gconv.String(other)
|
||||
if gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {
|
||||
return gconv.Int64(value) > gconv.Int64(other)
|
||||
}
|
||||
return strings.Compare(s1, s2) > 0
|
||||
}
|
||||
|
||||
// Build-in template function: ge
|
||||
func (view *View) funcGe(value interface{}, other interface{}) bool {
|
||||
s1 := gconv.String(value)
|
||||
s2 := gconv.String(other)
|
||||
if gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {
|
||||
return gconv.Int64(value) >= gconv.Int64(other)
|
||||
}
|
||||
return strings.Compare(s1, s2) >= 0
|
||||
}
|
||||
|
||||
// Build-in template function: include
|
||||
func (view *View) funcInclude(file string, data...map[string]interface{}) string {
|
||||
var m map[string]interface{} = nil
|
||||
|
||||
@ -31,7 +31,8 @@ var (
|
||||
// if the template files under <path> changes (recursively).
|
||||
func (view *View) getTemplate(path string, pattern string) (tpl *template.Template, err error) {
|
||||
r := templates.GetOrSetFuncLock(path, func() interface {} {
|
||||
files, err := gfile.ScanDir(path, pattern, true)
|
||||
files := ([]string)(nil)
|
||||
files, err = gfile.ScanDir(path, pattern, true)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@ -90,7 +91,7 @@ func (view *View) searchFile(file string) (path string, folder string, err error
|
||||
// ParseContent parses given template file <file>
|
||||
// with given template parameters <params> and function map <funcMap>
|
||||
// and returns the parsed string content.
|
||||
func (view *View) Parse(file string, params map[string]interface{}, funcMap...map[string]interface{}) (parsed string, err error) {
|
||||
func (view *View) Parse(file string, params...Params) (parsed string, err error) {
|
||||
view.mu.RLock()
|
||||
defer view.mu.RUnlock()
|
||||
path, folder, err := view.searchFile(file)
|
||||
@ -101,9 +102,6 @@ func (view *View) Parse(file string, params map[string]interface{}, funcMap...ma
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(funcMap) > 0 {
|
||||
tpl = tpl.Funcs(funcMap[0])
|
||||
}
|
||||
tpl, err = tpl.Parse(gfcache.GetContents(path))
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -112,10 +110,16 @@ func (view *View) Parse(file string, params map[string]interface{}, funcMap...ma
|
||||
// of the existing <params> or view.data because both variables are pointers.
|
||||
// It's need to merge the values of the two maps into a new map.
|
||||
vars := (map[string]interface{})(nil)
|
||||
length := len(view.data)
|
||||
if len(params) > 0 {
|
||||
length += len(params[0])
|
||||
}
|
||||
if length > 0 {
|
||||
vars = make(map[string]interface{}, length)
|
||||
}
|
||||
if len(view.data) > 0 {
|
||||
if len(params) > 0 {
|
||||
vars = make(map[string]interface{}, len(view.data) + len(params))
|
||||
for k, v := range params {
|
||||
for k, v := range params[0] {
|
||||
vars[k] = v
|
||||
}
|
||||
for k, v := range view.data {
|
||||
@ -125,7 +129,9 @@ func (view *View) Parse(file string, params map[string]interface{}, funcMap...ma
|
||||
vars = view.data
|
||||
}
|
||||
} else {
|
||||
vars = params
|
||||
if len(params) > 0 {
|
||||
vars = params[0]
|
||||
}
|
||||
}
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
if err := tpl.Execute(buffer, vars); err != nil {
|
||||
@ -137,13 +143,10 @@ func (view *View) Parse(file string, params map[string]interface{}, funcMap...ma
|
||||
// ParseContent parses given template content <content>
|
||||
// with given template parameters <params> and function map <funcMap>
|
||||
// and returns the parsed content in []byte.
|
||||
func (view *View) ParseContent(content string, params Params, funcMap...map[string]interface{}) (string, error) {
|
||||
func (view *View) ParseContent(content string, params...Params) (string, error) {
|
||||
view.mu.RLock()
|
||||
defer view.mu.RUnlock()
|
||||
tpl := template.New("").Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
|
||||
if len(funcMap) > 0 {
|
||||
tpl = tpl.Funcs(funcMap[0])
|
||||
}
|
||||
tpl := template.New("template content").Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
|
||||
tpl, err := tpl.Parse(content)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -152,10 +155,16 @@ func (view *View) ParseContent(content string, params Params, funcMap...map[stri
|
||||
// of the existing <params> or view.data because both variables are pointers.
|
||||
// It's need to merge the values of the two maps into a new map.
|
||||
vars := (map[string]interface{})(nil)
|
||||
length := len(view.data)
|
||||
if len(params) > 0 {
|
||||
length += len(params[0])
|
||||
}
|
||||
if length > 0 {
|
||||
vars = make(map[string]interface{}, length)
|
||||
}
|
||||
if len(view.data) > 0 {
|
||||
if len(params) > 0 {
|
||||
vars = make(map[string]interface{}, len(view.data) + len(params))
|
||||
for k, v := range params {
|
||||
for k, v := range params[0] {
|
||||
vars[k] = v
|
||||
}
|
||||
for k, v := range view.data {
|
||||
@ -165,7 +174,9 @@ func (view *View) ParseContent(content string, params Params, funcMap...map[stri
|
||||
vars = view.data
|
||||
}
|
||||
} else {
|
||||
vars = params
|
||||
if len(params) > 0 {
|
||||
vars = params[0]
|
||||
}
|
||||
}
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
if err := tpl.Execute(buffer, vars); err != nil {
|
||||
|
||||
@ -111,10 +111,16 @@ func AssertGT(value, expect interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// AssertGTE checks <value> is GREATER OR EQUAL THAN <expect>.
|
||||
// See AssertGE.
|
||||
// Deprecated.
|
||||
func AssertGTE(value, expect interface{}) {
|
||||
AssertGE(value, expect)
|
||||
}
|
||||
|
||||
// AssertGE checks <value> is GREATER OR EQUAL THAN <expect>.
|
||||
// Notice that, only string, integer and float types can be compared by AssertGTE,
|
||||
// others are invalid.
|
||||
func AssertGTE(value, expect interface{}) {
|
||||
func AssertGE(value, expect interface{}) {
|
||||
passed := false
|
||||
switch reflect.ValueOf(expect).Kind() {
|
||||
case reflect.String:
|
||||
@ -157,10 +163,16 @@ func AssertLT(value, expect interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// AssertLTE checks <value> is LESS OR EQUAL THAN <expect>.
|
||||
// See AssertLE.
|
||||
// Deprecated.
|
||||
func AssertLTE(value, expect interface{}) {
|
||||
AssertLE(value, expect)
|
||||
}
|
||||
|
||||
// AssertLE checks <value> is LESS OR EQUAL THAN <expect>.
|
||||
// Notice that, only string, integer and float types can be compared by AssertLTE,
|
||||
// others are invalid.
|
||||
func AssertLTE(value, expect interface{}) {
|
||||
func AssertLE(value, expect interface{}) {
|
||||
passed := false
|
||||
switch reflect.ValueOf(expect).Kind() {
|
||||
case reflect.String:
|
||||
|
||||
@ -62,7 +62,7 @@ func Export(i...interface{}) string {
|
||||
func PrintBacktrace() {
|
||||
index := 1
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
for i := 0; i < 10000; i++ {
|
||||
for i := 1; i < 10000; i++ {
|
||||
if _, path, line, ok := runtime.Caller(i); ok {
|
||||
buffer.WriteString(fmt.Sprintf(`%d. %s:%d%s`, index, path, line, "\n"))
|
||||
index++
|
||||
|
||||
@ -6,13 +6,12 @@ import (
|
||||
|
||||
func main() {
|
||||
s := ghttp.GetServer()
|
||||
s.EnableAdmin()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Writeln("您可以同时通过HTTP和HTTPS方式看到该内容!")
|
||||
})
|
||||
s.EnableHTTPS("./server.crt", "./server.key")
|
||||
s.SetHTTPSPort(8198, 8199)
|
||||
s.SetPort(8200, 8300)
|
||||
s.SetHTTPSPort(8100, 8200)
|
||||
s.SetPort(8300, 8400)
|
||||
s.EnableAdmin()
|
||||
s.Run()
|
||||
}
|
||||
|
||||
16
geg/net/ghttp/server/template/build-in/objects/objects.go
Normal file
16
geg/net/ghttp/server/template/build-in/objects/objects.go
Normal file
@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
content := `{{.Request.Get "name"}}`
|
||||
r.Response.WriteTplContent(content)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -10,8 +10,13 @@ func main() {
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Cookie.Set("theme", "default")
|
||||
r.Session.Set("name", "john")
|
||||
content := `Config:{{.Config.redis.cache}}, Cookie:{{.Cookie.theme}}, Session:{{.Session.name}}`
|
||||
r.Response.WriteTplContent(content, nil)
|
||||
content := `
|
||||
Get: {{.Get.name}}
|
||||
Post: {{.Post.name}}
|
||||
Config: {{.Config.redis}}
|
||||
Cookie: {{.Cookie.theme}},
|
||||
Session: {{.Session.name}}`
|
||||
r.Response.WriteTplContent(content)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/frame/gmvc"
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
)
|
||||
@ -11,7 +12,7 @@ type ControllerIndex struct {
|
||||
|
||||
func (c *ControllerIndex) Info() {
|
||||
c.View.Assign("title", "Go Frame 第一个网站")
|
||||
c.View.Assigns(map[string]interface{}{
|
||||
c.View.Assigns(g.Map{
|
||||
"name": "很开心1",
|
||||
"score": 100,
|
||||
})
|
||||
|
||||
@ -14,9 +14,6 @@ func main() {
|
||||
s.SetAccessLogEnabled(true)
|
||||
s.SetPort(2333)
|
||||
|
||||
v := g.View()
|
||||
v.AddPath("template")
|
||||
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
content, _ := gins.View().Parse("test.html", nil)
|
||||
r.Response.Write(content)
|
||||
|
||||
45
geg/os/gview/build_in_funcs/build_in_funcs2.go
Normal file
45
geg/os/gview/build_in_funcs/build_in_funcs2.go
Normal file
@ -0,0 +1,45 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
tplContent := `
|
||||
eq:
|
||||
eq "a" "a": {{eq "a" "a"}}
|
||||
eq "1" "1": {{eq "1" "1"}}
|
||||
eq 1 "1": {{eq 1 "1"}}
|
||||
|
||||
ne:
|
||||
ne 1 "1": {{ne 1 "1"}}
|
||||
ne "a" "a": {{ne "a" "a"}}
|
||||
ne "a" "b": {{ne "a" "b"}}
|
||||
|
||||
lt:
|
||||
lt 1 "2": {{lt 1 "2"}}
|
||||
lt 2 2 : {{lt 2 2 }}
|
||||
lt "a" "b": {{lt "a" "b"}}
|
||||
|
||||
le:
|
||||
le 1 "2": {{le 1 "2"}}
|
||||
le 2 1 : {{le 2 1 }}
|
||||
le "a" "a": {{le "a" "a"}}
|
||||
|
||||
gt:
|
||||
gt 1 "2": {{gt 1 "2"}}
|
||||
gt 2 1 : {{gt 2 1 }}
|
||||
gt "a" "a": {{gt "a" "a"}}
|
||||
|
||||
ge:
|
||||
ge 1 "2": {{ge 1 "2"}}
|
||||
ge 2 1 : {{ge 2 1 }}
|
||||
ge "a" "a": {{ge "a" "a"}}
|
||||
`
|
||||
content, err := g.View().ParseContent(tplContent, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(content)
|
||||
}
|
||||
@ -2,14 +2,20 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
"github.com/gogf/gf/g/frame/gmvc"
|
||||
)
|
||||
|
||||
|
||||
type Controller struct {
|
||||
gmvc.Controller
|
||||
}
|
||||
|
||||
func (c *Controller) Test() {
|
||||
c.View.Display("layout.html")
|
||||
}
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.WriteTpl("layout.html", nil)
|
||||
})
|
||||
s.BindControllerMethod("/", new(Controller), "Test")
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
@ -1,52 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gset"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 创建一个非并发安全的集合对象
|
||||
s := gset.New(true)
|
||||
|
||||
// 添加数据项
|
||||
s.Add(1)
|
||||
|
||||
// 批量添加数据项
|
||||
s.Add([]interface{}{1, 2, 3}...)
|
||||
|
||||
// 集合数据项大小
|
||||
fmt.Println(s.Size())
|
||||
|
||||
// 集合中是否存在指定数据项
|
||||
fmt.Println(s.Contains(2))
|
||||
|
||||
// 返回数据项slice
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// 删除数据项
|
||||
s.Remove(3)
|
||||
|
||||
// 遍历数据项
|
||||
s.Iterator(func(v interface{}) bool {
|
||||
fmt.Println("Iterator:", v)
|
||||
return true
|
||||
})
|
||||
|
||||
// 将集合转换为字符串
|
||||
fmt.Println(s.String())
|
||||
|
||||
// 并发安全写锁操作
|
||||
s.LockFunc(func(m map[interface{}]struct{}) {
|
||||
m[4] = struct{}{}
|
||||
})
|
||||
|
||||
// 并发安全读锁操作
|
||||
s.RLockFunc(func(m map[interface{}]struct{}) {
|
||||
fmt.Println(m)
|
||||
})
|
||||
|
||||
// 清空集合
|
||||
s.Clear()
|
||||
fmt.Println(s.Size())
|
||||
array := make([]interface{}, 0, 10)
|
||||
array[8] = 1
|
||||
fmt.Println(array)
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package gf
|
||||
|
||||
const VERSION = "v1.6.4"
|
||||
const VERSION = "v1.6.6"
|
||||
const AUTHORS = "john<john@goframe.org>"
|
||||
|
||||
Reference in New Issue
Block a user