Skip to content

Commit 620d98e

Browse files
committed
Added namespace identity in modules, routes, and templates
1 parent 150849c commit 620d98e

File tree

10 files changed

+619
-240
lines changed

10 files changed

+619
-240
lines changed

controller.go

Lines changed: 74 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package revel
77
import (
88
"errors"
99
"fmt"
10-
"go/build"
1110
"io"
1211
"net/http"
1312
"os"
@@ -92,10 +91,19 @@ func (c *Controller) setStatusIfNil(status int) {
9291
//
9392
// This action will render views/Users/ShowUser.html, passing in an extra
9493
// key-value "user": (User).
94+
//
95+
// This is the slower magical version which uses the runtime
96+
// to determine
97+
// 1) Set c.ViewArgs to the arguments passed into this function
98+
// 2) How to call the RenderTemplate by building the following line
99+
// c.RenderTemplate(c.Name + "/" + c.MethodType.Name + "." + c.Request.Format)
100+
//
101+
// If you want your code to run faster it is recommended you add the template values directly
102+
// to the c.ViewArgs and call c.RenderTemplate directly
95103
func (c *Controller) Render(extraViewArgs ...interface{}) Result {
96104
c.setStatusIfNil(http.StatusOK)
97105

98-
// Get the calling function name.
106+
// Get the calling function line number.
99107
_, _, line, ok := runtime.Caller(1)
100108
if !ok {
101109
ERROR.Println("Failed to get Caller information")
@@ -278,10 +286,11 @@ func (c *Controller) Message(message string, args ...interface{}) (value string)
278286
func (c *Controller) SetAction(controllerName, methodName string) error {
279287

280288
// Look up the controller and method types.
281-
var ok bool
282-
if c.Type, ok = controllers[strings.ToLower(controllerName)]; !ok {
289+
if c.Type = ControllerTypeByName(controllerName, anyModule); c.Type==nil {
283290
return errors.New("revel/controller: failed to find controller " + controllerName)
284291
}
292+
293+
// Note method name is case insensitive search
285294
if c.MethodType = c.Type.Method(methodName); c.MethodType == nil {
286295
return errors.New("revel/controller: failed to find action " + methodName)
287296
}
@@ -294,6 +303,26 @@ func (c *Controller) SetAction(controllerName, methodName string) error {
294303

295304
return nil
296305
}
306+
func ControllerTypeByName(controllerName string, moduleSource *Module) (c *ControllerType) {
307+
var found bool
308+
if c, found = controllers[controllerName]; !found {
309+
// Backup, passed in controllerName should be in lower case, but may not be
310+
if c, found = controllers[strings.ToLower(controllerName)]; !found {
311+
INFO.Printf("Cannot find controller name '%s' in controllers map ", controllerName)
312+
// Search for the controller by name
313+
for _, cType := range controllers {
314+
testControllerName := strings.ToLower(cType.Type.Name())
315+
if testControllerName == strings.ToLower(controllerName) && (cType.ModuleSource == moduleSource || moduleSource == anyModule) {
316+
WARN.Printf("Matched empty namespace controller for %s to this %s", controllerName, cType.ModuleSource.Name)
317+
c = cType
318+
found = true
319+
break
320+
}
321+
}
322+
}
323+
}
324+
return
325+
}
297326

298327
// This is a helper that initializes (zeros) a new app controller value.
299328
// Specifically, it sets all *revel.Controller embedded types to the provided controller.
@@ -365,6 +394,7 @@ func findControllers(appControllerType reflect.Type) (indexes [][]int) {
365394
// Controller registry and types.
366395

367396
type ControllerType struct {
397+
Namespace string // The namespace of the controller
368398
ModuleSource *Module // The module for the controller
369399
Type reflect.Type
370400
Methods []*MethodType
@@ -383,6 +413,30 @@ type MethodArg struct {
383413
Type reflect.Type
384414
}
385415

416+
func AddControllerType(moduleSource *Module,controllerType reflect.Type,methods []*MethodType) (newControllerType *ControllerType) {
417+
if moduleSource==nil {
418+
moduleSource = appModule
419+
}
420+
421+
newControllerType = &ControllerType{ModuleSource:moduleSource,Type:controllerType,Methods:methods,ControllerIndexes:findControllers(controllerType)}
422+
newControllerType.Namespace = moduleSource.Namespace()
423+
controllerName := newControllerType.Name()
424+
425+
// Store the first controller only in the controllers map with the unmapped namespace.
426+
if _, found := controllers[controllerName]; !found {
427+
controllers[controllerName] = newControllerType
428+
newControllerType.ModuleSource.AddController(newControllerType)
429+
if newControllerType.ModuleSource == appModule {
430+
// Add the controller mapping into the global namespace
431+
controllers[newControllerType.ShortName()] = newControllerType
432+
}
433+
} else {
434+
ERROR.Printf("Error, attempt to register duplicate controller as %s",controllerName)
435+
}
436+
TRACE.Printf("Registered controller: %s", controllerName)
437+
438+
return
439+
}
386440
// Method searches for a given exported method (case insensitive)
387441
func (ct *ControllerType) Method(name string) *MethodType {
388442
lowerName := strings.ToLower(name)
@@ -394,6 +448,16 @@ func (ct *ControllerType) Method(name string) *MethodType {
394448
return nil
395449
}
396450

451+
// The controller name without the namespace
452+
func (ct *ControllerType) Name() (string) {
453+
return ct.Namespace + ct.ShortName()
454+
}
455+
456+
// The controller name with the namespace
457+
func (ct *ControllerType) ShortName() (string) {
458+
return strings.ToLower(ct.Type.Name())
459+
}
460+
397461
var controllers = make(map[string]*ControllerType)
398462

399463
// RegisterController registers a Controller and its Methods with Revel.
@@ -409,30 +473,11 @@ func RegisterController(c interface{}, methods []*MethodType) {
409473
arg.Type = arg.Type.Elem()
410474
}
411475
}
412-
path := elem.PkgPath()
413-
gopathList := filepath.SplitList(build.Default.GOPATH)
414-
var controllerModule *Module
415-
416-
// See if the path exists in the module based
417-
for i := range Modules {
418-
found := false
419-
for _, gopath := range gopathList {
420-
if strings.HasPrefix(gopath+"/src/"+path, Modules[i].Path) {
421-
controllerModule = Modules[i]
422-
found = true
423-
break
424-
}
425-
}
426-
if found {
427-
break
428-
}
429-
}
430476

431-
controllers[strings.ToLower(elem.Name())] = &ControllerType{
432-
ModuleSource: controllerModule,
433-
Type: elem,
434-
Methods: methods,
435-
ControllerIndexes: findControllers(elem),
436-
}
437-
TRACE.Printf("Registered controller: %s", elem.Name())
477+
// Fetch module for controller, if none found controller must be part of the app
478+
controllerModule := ModuleFromPath(elem.PkgPath(), true)
479+
480+
controllerType := AddControllerType(controllerModule,elem,methods)
481+
482+
TRACE.Printf("Registered controller: %s", controllerType.Name())
438483
}

fakeapp_test.go

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,18 @@ type Static struct {
2828
*Controller
2929
}
3030

31+
type Implicit struct {
32+
*Controller
33+
}
34+
35+
type Application struct {
36+
*Controller
37+
}
38+
3139
func (c Hotels) Show(id int) Result {
3240
title := "View Hotel"
3341
hotel := &Hotel{id, "A Hotel", "300 Main St.", "New York", "NY", "10010", "USA", 300}
42+
// The line number below must match the one with the code : RenderArgNames: map[int][]string{43: {"title", "hotel"}},
3443
return c.Render(title, hotel)
3544
}
3645

@@ -61,20 +70,10 @@ func (c Static) Serve(prefix, path string) Result {
6170
return c.RenderFile(file, "")
6271
}
6372

64-
func startFakeBookingApp() {
65-
Init("prod", "github.com/revel/revel/testdata", "")
66-
67-
// Disable logging.
68-
TRACE = log.New(ioutil.Discard, "", 0)
69-
INFO = TRACE
70-
WARN = TRACE
71-
ERROR = TRACE
72-
73-
MainTemplateLoader = NewTemplateLoader([]string{ViewsPath, filepath.Join(RevelPath, "templates")})
74-
if err := MainTemplateLoader.Refresh(); err != nil {
75-
ERROR.Fatal(err)
76-
}
77-
73+
// Register controllers is in its own function so the route test can use it as well
74+
func registerControllers() {
75+
controllers = make(map[string]*ControllerType)
76+
fireEvent(ROUTE_REFRESH_REQUESTED, nil)
7877
RegisterController((*Hotels)(nil),
7978
[]*MethodType{
8079
{
@@ -85,7 +84,7 @@ func startFakeBookingApp() {
8584
Args: []*MethodArg{
8685
{"id", reflect.TypeOf((*int)(nil))},
8786
},
88-
RenderArgNames: map[int][]string{34: {"title", "hotel"}},
87+
RenderArgNames: map[int][]string{43: {"title", "hotel"}},
8988
},
9089
{
9190
Name: "Book",
@@ -106,6 +105,44 @@ func startFakeBookingApp() {
106105
RenderArgNames: map[int][]string{},
107106
},
108107
})
108+
RegisterController((*Implicit)(nil),
109+
[]*MethodType{
110+
{
111+
Name: "Implicit",
112+
Args: []*MethodArg{
113+
{Name: "prefix", Type: reflect.TypeOf((*string)(nil))},
114+
{Name: "filepath", Type: reflect.TypeOf((*string)(nil))},
115+
},
116+
RenderArgNames: map[int][]string{},
117+
},
118+
})
119+
RegisterController((*Application)(nil),
120+
[]*MethodType{
121+
{
122+
Name: "Application",
123+
Args: []*MethodArg{
124+
{Name: "prefix", Type: reflect.TypeOf((*string)(nil))},
125+
{Name: "filepath", Type: reflect.TypeOf((*string)(nil))},
126+
},
127+
RenderArgNames: map[int][]string{},
128+
},
129+
})
130+
}
131+
func startFakeBookingApp() {
132+
Init("prod", "github.com/revel/revel/testdata", "")
133+
134+
// Disable logging.
135+
TRACE = log.New(ioutil.Discard, "", 0)
136+
INFO = TRACE
137+
WARN = TRACE
138+
ERROR = TRACE
139+
140+
MainTemplateLoader = NewTemplateLoader([]string{ViewsPath, filepath.Join(RevelPath, "templates")})
141+
if err := MainTemplateLoader.Refresh(); err != nil {
142+
ERROR.Fatal(err)
143+
}
144+
145+
registerControllers()
109146

110147
runStartupHooks()
111148
}

module.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package revel
2+
3+
import (
4+
"sort"
5+
"strings"
6+
"path/filepath"
7+
"go/build"
8+
)
9+
10+
// Module specific functions
11+
type Module struct {
12+
Name, ImportPath, Path string
13+
ControllerTypeList []*ControllerType
14+
}
15+
16+
const namespaceSeperator = "|" // ., : are already used
17+
18+
var (
19+
anyModule = &Module{}
20+
appModule = &Module{Name:"App"}
21+
)
22+
23+
// Returns the namespace for the module in the format `module_name|`
24+
func (m *Module) Namespace() (namespace string) {
25+
namespace = m.Name + namespaceSeperator
26+
return
27+
}
28+
29+
// Returns the named controller and action that is in this module
30+
func (m *Module) ControllerByName(name,action string)(ctype *ControllerType) {
31+
comparision := name
32+
if strings.Index(name,namespaceSeperator)<0 {
33+
comparision = m.Namespace() + name
34+
}
35+
for _,c := range m.ControllerTypeList {
36+
if strings.Index(c.Name(),comparision)>-1 {
37+
ctype = c
38+
break
39+
}
40+
}
41+
return
42+
}
43+
func (m *Module) AddController(ct *ControllerType) {
44+
m.ControllerTypeList = append(m.ControllerTypeList,ct)
45+
}
46+
47+
48+
func loadModules() {
49+
keys := []string{}
50+
for _, key := range Config.Options("module.") {
51+
keys = append(keys, key)
52+
}
53+
54+
// Reorder module order by key name, a poor mans sort but at least it is consistent
55+
sort.Strings(keys)
56+
for _, key := range keys {
57+
INFO.Println("Sorted keys", key)
58+
59+
}
60+
for _, key := range keys {
61+
moduleImportPath := Config.StringDefault(key, "")
62+
if moduleImportPath == "" {
63+
continue
64+
}
65+
66+
modulePath, err := ResolveImportPath(moduleImportPath)
67+
if err != nil {
68+
ERROR.Fatalln("Failed to load module. Import of", moduleImportPath, "failed:", err)
69+
}
70+
// Drop anything between module.???.<name of module>
71+
subKey := key[len("module."):]
72+
if index := strings.Index(subKey, "."); index > -1 {
73+
subKey = subKey[index+1:]
74+
}
75+
76+
addModule(subKey, moduleImportPath, modulePath)
77+
}
78+
}
79+
80+
// Based on the full path given return the relevant module
81+
// Only be used on initialization
82+
func ModuleFromPath(path string, addGopathToPath bool) (module *Module) {
83+
gopathList := filepath.SplitList(build.Default.GOPATH)
84+
85+
// See if the path exists in the module based
86+
for i := range Modules {
87+
if addGopathToPath {
88+
for _, gopath := range gopathList {
89+
if strings.HasPrefix(gopath+"/src/"+path, Modules[i].Path) {
90+
module = Modules[i]
91+
break
92+
}
93+
}
94+
} else {
95+
if strings.HasPrefix(path, Modules[i].Path) {
96+
module = Modules[i]
97+
break
98+
}
99+
100+
}
101+
102+
if module!=nil {
103+
break
104+
}
105+
}
106+
return
107+
}
108+

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy