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
**Lead Developer:** Manu Martinez-Almeida (@manucorporat)
**Stuff:**
**Staff:**
Javier Provecho (@javierprovecho)
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
- ★ Added support for OPTIONS verb
- ★ Setting response headers before calling WriteHeader
- Improved documentation for model binding
- ★ Added Content.Redirect()
- ★ Added tons of Unit tests
**@austinheap (Austin Heap)**
- Adds travis CI integration
- Added travis CI integration
**@bluele (Jun Kimura)**
@ -67,20 +70,23 @@ People and companies, who have contributed, in alphabetical order.
**@mdigger (Dmitry Sedykh)**
- Fixes Form binding when content-type is x-www-form-urlencoded
- No repeat call c.Writer.Status() in gin.Logger
- Fixed Content-Type for json render
- Fixes Content-Type for json render
**@mopemope (Yutaka Matsubara)**
- ★ Adds Godep support (Dependencies Manager)
- Fix variadic parameter in the flexible render API
- Fix Corrupted plain render
- Fix variadic parameter in new flexible render API
**@msemenistyi (Mykyta Semenistyi)**
- update Readme.md. Add code to String method
**@msoedov (Sasha Myasoedov)**
- ★ Adds tons of unit tests.
**@ngerakines (Nick Gerakines)**
- ★ Improves API, c.GET() doesn't panic
- Adds MustGet() method
@ -95,4 +101,8 @@ People and companies, who have contributed, in alphabetical order.
**@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)

View File

@ -1,6 +1,6 @@
#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)
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:
```r.GET("/test", func(c *gin.Context) {
```go
r.GET("/test", func(c *gin.Context) {
c.Redirect(301, "http://www.google.com/")
})
Both internal and external locations are supported.
```
Both internal and external locations are supported.
#### Custom Middlewares
@ -425,7 +426,7 @@ func main() {
time.Sleep(5 * time.Second)
// 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)
// 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

28
gin.go
View File

@ -1,6 +1,7 @@
package gin
import (
"fmt"
"github.com/gin-gonic/gin/render"
"github.com/julienschmidt/httprouter"
"html/template"
@ -73,13 +74,21 @@ func Default() *Engine {
}
func (engine *Engine) LoadHTMLGlob(pattern string) {
templ := template.Must(template.ParseGlob(pattern))
engine.SetHTMLTemplate(templ)
if gin_mode == debugCode {
engine.HTMLRender = render.HTMLDebug
} else {
templ := template.Must(template.ParseGlob(pattern))
engine.SetHTMLTemplate(templ)
}
}
func (engine *Engine) LoadHTMLFiles(files ...string) {
templ := template.Must(template.ParseFiles(files...))
engine.SetHTMLTemplate(templ)
if gin_mode == debugCode {
engine.HTMLRender = render.HTMLDebug
} else {
templ := template.Must(template.ParseFiles(files...))
engine.SetHTMLTemplate(templ)
}
}
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) {
if gin_mode == debugCode {
fmt.Println("[GIN-debug] Listening and serving HTTP on " + addr)
}
if err := http.ListenAndServe(addr, engine); err != nil {
panic(err)
}
}
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 {
panic(err)
}
@ -160,6 +175,11 @@ func (group *RouterGroup) pathFor(p string) string {
func (group *RouterGroup) Handle(method, p string, handlers []HandlerFunc) {
p = group.pathFor(p)
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) {
c := group.engine.createContext(w, req, params, handlers)
c.Next()

View File

@ -10,6 +10,10 @@ import (
"testing"
)
func init() {
SetMode(TestMode)
}
func PerformRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
req, _ := http.NewRequest(method, path, nil)
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
redirectRender struct{}
// Redirects
htmlDebugRender struct{}
// form binding
HTMLRender struct {
Template *template.Template
@ -32,10 +35,11 @@ type (
)
var (
JSON = jsonRender{}
XML = xmlRender{}
Plain = plainRender{}
Redirect = redirectRender{}
JSON = jsonRender{}
XML = xmlRender{}
Plain = plainRender{}
Redirect = redirectRender{}
HTMLDebug = htmlDebugRender{}
)
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])
}
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 {
writeHeader(w, code, "text/plain")
format := data[0].(string)
@ -80,3 +77,21 @@ func (_ plainRender) Render(w http.ResponseWriter, code int, data ...interface{}
}
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) {
if code != 0 {
if code > 0 {
w.status = code
if w.written {
log.Println("[GIN] WARNING. Headers were already written!")

View File

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