Update to version 12.1.8 - Read HISTORY.md

Former-commit-id: d3d30cb15537146e3071731be9d674a5cb59de97
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-02-16 11:14:35 +02:00
parent 899aec8b19
commit 08403f0317
21 changed files with 275 additions and 240 deletions

View File

@ -21,6 +21,20 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
**How to upgrade**: Open your command-line and execute this command: `go get github.com/kataras/iris/v12@latest`.
# Su, 16 February 2020 | v12.1.8
New Features:
- [[FEATURE REQUEST] MVC serving gRPC-compatible controller](https://github.com/kataras/iris/issues/1449)
Fixes:
- [App can't find embedded pug template files by go-bindata](https://github.com/kataras/iris/issues/1450)
New Examples:
- [_examples/mvc/grpc-compatible](_examples/mvc/grpc-compatible)
# Mo, 10 February 2020 | v12.1.7
Implement **new** `SetRegisterRule(iris.RouteOverride, RouteSkip, RouteError)` to resolve: https://github.com/kataras/iris/issues/1448

View File

@ -21,9 +21,9 @@ Los desarrolladores no están obligados a actualizar si realmente no lo necesita
**Cómo actualizar**: Abra su línea de comandos y ejecute este comando: `go get github.com/kataras/iris/v12@latest`.
# Mo, 10 February 2020 | v12.1.7
# Su, 16 February 2020 | v12.1.8
Not translated yet, please navigate to the [english version](HISTORY.md#mo-10-february-2020--v1217) instead.
Not translated yet, please navigate to the [english version](HISTORY.md#su-16-february-2020--v1218) instead.
# Sábado, 26 de octubre 2019 | v12.0.0

View File

@ -1,10 +1,11 @@
<!-- # News
# News
![](https://iris-go.com/images/release.png) Iris version **12.1.7** has been [released](HISTORY.md#mo-10-february-2020--v1217)!
![](https://iris-go.com/images/release.png) Iris version **12.1.8** has been [released](HISTORY.md#su-16-february-2020--v1218)!
![](https://iris-go.com/images/cli.png) The official [Iris Command Line Interface](https://github.com/kataras/iris-cli) will soon be near you in 2020!
![](https://iris-go.com/images/sponsor.png) Support your favorite web framework through [Github Sponsors Program](https://github.com/sponsors/kataras)! -->
![](https://iris-go.com/images/sponsor.png) Support your favorite web framework through [Github Sponsors Program](https://github.com/sponsors/kataras)!
# Iris Web Framework <a href="README_ZH.md"><img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a> <a href="README_ES.md"><img width="20px" src="https://iris-go.com/images/flag-spain.png" /></a> <a href="README_KO.md"><img width="20px" src="https://iris-go.com/images/flag-south-korea.svg" /></a> <a href="README_FA.md"><img width="20px" src="https://iris-go.com/images/flag-iran.svg" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg" /></a>
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://godoc.org/github.com/kataras/iris)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://www.paypal.me/kataras)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->

View File

@ -1 +1 @@
12.1.7:https://github.com/kataras/iris/releases/tag/v12.1.7
12.1.8:https://github.com/kataras/iris/releases/tag/v12.1.8

View File

@ -3,6 +3,6 @@ module app
go 1.13
require (
github.com/kataras/iris/v12 v12.1.7
github.com/kataras/iris/v12 v12.1.8
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
)

View File

@ -31,11 +31,19 @@ func newApp() *iris.Application {
return ctx.Request().Context()
}).
// Bind loginRequest.
Register(func(ctx iris.Context) loginRequest {
var req loginRequest
ctx.ReadJSON(&req)
return req
}).
// Register(func(ctx iris.Context) loginRequest {
// var req loginRequest
// ctx.ReadJSON(&req)
// return req
// }).
// OR
// Bind any other structure or pointer to a structure from request's
// XML
// YAML
// Query
// Form
// JSON (default, if not client's "Content-Type" specified otherwise)
Register(mvc.AutoBinding).
Handle(&myController{})
return app

View File

@ -6,7 +6,7 @@ import (
"github.com/kataras/iris/v12/httptest"
)
func TestBindContextContext(t *testing.T) {
func TestGRPCCompatible(t *testing.T) {
app := newApp()
e := httptest.New(t, app)

View File

@ -215,9 +215,9 @@ type bintree struct {
}
var _bintree = &bintree{nil, map[string]*bintree{
"templates": &bintree{nil, map[string]*bintree{
"index.pug": &bintree{templatesIndexPug, map[string]*bintree{}},
"layout.pug": &bintree{templatesLayoutPug, map[string]*bintree{}},
"templates": {nil, map[string]*bintree{
"index.pug": {templatesIndexPug, map[string]*bintree{}},
"layout.pug": {templatesLayoutPug, map[string]*bintree{}},
}},
}}

2
doc.go
View File

@ -38,7 +38,7 @@ Source code and other details for the project are available at GitHub:
Current Version
12.1.7
12.1.8
Installation

View File

@ -1,43 +0,0 @@
package hero
import (
"reflect"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/hero/di"
)
func init() {
di.DefaultHijacker = func(fieldOrFuncInput reflect.Type) (*di.BindObject, bool) {
if !IsContext(fieldOrFuncInput) {
return nil, false
}
// this is being used on both func injector and struct injector.
// if the func's input argument or the struct's field is a type of Context
// then we can do a fast binding using the ctxValue
// which is used as slice of reflect.Value, because of the final method's `Call`.
return &di.BindObject{
Type: contextTyp,
BindType: di.Dynamic,
ReturnValue: func(ctx context.Context) reflect.Value {
return ctx.ReflectValue()[0]
},
}, true
}
di.DefaultTypeChecker = func(fn reflect.Type) bool {
// valid if that single input arg is a typeof context.Context
// or first argument is context.Context and second argument is a variadic, which is ignored (i.e new sessions#Start).
return (fn.NumIn() == 1 || (fn.NumIn() == 2 && fn.IsVariadic())) && IsContext(fn.In(0))
}
di.DefaultErrorHandler = di.ErrorHandlerFunc(func(ctx context.Context, err error) {
if err == nil {
return
}
ctx.StatusCode(400)
ctx.WriteString(err.Error())
ctx.StopExecution()
})
}

View File

@ -9,12 +9,6 @@ import (
)
type (
// Hijacker is a type which is used to catch fields or function's input argument
// to bind a custom object based on their type.
Hijacker func(reflect.Type) (*BindObject, bool)
// TypeChecker checks if a specific field's or function input argument's
// is valid to be binded.
TypeChecker func(reflect.Type) bool
// ErrorHandler is the optional interface to handle errors per hero func,
// see `mvc/Application#HandleError` for MVC application-level error handler registration too.
//
@ -34,15 +28,51 @@ func (fn ErrorHandlerFunc) HandleError(ctx context.Context, err error) {
fn(ctx, err)
}
var (
// DefaultHijacker is the hijacker used on the package-level Struct & Func functions.
DefaultHijacker Hijacker
// DefaultTypeChecker is the typechecker used on the package-level Struct & Func functions.
DefaultTypeChecker TypeChecker
// DefaultErrorHandler is the error handler used on the package-level `Func` function
// to catch any errors from dependencies or handlers.
DefaultErrorHandler ErrorHandler
)
// DefaultErrorHandler is the default error handler will be fired on
// any error from registering a request-scoped dynamic dependency and on a controller's method failure.
var DefaultErrorHandler ErrorHandler = ErrorHandlerFunc(func(ctx context.Context, err error) {
if err == nil {
return
}
ctx.StatusCode(400)
ctx.WriteString(err.Error())
ctx.StopExecution()
})
var emptyValue reflect.Value
// DefaultFallbackBinder used to bind any oprhan inputs. Its error is handled by the `ErrorHandler`.
var DefaultFallbackBinder FallbackBinder = func(ctx context.Context, input OrphanInput) (newValue reflect.Value, err error) {
wasPtr := input.Type.Kind() == reflect.Ptr
newValue = reflect.New(IndirectType(input.Type))
ptr := newValue.Interface()
switch ctx.GetContentTypeRequested() {
case context.ContentXMLHeaderValue:
err = ctx.ReadXML(ptr)
case context.ContentYAMLHeaderValue:
err = ctx.ReadYAML(ptr)
case context.ContentFormHeaderValue:
err = ctx.ReadQuery(ptr)
case context.ContentFormMultipartHeaderValue:
err = ctx.ReadForm(ptr)
default:
err = ctx.ReadJSON(ptr)
// json
}
// if err != nil {
// return emptyValue, err
// }
if !wasPtr {
newValue = newValue.Elem()
}
return newValue, err
}
// Struct is being used to return a new injector based on
// a struct value instance, if it contains fields that the types of those
@ -55,8 +85,6 @@ func Struct(s interface{}, values ...reflect.Value) *StructInjector {
return MakeStructInjector(
ValueOf(s),
DefaultHijacker,
DefaultTypeChecker,
SortByNumMethods,
Values(values).CloneWithFieldsOf(s)...,
)
@ -74,9 +102,6 @@ func Func(fn interface{}, values ...reflect.Value) *FuncInjector {
return MakeFuncInjector(
ValueOf(fn),
DefaultHijacker,
DefaultTypeChecker,
DefaultErrorHandler,
values...,
)
}
@ -88,28 +113,34 @@ func Func(fn interface{}, values ...reflect.Value) *FuncInjector {
type D struct {
Values
hijacker Hijacker
goodFunc TypeChecker
errorHandler ErrorHandler
sorter Sorter
fallbackBinder FallbackBinder
errorHandler ErrorHandler
sorter Sorter
}
// OrphanInput represents an input without registered dependency.
// Used to help the framework (or the caller) auto-resolve it by the request.
type OrphanInput struct {
// Index int // function or struct field index.
Type reflect.Type
}
// FallbackBinder represents a handler of oprhan input values, handler's input arguments or controller's fields.
type FallbackBinder func(ctx context.Context, input OrphanInput) (reflect.Value, error)
// New creates and returns a new Dependency Injection container.
// See `Values` field and `Func` and `Struct` methods for more.
func New() *D {
return &D{}
return &D{
errorHandler: DefaultErrorHandler,
fallbackBinder: DefaultFallbackBinder,
}
}
// Hijack sets a hijacker function, read the `Hijacker` type for more explanation.
func (d *D) Hijack(fn Hijacker) *D {
d.hijacker = fn
return d
}
// GoodFunc sets a type checker for a valid function that can be binded,
// read the `TypeChecker` type for more explanation.
func (d *D) GoodFunc(fn TypeChecker) *D {
d.goodFunc = fn
// FallbackBinder adds a binder which will handle any oprhan input values.
// See `FallbackBinder` type.
func (d *D) FallbackBinder(fallbackBinder FallbackBinder) *D {
d.fallbackBinder = fallbackBinder
return d
}
@ -130,11 +161,10 @@ func (d *D) Sort(with Sorter) *D {
// parent's (current "D") hijacker, good func type checker, sorter and all dependencies values.
func (d *D) Clone() *D {
return &D{
Values: d.Values.Clone(),
hijacker: d.hijacker,
goodFunc: d.goodFunc,
errorHandler: d.errorHandler,
sorter: d.sorter,
Values: d.Values.Clone(),
fallbackBinder: d.fallbackBinder,
errorHandler: d.errorHandler,
sorter: d.sorter,
}
}
@ -144,16 +174,19 @@ func (d *D) Clone() *D {
// with the injector's `Inject` and `InjectElem` methods.
func (d *D) Struct(s interface{}) *StructInjector {
if s == nil {
return &StructInjector{Has: false}
return &StructInjector{}
}
return MakeStructInjector(
injector := MakeStructInjector(
ValueOf(s),
d.hijacker,
d.goodFunc,
d.sorter,
d.Values.CloneWithFieldsOf(s)...,
)
injector.ErrorHandler = d.errorHandler
injector.FallbackBinder = d.fallbackBinder
return injector
}
// Func is being used to return a new injector based on
@ -163,14 +196,16 @@ func (d *D) Struct(s interface{}) *StructInjector {
// with the injector's `Inject` method.
func (d *D) Func(fn interface{}) *FuncInjector {
if fn == nil {
return &FuncInjector{Has: false}
return &FuncInjector{}
}
return MakeFuncInjector(
injector := MakeFuncInjector(
ValueOf(fn),
d.hijacker,
d.goodFunc,
d.errorHandler,
d.Values...,
).ErrorHandler(d.errorHandler)
)
injector.ErrorHandler = d.errorHandler
injector.FallbackBinder = d.fallbackBinder
return injector
}

View File

@ -18,10 +18,10 @@ type (
FuncInjector struct {
// the original function, is being used
// only the .Call, which is referring to the same function, always.
fn reflect.Value
typ reflect.Type
goodFunc TypeChecker
errorHandler ErrorHandler
fn reflect.Value
typ reflect.Type
FallbackBinder FallbackBinder
ErrorHandler ErrorHandler
inputs []*targetFuncInput
// Length is the number of the valid, final binded input arguments.
@ -51,13 +51,13 @@ func (s *FuncInjector) miss(index int, remaining Values) {
// that the caller should use to bind input arguments of the "fn" function.
//
// The hijack and the goodFunc are optional, the "values" is the dependencies collection.
func MakeFuncInjector(fn reflect.Value, hijack Hijacker, goodFunc TypeChecker, errorHandler ErrorHandler, values ...reflect.Value) *FuncInjector {
func MakeFuncInjector(fn reflect.Value, values ...reflect.Value) *FuncInjector {
typ := IndirectType(fn.Type())
s := &FuncInjector{
fn: fn,
typ: typ,
goodFunc: goodFunc,
errorHandler: errorHandler,
fn: fn,
typ: typ,
FallbackBinder: DefaultFallbackBinder,
ErrorHandler: DefaultErrorHandler,
}
if !IsFunc(typ) {
@ -71,16 +71,12 @@ func MakeFuncInjector(fn reflect.Value, hijack Hijacker, goodFunc TypeChecker, e
for i := 0; i < n; i++ {
inTyp := typ.In(i)
if hijack != nil {
b, ok := hijack(inTyp)
if ok && b != nil {
s.inputs = append(s.inputs, &targetFuncInput{
InputIndex: i,
Object: b,
})
continue
}
if b, ok := tryBindContext(inTyp); ok {
s.inputs = append(s.inputs, &targetFuncInput{
InputIndex: i,
Object: b,
})
continue
}
matched := false
@ -98,6 +94,50 @@ func MakeFuncInjector(fn reflect.Value, hijack Hijacker, goodFunc TypeChecker, e
break
}
// TODO: (already working on it) clean up or even re-write the whole di, hero and some of the mvc,
// this is a dirty but working-solution for #1449.
// Limitations:
// - last input argument
// - not able to customize it other than DefaultFallbackBinder on MVC (on hero it can be customized)
// - the "di" package is now depends on context package which is not an import-cycle issue, it's not imported there.
if i == n-1 {
if v.Type() == autoBindingTyp && s.FallbackBinder != nil {
canFallback := true
if k := inTyp.Kind(); k == reflect.Ptr {
if inTyp.Elem().Kind() != reflect.Struct {
canFallback = false
}
} else if k != reflect.Struct {
canFallback = false
}
if canFallback {
matched = true
s.inputs = append(s.inputs, &targetFuncInput{
InputIndex: i,
Object: &BindObject{
Type: inTyp,
BindType: Dynamic,
ReturnValue: func(ctx context.Context) reflect.Value {
value, err := s.FallbackBinder(ctx, OrphanInput{Type: inTyp})
if err != nil {
if s.ErrorHandler != nil {
s.ErrorHandler.HandleError(ctx, err)
}
}
return value
},
},
})
break
}
}
}
}
if !matched {
@ -108,7 +148,6 @@ func MakeFuncInjector(fn reflect.Value, hijack Hijacker, goodFunc TypeChecker, e
// with different set of binding "values".
s.miss(i, values) // send the remaining dependencies values.
}
}
return s
@ -119,6 +158,11 @@ func (s *FuncInjector) refresh() {
s.Has = s.Length > 0
}
// AutoBindingValue a fake type to expliclty set the return value of hero.AutoBinding.
type AutoBindingValue struct{}
var autoBindingTyp = reflect.TypeOf(AutoBindingValue{})
func (s *FuncInjector) addValue(inputIndex int, value reflect.Value) bool {
defer s.refresh()
@ -129,31 +173,14 @@ func (s *FuncInjector) addValue(inputIndex int, value reflect.Value) bool {
inTyp := s.typ.In(inputIndex)
// the binded values to the func's inputs.
b, err := MakeBindObject(value, s.goodFunc, s.errorHandler)
b, err := MakeBindObject(value, s.ErrorHandler)
if err != nil {
return false
}
// TODO: expose that (need to push a fix for issue #1450 first)
if b.Type == reflectValueType {
b.Type = inTyp
// returnValue := b.ReturnValue
b.ReturnValue = func(ctx context.Context) reflect.Value {
newValue := reflect.New(inTyp)
if err := ctx.ReadJSON(newValue.Interface()); err != nil {
if s.errorHandler != nil {
s.errorHandler.HandleError(ctx, err)
}
}
return newValue.Elem()
}
}
if b.IsAssignable(inTyp) {
// fmt.Printf("binded input index: %d for type: %s and value: %v with pointer: %v\n",
// i, b.Type.String(), inTyp.String(), inTyp.Pointer())
// fmt.Printf("binded input index: %d for type: %s and value: %v with dependency: %v\n",
// inputIndex, b.Type.String(), inTyp.String(), b)
s.inputs = append(s.inputs, &targetFuncInput{
InputIndex: inputIndex,
Object: &b,
@ -164,12 +191,6 @@ func (s *FuncInjector) addValue(inputIndex int, value reflect.Value) bool {
return false
}
// ErrorHandler registers an error handler for this FuncInjector.
func (s *FuncInjector) ErrorHandler(errorHandler ErrorHandler) *FuncInjector {
s.errorHandler = errorHandler
return s
}
// Retry used to add missing dependencies, i.e path parameter builtin bindings if not already exists
// in the `hero.Handler`, once, only for that func injector.
func (s *FuncInjector) Retry(retryFn func(inIndex int, inTyp reflect.Type, remainingValues Values) (reflect.Value, bool)) bool {

View File

@ -45,10 +45,10 @@ type BindObject struct {
// or the input arguments (if "v.elem()" is func)
// are valid to be included as the final object's dependencies, even if the caller added more
// the "di" is smart enough to select what each "v" needs and what not before serve time.
func MakeBindObject(v reflect.Value, goodFunc TypeChecker, errorHandler ErrorHandler) (b BindObject, err error) {
func MakeBindObject(v reflect.Value, errorHandler ErrorHandler) (b BindObject, err error) {
if IsFunc(v) {
b.BindType = Dynamic
b.ReturnValue, b.Type, err = MakeReturnValue(v, goodFunc, errorHandler)
b.ReturnValue, b.Type, err = MakeReturnValue(v, errorHandler)
} else {
b.BindType = Static
b.Type = v.Type()
@ -58,6 +58,23 @@ func MakeBindObject(v reflect.Value, goodFunc TypeChecker, errorHandler ErrorHan
return
}
func tryBindContext(fieldOrFuncInput reflect.Type) (*BindObject, bool) {
if !IsContext(fieldOrFuncInput) {
return nil, false
}
// this is being used on both func injector and struct injector.
// if the func's input argument or the struct's field is a type of Context
// then we can do a fast binding using the ctxValue
// which is used as slice of reflect.Value, because of the final method's `Call`.
return &BindObject{
Type: contextTyp,
BindType: Dynamic,
ReturnValue: func(ctx context.Context) reflect.Value {
return ctx.ReflectValue()[0]
},
}, true
}
var errBad = errors.New("bad")
// MakeReturnValue takes any function
@ -71,7 +88,7 @@ var errBad = errors.New("bad")
//
// The return type of the "fn" should be a value instance, not a pointer.
// The binder function should return just one value.
func MakeReturnValue(fn reflect.Value, goodFunc TypeChecker, errorHandler ErrorHandler) (func(ctx context.Context) reflect.Value, reflect.Type, error) {
func MakeReturnValue(fn reflect.Value, errorHandler ErrorHandler) (func(context.Context) reflect.Value, reflect.Type, error) {
typ := IndirectType(fn.Type())
// invalid if not a func.
@ -86,10 +103,8 @@ func MakeReturnValue(fn reflect.Value, goodFunc TypeChecker, errorHandler ErrorH
return nil, typ, errBad
}
if goodFunc != nil {
if !goodFunc(typ) {
return nil, typ, errBad
}
if !goodFunc(typ) {
return nil, typ, errBad
}
firstOutTyp := typ.Out(0)
@ -114,17 +129,6 @@ func MakeReturnValue(fn reflect.Value, goodFunc TypeChecker, errorHandler ErrorH
return firstZeroOutVal
}
// if firstOutTyp == reflectValueType {
// converted := v.Convert(typ.In(0))
// fmt.Printf("object.go#124: converted: %#+v\n", converted)
// return converted //reflect.ValueOf(v.Interface())
// }
// if v.String() == "<interface {} Value>" {
// println("di/object.go: " + v.String())
// // println("di/object.go: because it's interface{} it should be returned as: " + v.Elem().Type().String() + " and its value: " + v.Elem().Interface().(string))
// return v.Elem()
// }
return v
}

View File

@ -2,6 +2,8 @@ package di
import (
"reflect"
"github.com/kataras/iris/v12/context"
)
// EmptyIn is just an empty slice of reflect.Value.
@ -131,6 +133,19 @@ func goodVal(v reflect.Value) bool {
return v.IsValid()
}
var contextTyp = reflect.TypeOf((*context.Context)(nil)).Elem()
// IsContext returns true if the "inTyp" is a type of Context.
func IsContext(inTyp reflect.Type) bool {
return inTyp.Implements(contextTyp)
}
func goodFunc(fn reflect.Type) bool {
// valid if that single input arg is a typeof context.Context
// or first argument is context.Context and second argument is a variadic, which is ignored (i.e new sessions#Start).
return (fn.NumIn() == 1 || (fn.NumIn() == 2 && fn.IsVariadic())) && IsContext(fn.In(0))
}
// IsFunc returns true if the passed type is function.
func IsFunc(kindable interface {
Kind() reflect.Kind

View File

@ -61,6 +61,9 @@ type (
Has bool
CanInject bool // if any bindable fields when the state is NOT singleton.
Scope Scope
FallbackBinder FallbackBinder
ErrorHandler ErrorHandler
}
)
@ -103,11 +106,13 @@ var SortByNumMethods Sorter = func(t1 reflect.Type, t2 reflect.Type) bool {
// of the "v" struct value or pointer.
//
// The hijack and the goodFunc are optional, the "values" is the dependencies collection.
func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker, sorter Sorter, values ...reflect.Value) *StructInjector {
func MakeStructInjector(v reflect.Value, sorter Sorter, values ...reflect.Value) *StructInjector {
s := &StructInjector{
initRef: v,
initRefAsSlice: []reflect.Value{v},
elemType: IndirectType(v.Type()),
FallbackBinder: DefaultFallbackBinder,
ErrorHandler: DefaultErrorHandler,
}
// Optionally check and keep good values only here,
@ -138,15 +143,12 @@ func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker,
for _, f := range fields {
// fmt.Printf("[%d] field type [%s] value name [%s]\n", idx, f.Type.String(), f.Name)
if hijack != nil {
if b, ok := hijack(f.Type); ok && b != nil {
s.fields = append(s.fields, &targetStructField{
FieldIndex: f.Index,
Object: b,
})
continue
}
if b, ok := tryBindContext(f.Type); ok {
s.fields = append(s.fields, &targetStructField{
FieldIndex: f.Index,
Object: b,
})
continue
}
var possibleValues []*targetStructField
@ -157,9 +159,10 @@ func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker,
}
// the binded values to the struct's fields.
b, err := MakeBindObject(val, goodFunc, nil)
b, err := MakeBindObject(val, nil)
if err != nil {
return s // if error stop here.
panic(err)
// return s // if error stop here.
}
if b.IsAssignable(f.Type) {

View File

@ -11,31 +11,17 @@ import (
"github.com/kataras/golog"
)
var contextTyp = reflect.TypeOf((*context.Context)(nil)).Elem()
// var genericFuncTyp = reflect.TypeOf(func(context.Context) reflect.Value { return reflect.Value{} })
// IsContext returns true if the "inTyp" is a type of Context.
func IsContext(inTyp reflect.Type) bool {
return inTyp.Implements(contextTyp)
}
// var genericFuncTyp = reflect.TypeOf(func(context.Context) interface{} { return nil })
var genericFuncTyp = reflect.TypeOf(func(context.Context) reflect.Value { return reflect.Value{} })
// IsGenericFunc reports whether the "inTyp" is a type of func(Context) interface{}.
func IsGenericFunc(inTyp reflect.Type) bool {
return inTyp == genericFuncTyp
}
// // IsGenericFunc reports whether the "inTyp" is a type of func(Context) interface{}.
// func IsGenericFunc(inTyp reflect.Type) bool {
// return inTyp == genericFuncTyp
// }
// checks if "handler" is context.Handler: func(context.Context).
func isContextHandler(handler interface{}) (context.Handler, bool) {
h, is := handler.(context.Handler)
if !is {
fh, is := handler.(func(context.Context))
if is {
return fh, is
}
}
return h, is
h, ok := handler.(context.Handler)
return h, ok
}
func validateHandler(handler interface{}) error {
@ -72,7 +58,7 @@ func makeHandler(handler interface{}, errorHandler di.ErrorHandler, values ...re
}
funcInjector := di.Func(fn, values...)
funcInjector.ErrorHandler(errorHandler)
funcInjector.ErrorHandler = errorHandler
valid := funcInjector.Length == n

View File

@ -4,7 +4,6 @@ package hero_test
import (
"fmt"
"reflect"
"testing"
"github.com/kataras/iris/v12"
@ -128,37 +127,23 @@ func TestBindFunctionAsFunctionInputArgument(t *testing.T) {
Expect().Status(iris.StatusOK).Body().Equal(expectedUsername)
}
func TestBindReflectValue(t *testing.T) {
// TODO: THINK of simplify this,
// as 'hero' and 'mvc' are not depend on the root kataras/iris/v12 package, smart decision back then.
// e.g.
// app := iris.New()
// app.RegisterDependency(...)
// app.HandleFunc("GET POST", "/", func(input MyInput) MyOutput {})
// instead of:
// app := iris.New()
// h := hero.New()
// h.Register(...) or hero.Register for shared deps across Iris different applications.
// handler := h.Handler(func(input MyInput) MyOutput {})
// app.HandleMany("GET POST", "/", handler)
func TestAutoBinding(t *testing.T) {
h := New()
h.Register(func(ctx iris.Context) reflect.Value {
var v interface{}
err := ctx.ReadJSON(&v)
if err != nil {
t.Fatal(err)
}
return reflect.ValueOf(v)
// return reflect.Value{}
h.Register(AutoBinding)
postHandler := h.Handler(func(input *testUserStruct /* ptr */) string {
return input.Username
})
postHandler := h.Handler(func(input testUserStruct) string {
postHandler2 := h.Handler(func(input testUserStruct) string {
return input.Username
})
app := iris.New()
app.Post("/", postHandler)
app.Post("/2", postHandler2)
e := httptest.New(t, app)
e.POST("/").WithJSON(iris.Map{"username": "makis"}).Expect().Status(httptest.StatusOK).Body().Equal("makis")
e.POST("/2").WithJSON(iris.Map{"username": "kataras"}).Expect().Status(httptest.StatusOK).Body().Equal("kataras")
}

View File

@ -48,6 +48,12 @@ func (h *Hero) Dependencies() *di.Values {
return &h.values
}
// AutoBinding used to be registered as dependency to try to automatically
// map and bind the inputs that are not already binded with a dependency.
//
// See `DefaultFallbackBinder`.
var AutoBinding = di.AutoBindingValue{}
// Register adds one or more values as dependencies.
// The value can be a single struct value-instance or a function
// which has one input and one output, the input should be

View File

@ -41,7 +41,7 @@ import (
)
// Version is the current version number of the Iris Web Framework.
const Version = "12.1.7"
const Version = "12.1.8"
// HTTP status codes as registered with IANA.
// See: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml.

View File

@ -396,8 +396,6 @@ func (c *ControllerActivator) attachInjector() {
if c.injector == nil {
c.injector = di.MakeStructInjector(
di.ValueOf(c.Value),
di.DefaultHijacker,
di.DefaultTypeChecker,
c.sorter,
di.Values(c.dependencies).CloneWithFieldsOf(c.Value)...,
)
@ -426,7 +424,7 @@ func (c *ControllerActivator) handlerOf(m reflect.Method, funcDependencies []ref
// fmt.Printf("for %s | values: %s\n", funcName, funcDependencies)
funcInjector := di.Func(m.Func, funcDependencies...)
funcInjector.ErrorHandler(c.errorHandler)
funcInjector.ErrorHandler = c.errorHandler
// fmt.Printf("actual injector's inputs length: %d\n", funcInjector.Length)
if funcInjector.Has {
@ -492,10 +490,6 @@ func (c *ControllerActivator) handlerOf(m reflect.Method, funcDependencies []ref
return // stop as soon as possible, although it would stop later on if `ctx.StopExecution` called.
}
// for idxx, inn := range in {
// println("controller.go: execution: in.Value = "+inn.String()+" and in.Type = "+inn.Type().Kind().String()+" of index: ", idxx)
// }
hero.DispatchFuncResult(ctx, errorHandler, call(in))
return
}

View File

@ -104,6 +104,12 @@ func (app *Application) Configure(configurators ...func(*Application)) *Applicat
return app
}
// AutoBinding used to be registered as dependency to try to automatically
// map and bind the inputs that are not already binded with a dependency.
//
// A shortcut of `hero.AutoBinding`. Read more at: `hero#DefaultFallbackBinder`.
var AutoBinding = hero.AutoBinding
// Register appends one or more values as dependencies.
// The value can be a single struct value-instance or a function
// which has one input and one output, the input should be