diff --git a/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/bindata.go b/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/bindata.go index 74181a48..d020adb7 100644 --- a/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/bindata.go +++ b/_examples/file-server/single-page-application/embedded-single-page-application-with-other-routes/bindata.go @@ -182,9 +182,9 @@ func AssetNames() []string { // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ - "public/app.js": publicAppJs, + "public/app.js": publicAppJs, "public/css/main.css": publicCssMainCss, - "public/index.html": publicIndexHtml, + "public/index.html": publicIndexHtml, } // AssetDir returns the file names below a certain @@ -226,13 +226,14 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } + var _bintree = &bintree{nil, map[string]*bintree{ - "public": &bintree{nil, map[string]*bintree{ - "app.js": &bintree{publicAppJs, map[string]*bintree{}}, - "css": &bintree{nil, map[string]*bintree{ - "main.css": &bintree{publicCssMainCss, map[string]*bintree{}}, + "public": {nil, map[string]*bintree{ + "app.js": {publicAppJs, map[string]*bintree{}}, + "css": {nil, map[string]*bintree{ + "main.css": {publicCssMainCss, map[string]*bintree{}}, }}, - "index.html": &bintree{publicIndexHtml, map[string]*bintree{}}, + "index.html": {publicIndexHtml, map[string]*bintree{}}, }}, }} @@ -282,4 +283,3 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } - diff --git a/_examples/http_responsewriter/quicktemplate/templates/base.qtpl.go b/_examples/http_responsewriter/quicktemplate/templates/base.qtpl.go new file mode 100644 index 00000000..32a5e638 --- /dev/null +++ b/_examples/http_responsewriter/quicktemplate/templates/base.qtpl.go @@ -0,0 +1,128 @@ +// This file is automatically generated by qtc from "base.qtpl". +// See https://github.com/valyala/quicktemplate for details. + +// This is our templates' base implementation. +// + +//line base.qtpl:3 +package templates + +//line base.qtpl:3 +import ( + qtio422016 "io" + + qt422016 "github.com/valyala/quicktemplate" +) + +//line base.qtpl:3 +var ( + _ = qtio422016.Copy + _ = qt422016.AcquireByteBuffer +) + +//line base.qtpl:4 +type Partial interface { + //line base.qtpl:4 + Body() string + //line base.qtpl:4 + StreamBody(qw422016 *qt422016.Writer) + //line base.qtpl:4 + WriteBody(qq422016 qtio422016.Writer) +//line base.qtpl:4 +} + +// Template writes a template implementing the Partial interface. + +//line base.qtpl:11 +func StreamTemplate(qw422016 *qt422016.Writer, p Partial) { + //line base.qtpl:11 + qw422016.N().S(` + + + Quicktemplate integration with Iris + + +
+ Header contents here... +
+ +
+ `) + //line base.qtpl:22 + p.StreamBody(qw422016) + //line base.qtpl:22 + qw422016.N().S(` +
+ + + + +`) +//line base.qtpl:30 +} + +//line base.qtpl:30 +func WriteTemplate(qq422016 qtio422016.Writer, p Partial) { + //line base.qtpl:30 + qw422016 := qt422016.AcquireWriter(qq422016) + //line base.qtpl:30 + StreamTemplate(qw422016, p) + //line base.qtpl:30 + qt422016.ReleaseWriter(qw422016) +//line base.qtpl:30 +} + +//line base.qtpl:30 +func Template(p Partial) string { + //line base.qtpl:30 + qb422016 := qt422016.AcquireByteBuffer() + //line base.qtpl:30 + WriteTemplate(qb422016, p) + //line base.qtpl:30 + qs422016 := string(qb422016.B) + //line base.qtpl:30 + qt422016.ReleaseByteBuffer(qb422016) + //line base.qtpl:30 + return qs422016 +//line base.qtpl:30 +} + +// Base template implementation. Other pages may inherit from it if they need +// overriding only certain Partial methods. + +//line base.qtpl:35 +type Base struct{} + +//line base.qtpl:36 +func (b *Base) StreamBody(qw422016 *qt422016.Writer) { +//line base.qtpl:36 +qw422016.N().S(`This is the base body`) } + +//line base.qtpl:36 +//line base.qtpl:36 +func (b *Base) WriteBody(qq422016 qtio422016.Writer) { + //line base.qtpl:36 + qw422016 := qt422016.AcquireWriter(qq422016) + //line base.qtpl:36 + b.StreamBody(qw422016) + //line base.qtpl:36 + qt422016.ReleaseWriter(qw422016) +//line base.qtpl:36 +} + +//line base.qtpl:36 +func (b *Base) Body() string { + //line base.qtpl:36 + qb422016 := qt422016.AcquireByteBuffer() + //line base.qtpl:36 + b.WriteBody(qb422016) + //line base.qtpl:36 + qs422016 := string(qb422016.B) + //line base.qtpl:36 + qt422016.ReleaseByteBuffer(qb422016) + //line base.qtpl:36 + return qs422016 +//line base.qtpl:36 +} diff --git a/_examples/http_responsewriter/quicktemplate/templates/hello.qtpl.go b/_examples/http_responsewriter/quicktemplate/templates/hello.qtpl.go new file mode 100644 index 00000000..5b812bfb --- /dev/null +++ b/_examples/http_responsewriter/quicktemplate/templates/hello.qtpl.go @@ -0,0 +1,72 @@ +// This file is automatically generated by qtc from "hello.qtpl". +// See https://github.com/valyala/quicktemplate for details. + +// Hello template, implements the Partial's methods. +// + +//line hello.qtpl:3 +package templates + +//line hello.qtpl:3 +import ( + qtio422016 "io" + + qt422016 "github.com/valyala/quicktemplate" +) + +//line hello.qtpl:3 +var ( + _ = qtio422016.Copy + _ = qt422016.AcquireByteBuffer +) + +//line hello.qtpl:4 +type Hello struct { + Vars map[string]interface{} +} + +//line hello.qtpl:9 +func (h *Hello) StreamBody(qw422016 *qt422016.Writer) { + //line hello.qtpl:9 + qw422016.N().S(` +

`) + //line hello.qtpl:10 + qw422016.E().V(h.Vars["message"]) + //line hello.qtpl:10 + qw422016.N().S(`

+
+ Hello `) + //line hello.qtpl:12 + qw422016.E().V(h.Vars["name"]) + //line hello.qtpl:12 + qw422016.N().S(`! +
+`) +//line hello.qtpl:14 +} + +//line hello.qtpl:14 +func (h *Hello) WriteBody(qq422016 qtio422016.Writer) { + //line hello.qtpl:14 + qw422016 := qt422016.AcquireWriter(qq422016) + //line hello.qtpl:14 + h.StreamBody(qw422016) + //line hello.qtpl:14 + qt422016.ReleaseWriter(qw422016) +//line hello.qtpl:14 +} + +//line hello.qtpl:14 +func (h *Hello) Body() string { + //line hello.qtpl:14 + qb422016 := qt422016.AcquireByteBuffer() + //line hello.qtpl:14 + h.WriteBody(qb422016) + //line hello.qtpl:14 + qs422016 := string(qb422016.B) + //line hello.qtpl:14 + qt422016.ReleaseByteBuffer(qb422016) + //line hello.qtpl:14 + return qs422016 +//line hello.qtpl:14 +} diff --git a/_examples/http_responsewriter/quicktemplate/templates/index.qtpl.go b/_examples/http_responsewriter/quicktemplate/templates/index.qtpl.go new file mode 100644 index 00000000..e5297ac4 --- /dev/null +++ b/_examples/http_responsewriter/quicktemplate/templates/index.qtpl.go @@ -0,0 +1,62 @@ +// This file is automatically generated by qtc from "index.qtpl". +// See https://github.com/valyala/quicktemplate for details. + +// Index template, implements the Partial's methods. +// + +//line index.qtpl:3 +package templates + +//line index.qtpl:3 +import ( + qtio422016 "io" + + qt422016 "github.com/valyala/quicktemplate" +) + +//line index.qtpl:3 +var ( + _ = qtio422016.Copy + _ = qt422016.AcquireByteBuffer +) + +//line index.qtpl:4 +type Index struct{} + +//line index.qtpl:7 +func (i *Index) StreamBody(qw422016 *qt422016.Writer) { + //line index.qtpl:7 + qw422016.N().S(` +

Index Page

+
+ This is our index page's body. +
+`) +//line index.qtpl:12 +} + +//line index.qtpl:12 +func (i *Index) WriteBody(qq422016 qtio422016.Writer) { + //line index.qtpl:12 + qw422016 := qt422016.AcquireWriter(qq422016) + //line index.qtpl:12 + i.StreamBody(qw422016) + //line index.qtpl:12 + qt422016.ReleaseWriter(qw422016) +//line index.qtpl:12 +} + +//line index.qtpl:12 +func (i *Index) Body() string { + //line index.qtpl:12 + qb422016 := qt422016.AcquireByteBuffer() + //line index.qtpl:12 + i.WriteBody(qb422016) + //line index.qtpl:12 + qs422016 := string(qb422016.B) + //line index.qtpl:12 + qt422016.ReleaseByteBuffer(qb422016) + //line index.qtpl:12 + return qs422016 +//line index.qtpl:12 +} diff --git a/_examples/structuring/bootstrap/main.go b/_examples/structuring/bootstrap/main.go index 158b31c4..3d335caf 100644 --- a/_examples/structuring/bootstrap/main.go +++ b/_examples/structuring/bootstrap/main.go @@ -6,9 +6,14 @@ import ( "github.com/kataras/iris/_examples/structuring/bootstrap/routes" ) -func main() { +func newApp() *bootstrap.Bootstrapper { app := bootstrap.New("Awesome App", "kataras2006@hotmail.com") app.Bootstrap() app.Configure(identity.Configure, routes.Configure) + return app +} + +func main() { + app := newApp() app.Listen(":8080") } diff --git a/_examples/structuring/bootstrap/main_test.go b/_examples/structuring/bootstrap/main_test.go index e9d5065e..1fe5f562 100644 --- a/_examples/structuring/bootstrap/main_test.go +++ b/_examples/structuring/bootstrap/main_test.go @@ -8,6 +8,7 @@ import ( // go test -v func TestApp(t *testing.T) { + app := newApp() e := httptest.New(t, app.Application) // test our routes diff --git a/_examples/websocket/connectionlist/main.go b/_examples/websocket/connectionlist/main.go index f13bc02f..f736bb21 100644 --- a/_examples/websocket/connectionlist/main.go +++ b/_examples/websocket/connectionlist/main.go @@ -77,7 +77,7 @@ func main() { go func() { i := 0 - for range time.Tick(1*time.Second){ //another way to get clock signal + for range time.Tick(1 * time.Second) { //another way to get clock signal mutex.Lock() broadcast(Conn, fmt.Sprintf("aaaa2 %d\n", i)) mutex.Unlock() diff --git a/context/context.go b/context/context.go index ee09f300..b357f936 100644 --- a/context/context.go +++ b/context/context.go @@ -91,6 +91,17 @@ func (r *RequestParams) Visit(visitor func(key string, value string)) { }) } +// GetEntry returns the internal Entry of the memstore, as value +// if not found then it returns a zero Entry and false. +func (r RequestParams) GetEntry(key string) (memstore.Entry, bool) { + // we don't return the pointer here, we don't want to give the end-developer + // the strength to change the entry that way. + if e := r.store.GetEntry(key); e != nil { + return *e, true + } + return memstore.Entry{}, false +} + // Get returns a path parameter's value based on its route's dynamic path key. func (r RequestParams) Get(key string) string { return r.store.GetString(key) diff --git a/core/memstore/memstore.go b/core/memstore/memstore.go index ed6bd78b..93e5a557 100644 --- a/core/memstore/memstore.go +++ b/core/memstore/memstore.go @@ -25,6 +25,150 @@ type ( Store []Entry ) +func (e Entry) GetByKindOrNil(k reflect.Kind) interface{} { + switch k { + case reflect.String: + v := e.StringDefault("__$nf") + if v == "__$nf" { + return nil + } + return v + case reflect.Int: + v, err := e.IntDefault(-1) + if err != nil || v == -1 { + return nil + } + return v + case reflect.Int64: + v, err := e.Int64Default(-1) + if err != nil || v == -1 { + return nil + } + return v + case reflect.Bool: + v, err := e.BoolDefault(false) + if err != nil { + return nil + } + return v + default: + return e.ValueRaw + } +} + +// StringDefault returns the entry's value as string. +// If not found returns "def". +func (e Entry) StringDefault(def string) string { + v := e.ValueRaw + + if vString, ok := v.(string); ok { + return vString + } + + return def +} + +// String returns the entry's value as string. +func (e Entry) String() string { + return e.StringDefault("") +} + +// StringTrim returns the entry's string value without trailing spaces. +func (e Entry) StringTrim() string { + return strings.TrimSpace(e.String()) +} + +// ErrIntParse returns an error message when int parse failed +// it's not statical error, it depends on the failed value. +var ErrIntParse = errors.New("unable to find or parse the integer, found: %#v") + +// IntDefault returns the entry's value as int. +// If not found returns "def". +func (e Entry) IntDefault(def int) (int, error) { + v := e.ValueRaw + if v == nil { + return def, nil + } + if vint, ok := v.(int); ok { + return vint, nil + } else if vstring, sok := v.(string); sok { + if vstring == "" { + return def, nil + } + return strconv.Atoi(vstring) + } + + return def, nil +} + +// Int64Default returns the entry's value as int64. +// If not found returns "def". +func (e Entry) Int64Default(def int64) (int64, error) { + v := e.ValueRaw + if v == nil { + return def, nil + } + if vint64, ok := v.(int64); ok { + return vint64, nil + } else if vstring, sok := v.(string); sok { + if vstring == "" { + return def, nil + } + return strconv.ParseInt(vstring, 10, 64) + } + + return def, nil +} + +// Float64Default returns the entry's value as float64. +// If not found returns "def". +func (e Entry) Float64Default(def float64) (float64, error) { + v := e.ValueRaw + if v == nil { + return def, nil + } + if vfloat64, ok := v.(float64); ok { + return vfloat64, nil + } else if vstring, sok := v.(string); sok { + if vstring == "" { + return def, nil + } + return strconv.ParseFloat(vstring, 64) + } + + return def, nil +} + +// BoolDefault returns the user's value as bool. +// a string which is "1" or "t" or "T" or "TRUE" or "true" or "True" +// or "0" or "f" or "F" or "FALSE" or "false" or "False". +// Any other value returns an error. +// +// If not found returns "def". +func (e Entry) BoolDefault(def bool) (bool, error) { + v := e.ValueRaw + if v == nil { + return def, nil + } + + if vBoolean, ok := v.(bool); ok { + return vBoolean, nil + } + + if vString, ok := v.(string); ok { + return strconv.ParseBool(vString) + } + + if vInt, ok := v.(int); ok { + if vInt == 1 { + return true, nil + } + return false, nil + } + + return def, nil +} + // Value returns the value of the entry, // respects the immutable. func (e Entry) Value() interface{} { @@ -128,19 +272,35 @@ func (r *Store) SetImmutable(key string, value interface{}) (Entry, bool) { return r.Save(key, value, true) } -// GetDefault returns the entry's value based on its key. -// If not found returns "def". -func (r *Store) GetDefault(key string, def interface{}) interface{} { +// GetEntry returns a pointer to the "Entry" found with the given "key" +// if nothing found then it returns nil, so be careful with that, +// it's not supposed to be used by end-developers. +func (r *Store) GetEntry(key string) *Entry { args := *r n := len(args) for i := 0; i < n; i++ { kv := &args[i] if kv.Key == key { - return kv.Value() + return kv } } - return def + return nil +} + +// GetDefault returns the entry's value based on its key. +// If not found returns "def". +// This function checks for immutability as well, the rest don't. +func (r *Store) GetDefault(key string, def interface{}) interface{} { + v := r.GetEntry(key) + if v == nil || v.ValueRaw == nil { + return def + } + vv := v.Value() + if vv == nil { + return def + } + return vv } // Get returns the entry's value based on its key. @@ -162,16 +322,12 @@ func (r *Store) Visit(visitor func(key string, value interface{})) { // GetStringDefault returns the entry's value as string, based on its key. // If not found returns "def". func (r *Store) GetStringDefault(key string, def string) string { - v := r.Get(key) + v := r.GetEntry(key) if v == nil { return def } - if vString, ok := v.(string); ok { - return vString - } - - return def + return v.StringDefault(def) } // GetString returns the entry's value as string, based on its key. @@ -184,27 +340,14 @@ func (r *Store) GetStringTrim(name string) string { return strings.TrimSpace(r.GetString(name)) } -// ErrIntParse returns an error message when int parse failed -// it's not statical error, it depends on the failed value. -var ErrIntParse = errors.New("unable to find or parse the integer, found: %#v") - // GetIntDefault returns the entry's value as int, based on its key. // If not found returns "def". func (r *Store) GetIntDefault(key string, def int) (int, error) { - v := r.Get(key) + v := r.GetEntry(key) if v == nil { return def, nil } - if vint, ok := v.(int); ok { - return vint, nil - } else if vstring, sok := v.(string); sok { - if vstring == "" { - return def, nil - } - return strconv.Atoi(vstring) - } - - return def, nil + return v.IntDefault(def) } // GetInt returns the entry's value as int, based on its key. @@ -216,20 +359,11 @@ func (r *Store) GetInt(key string) (int, error) { // GetInt64Default returns the entry's value as int64, based on its key. // If not found returns "def". func (r *Store) GetInt64Default(key string, def int64) (int64, error) { - v := r.Get(key) + v := r.GetEntry(key) if v == nil { return def, nil } - if vint64, ok := v.(int64); ok { - return vint64, nil - } else if vstring, sok := v.(string); sok { - if vstring == "" { - return def, nil - } - return strconv.ParseInt(vstring, 10, 64) - } - - return def, nil + return v.Int64Default(def) } // GetInt64 returns the entry's value as int64, based on its key. @@ -241,20 +375,11 @@ func (r *Store) GetInt64(key string) (int64, error) { // GetFloat64Default returns the entry's value as float64, based on its key. // If not found returns "def". func (r *Store) GetFloat64Default(key string, def float64) (float64, error) { - v := r.Get(key) + v := r.GetEntry(key) if v == nil { return def, nil } - if vfloat64, ok := v.(float64); ok { - return vfloat64, nil - } else if vstring, sok := v.(string); sok { - if vstring == "" { - return def, nil - } - return strconv.ParseFloat(vstring, 64) - } - - return def, nil + return v.Float64Default(def) } // GetFloat64 returns the entry's value as float64, based on its key. @@ -270,27 +395,11 @@ func (r *Store) GetFloat64(key string) (float64, error) { // // If not found returns "def". func (r *Store) GetBoolDefault(key string, def bool) (bool, error) { - v := r.Get(key) + v := r.GetEntry(key) if v == nil { return def, nil } - - if vBoolean, ok := v.(bool); ok { - return vBoolean, nil - } - - if vString, ok := v.(string); ok { - return strconv.ParseBool(vString) - } - - if vInt, ok := v.(int); ok { - if vInt == 1 { - return true, nil - } - return false, nil - } - - return def, nil + return v.BoolDefault(def) } // GetBool returns the user's value as bool, based on its key. diff --git a/core/router/macro/interpreter/ast/ast.go b/core/router/macro/interpreter/ast/ast.go index 0f5b33d7..1e39bc85 100644 --- a/core/router/macro/interpreter/ast/ast.go +++ b/core/router/macro/interpreter/ast/ast.go @@ -51,6 +51,23 @@ const ( ParamTypePath ) +// ValidKind will return true if at least one param type is supported +// for this std kind. +func ValidKind(k reflect.Kind) bool { + switch k { + case reflect.String: + fallthrough + case reflect.Int: + fallthrough + case reflect.Int64: + fallthrough + case reflect.Bool: + return true + default: + return false + } +} + // Not because for a single reason // a string may be a // ParamTypeString or a ParamTypeFile @@ -105,6 +122,7 @@ var paramTypes = map[string]ParamType{ // Available: // "string" // "int" +// "long" // "alphabetical" // "file" // "path"