<commit_before>package goanna

import (
	"fmt"
	"github.com/gorilla/mux"
	"log"
	"net/http"
	"reflect"
)

type ControllerFactoryFunc func() ControllerInterface

type ControllerHandler struct {
	factory    ControllerFactoryFunc
	methodName string
}

func (handler ControllerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	handler.getResponse(r).Send(w)
}

// getResponse executes the specified controller's method using reflection
// and returns the response object
func (handler ControllerHandler) getResponse(r *http.Request) Response {
	controller := handler.factory()
	controller.Init(r)
	rController := reflect.ValueOf(controller)
	method := rController.MethodByName(handler.methodName)

	// get args from gorilla mux
	var args []reflect.Value
	for _, val := range mux.Vars(r) {
		args = append(args, reflect.ValueOf(val))
	}
	expected := len(args)
	actual := method.Type().NumIn()
	if expected != actual {
		log.Panic(fmt.Sprintf("Method '%s' has %d args, expected %d", handler.methodName, actual, expected))
	}

	out := method.Call(args)
	if out[0].IsNil() {
		return NewErrorResponse("Response from controller was nil", 500)
	}
	resp := out[0].Interface().(Response)
	if resp == nil {
		return NewErrorResponse("Response from controller was not Response interface", 500)
	}
	controller.Session().WriteToResponse(resp)
	return resp
}

// isValid checks that the controller and method specifies
// will sucessfully execute if getResponse is called on it
func (handler ControllerHandler) isValid() bool {
	controller := handler.factory()
	rController := reflect.ValueOf(controller)
	method := rController.MethodByName(handler.methodName)
	typeOfMethod := method.Type()

	var r *Response
	responseType := reflect.TypeOf(r).Elem()

	return (method.Kind() == reflect.Func) &&
		(typeOfMethod.NumMethod() == 0) &&
		(typeOfMethod.NumOut() == 1) &&
		typeOfMethod.Out(0) == responseType

}
<commit_msg>More useful error when binding to a non-existent method<commit_after>package goanna

import (
	"fmt"
	"github.com/gorilla/mux"
	"log"
	"net/http"
	"reflect"
)

type ControllerFactoryFunc func() ControllerInterface

type ControllerHandler struct {
	factory    ControllerFactoryFunc
	methodName string
}

func (handler ControllerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	handler.getResponse(r).Send(w)
}

// getResponse executes the specified controller's method using reflection
// and returns the response object
func (handler ControllerHandler) getResponse(r *http.Request) Response {
	controller := handler.factory()
	controller.Init(r)
	rController := reflect.ValueOf(controller)
	method := rController.MethodByName(handler.methodName)

	// get args from gorilla mux
	var args []reflect.Value
	for _, val := range mux.Vars(r) {
		args = append(args, reflect.ValueOf(val))
	}
	expected := len(args)
	actual := method.Type().NumIn()
	if expected != actual {
		log.Panic(fmt.Sprintf("Method '%s' has %d args, expected %d", handler.methodName, actual, expected))
	}

	out := method.Call(args)
	if out[0].IsNil() {
		return NewErrorResponse("Response from controller was nil", 500)
	}
	resp := out[0].Interface().(Response)
	if resp == nil {
		return NewErrorResponse("Response from controller was not Response interface", 500)
	}
	controller.Session().WriteToResponse(resp)
	return resp
}

// isValid checks that the controller and method specifies
// will sucessfully execute if getResponse is called on it
func (handler ControllerHandler) isValid() bool {
	controller := handler.factory()
	rController := reflect.ValueOf(controller)
	method := rController.MethodByName(handler.methodName)
	if (method == reflect.Value{}) {
		panic("No such method: " + handler.methodName)
	}
	typeOfMethod := method.Type()

	var r *Response
	responseType := reflect.TypeOf(r).Elem()

	return (method.Kind() == reflect.Func) &&
		(typeOfMethod.NumMethod() == 0) &&
		(typeOfMethod.NumOut() == 1) &&
		typeOfMethod.Out(0) == responseType

}

{'fraction_non_alphanumeric': 0.12556846892369883, 'fraction_numerical': 0.0055583628094997475, 'mean_word_length': 4.980362537764351, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '184544', 'n_tokens_mistral': 1238, 'n_tokens_neox': 1193, 'n_words': 329}