Merge branch 'master' into export_responsewriter_app_engine

* master:
  Fixes bug when status code is negative
  Update README.md
  Updates CHANGELOG and AUTHORS
  Fixes html debug mode
  Using test mode
  Adds TestMode
  HTML template debug mode.
  Update README.md
  Typo in AUTHORS
  Adds debug mode (part 1)
  Updates AUTHORS.md
  Updates CHANGELOG
  Update README.md
This commit is contained in:
Wael M. Nasreddine 2014-08-24 14:55:44 -07:00
commit ae4800e50f
9 changed files with 134 additions and 30 deletions

View File

@ -5,7 +5,7 @@ List of all the awesome people working to make Gin the best Web Framework in Go!
##gin 0.x series authors ##gin 0.x series authors
**Lead Developer:** Manu Martinez-Almeida (@manucorporat) **Lead Developer:** Manu Martinez-Almeida (@manucorporat)
**Stuff:** **Staff:**
Javier Provecho (@javierprovecho) Javier Provecho (@javierprovecho)
People and companies, who have contributed, in alphabetical order. People and companies, who have contributed, in alphabetical order.
@ -22,10 +22,13 @@ People and companies, who have contributed, in alphabetical order.
- Using template.Must to fix multiple return issue - Using template.Must to fix multiple return issue
- ★ Added support for OPTIONS verb - ★ Added support for OPTIONS verb
- ★ Setting response headers before calling WriteHeader - ★ Setting response headers before calling WriteHeader
- Improved documentation for model binding
- ★ Added Content.Redirect()
- ★ Added tons of Unit tests
**@austinheap (Austin Heap)** **@austinheap (Austin Heap)**
- Adds travis CI integration - Added travis CI integration
**@bluele (Jun Kimura)** **@bluele (Jun Kimura)**
@ -67,20 +70,23 @@ People and companies, who have contributed, in alphabetical order.
**@mdigger (Dmitry Sedykh)** **@mdigger (Dmitry Sedykh)**
- Fixes Form binding when content-type is x-www-form-urlencoded - Fixes Form binding when content-type is x-www-form-urlencoded
- No repeat call c.Writer.Status() in gin.Logger - No repeat call c.Writer.Status() in gin.Logger
- Fixed Content-Type for json render - Fixes Content-Type for json render
**@mopemope (Yutaka Matsubara)** **@mopemope (Yutaka Matsubara)**
- ★ Adds Godep support (Dependencies Manager) - ★ Adds Godep support (Dependencies Manager)
- Fix variadic parameter in the flexible render API - Fix variadic parameter in the flexible render API
- Fix Corrupted plain render - Fix Corrupted plain render
- Fix variadic parameter in new flexible render API
**@msemenistyi (Mykyta Semenistyi)** **@msemenistyi (Mykyta Semenistyi)**
- update Readme.md. Add code to String method - update Readme.md. Add code to String method
**@msoedov (Sasha Myasoedov)**
- ★ Adds tons of unit tests.
**@ngerakines (Nick Gerakines)** **@ngerakines (Nick Gerakines)**
- ★ Improves API, c.GET() doesn't panic - ★ Improves API, c.GET() doesn't panic
- Adds MustGet() method - Adds MustGet() method
@ -95,4 +101,8 @@ People and companies, who have contributed, in alphabetical order.
**@SkuliOskarsson (Skuli Oskarsson)** **@SkuliOskarsson (Skuli Oskarsson)**
- Fixes some texts in README II - Fixes some texts in README II
**@yuyabee**
- Fixed README

View File

@ -1,6 +1,12 @@
##Changelog #Changelog
###Gin 0.4 (??) ###Gin 0.4 (Aug 21, 2014)
- [NEW] Development mode
- [NEW] Unit tests
- [NEW] Add Content.Redirect()
- [FIX] Deferring WriteHeader()
- [FIX] Improved documentation for model binding
###Gin 0.3 (Jul 18, 2014) ###Gin 0.3 (Jul 18, 2014)

View File

@ -1,6 +1,6 @@
#Gin Web Framework #Gin Web Framework
[![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.png)](https://godoc.org/github.com/gin-gonic/gin) [![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://godoc.org/github.com/gin-gonic/gin)
[![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin) [![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin)
Gin is a web framework written in Golang. It features a martini-like API with much better performance, up to 40 times faster. If you need performance and good productivity, you will love Gin. Gin is a web framework written in Golang. It features a martini-like API with much better performance, up to 40 times faster. If you need performance and good productivity, you will love Gin.
@ -324,12 +324,13 @@ func main() {
Issuing a HTTP redirect is easy: Issuing a HTTP redirect is easy:
```r.GET("/test", func(c *gin.Context) { ```go
r.GET("/test", func(c *gin.Context) {
c.Redirect(301, "http://www.google.com/") c.Redirect(301, "http://www.google.com/")
}) })
Both internal and external locations are supported.
``` ```
Both internal and external locations are supported.
#### Custom Middlewares #### Custom Middlewares
@ -425,7 +426,7 @@ func main() {
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
// note than you are using the copied context "c_cp", IMPORTANT // note than you are using the copied context "c_cp", IMPORTANT
log.Println("Done! in path " + c_cp.Req.URL.Path) log.Println("Done! in path " + c_cp.Request.URL.Path)
}() }()
}) })
@ -435,7 +436,7 @@ func main() {
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
// since we are NOT using a goroutine, we do not have to copy the context // since we are NOT using a goroutine, we do not have to copy the context
log.Println("Done! in path " + c.Req.URL.Path) log.Println("Done! in path " + c.Request.URL.Path)
}) })
// Listen and server on 0.0.0.0:8080 // Listen and server on 0.0.0.0:8080

28
gin.go
View File

@ -1,6 +1,7 @@
package gin package gin
import ( import (
"fmt"
"github.com/gin-gonic/gin/render" "github.com/gin-gonic/gin/render"
"github.com/julienschmidt/httprouter" "github.com/julienschmidt/httprouter"
"html/template" "html/template"
@ -73,13 +74,21 @@ func Default() *Engine {
} }
func (engine *Engine) LoadHTMLGlob(pattern string) { func (engine *Engine) LoadHTMLGlob(pattern string) {
templ := template.Must(template.ParseGlob(pattern)) if gin_mode == debugCode {
engine.SetHTMLTemplate(templ) engine.HTMLRender = render.HTMLDebug
} else {
templ := template.Must(template.ParseGlob(pattern))
engine.SetHTMLTemplate(templ)
}
} }
func (engine *Engine) LoadHTMLFiles(files ...string) { func (engine *Engine) LoadHTMLFiles(files ...string) {
templ := template.Must(template.ParseFiles(files...)) if gin_mode == debugCode {
engine.SetHTMLTemplate(templ) engine.HTMLRender = render.HTMLDebug
} else {
templ := template.Must(template.ParseFiles(files...))
engine.SetHTMLTemplate(templ)
}
} }
func (engine *Engine) SetHTMLTemplate(templ *template.Template) { func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
@ -105,12 +114,18 @@ func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
func (engine *Engine) Run(addr string) { func (engine *Engine) Run(addr string) {
if gin_mode == debugCode {
fmt.Println("[GIN-debug] Listening and serving HTTP on " + addr)
}
if err := http.ListenAndServe(addr, engine); err != nil { if err := http.ListenAndServe(addr, engine); err != nil {
panic(err) panic(err)
} }
} }
func (engine *Engine) RunTLS(addr string, cert string, key string) { func (engine *Engine) RunTLS(addr string, cert string, key string) {
if gin_mode == debugCode {
fmt.Println("[GIN-debug] Listening and serving HTTPS on " + addr)
}
if err := http.ListenAndServeTLS(addr, cert, key, engine); err != nil { if err := http.ListenAndServeTLS(addr, cert, key, engine); err != nil {
panic(err) panic(err)
} }
@ -160,6 +175,11 @@ func (group *RouterGroup) pathFor(p string) string {
func (group *RouterGroup) Handle(method, p string, handlers []HandlerFunc) { func (group *RouterGroup) Handle(method, p string, handlers []HandlerFunc) {
p = group.pathFor(p) p = group.pathFor(p)
handlers = group.combineHandlers(handlers) handlers = group.combineHandlers(handlers)
if gin_mode == debugCode {
nuHandlers := len(handlers)
name := funcName(handlers[nuHandlers-1])
fmt.Printf("[GIN-debug] %-5s %-25s --> %s (%d handlers)\n", method, p, name, nuHandlers)
}
group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) { group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
c := group.engine.createContext(w, req, params, handlers) c := group.engine.createContext(w, req, params, handlers)
c.Next() c.Next()

View File

@ -10,6 +10,10 @@ import (
"testing" "testing"
) )
func init() {
SetMode(TestMode)
}
func PerformRequest(r http.Handler, method, path string) *httptest.ResponseRecorder { func PerformRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
req, _ := http.NewRequest(method, path, nil) req, _ := http.NewRequest(method, path, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()

42
mode.go Normal file
View File

@ -0,0 +1,42 @@
package gin
import (
"os"
)
const GIN_MODE = "GIN_MODE"
const (
DebugMode string = "debug"
ReleaseMode string = "release"
TestMode string = "test"
)
const (
debugCode = iota
releaseCode = iota
testCode = iota
)
var gin_mode int = debugCode
func SetMode(value string) {
switch value {
case DebugMode:
gin_mode = debugCode
case ReleaseMode:
gin_mode = releaseCode
case TestMode:
gin_mode = testCode
default:
panic("gin mode unknown, the allowed modes are: " + DebugMode + " and " + ReleaseMode)
}
}
func init() {
value := os.Getenv(GIN_MODE)
if len(value) == 0 {
SetMode(DebugMode)
} else {
SetMode(value)
}
}

View File

@ -25,6 +25,9 @@ type (
// Redirects // Redirects
redirectRender struct{} redirectRender struct{}
// Redirects
htmlDebugRender struct{}
// form binding // form binding
HTMLRender struct { HTMLRender struct {
Template *template.Template Template *template.Template
@ -32,10 +35,11 @@ type (
) )
var ( var (
JSON = jsonRender{} JSON = jsonRender{}
XML = xmlRender{} XML = xmlRender{}
Plain = plainRender{} Plain = plainRender{}
Redirect = redirectRender{} Redirect = redirectRender{}
HTMLDebug = htmlDebugRender{}
) )
func writeHeader(w http.ResponseWriter, code int, contentType string) { func writeHeader(w http.ResponseWriter, code int, contentType string) {
@ -61,13 +65,6 @@ func (_ xmlRender) Render(w http.ResponseWriter, code int, data ...interface{})
return encoder.Encode(data[0]) return encoder.Encode(data[0])
} }
func (html HTMLRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
writeHeader(w, code, "text/html")
file := data[0].(string)
obj := data[1]
return html.Template.ExecuteTemplate(w, file, obj)
}
func (_ plainRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { func (_ plainRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
writeHeader(w, code, "text/plain") writeHeader(w, code, "text/plain")
format := data[0].(string) format := data[0].(string)
@ -80,3 +77,21 @@ func (_ plainRender) Render(w http.ResponseWriter, code int, data ...interface{}
} }
return err return err
} }
func (_ htmlDebugRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
writeHeader(w, code, "text/html")
file := data[0].(string)
obj := data[1]
t, err := template.ParseFiles(file)
if err != nil {
return err
}
return t.ExecuteTemplate(w, file, obj)
}
func (html HTMLRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
writeHeader(w, code, "text/html")
file := data[0].(string)
obj := data[1]
return html.Template.ExecuteTemplate(w, file, obj)
}

View File

@ -27,7 +27,7 @@ func (w *responseWriter) reset(writer http.ResponseWriter) {
} }
func (w *responseWriter) WriteHeader(code int) { func (w *responseWriter) WriteHeader(code int) {
if code != 0 { if code > 0 {
w.status = code w.status = code
if w.written { if w.written {
log.Println("[GIN] WARNING. Headers were already written!") log.Println("[GIN] WARNING. Headers were already written!")

View File

@ -2,6 +2,8 @@ package gin
import ( import (
"encoding/xml" "encoding/xml"
"reflect"
"runtime"
) )
type H map[string]interface{} type H map[string]interface{}
@ -38,3 +40,7 @@ func filterFlags(content string) string {
} }
return content return content
} }
func funcName(f interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
}