Permalink
Browse files

primitive before filter working, fixed bug with helper scope merging

  • Loading branch information...
dantebronto committed Jan 25, 2011
1 parent 44b4097 commit a566c3bb9109f563aab8913a084a72cd8a258a47
Showing with 157 additions and 68 deletions.
  1. +1 −1 examples/controllers/app.js
  2. +7 −3 examples/templating/app.js
  3. +16 −0 lib/picard/filters.js
  4. +46 −25 lib/picard/request.js
  5. +68 −24 lib/picard/routing.js
  6. +19 −15 lib/picard/template.js
@@ -4,7 +4,7 @@ var Picard = require('../../lib/picard').start()
Picard.routeSet('operations', function(){
- var ops = this;
+ var ops = this
ops.pathPrefix = '/ops'
ops.layout = 'application'
View
@@ -2,14 +2,18 @@ var Picard = require('../../lib/picard').start()
var _ = require('underscore') // assumes underscore.js is require-able
Picard.template.ext = 'html.ejs' // default is 'haml'
-Picard.template.compile = _.template // template compilation function, see underscore.js docs: http://documentcloud.github.com/underscore/#template
+Picard.template.compile = _.template // template compilation function, see underscore.js docs:
+ // http://documentcloud.github.com/underscore/#template
+
+Picard.helpers({
+ _ : _ // make underscore available in the view scope
+})
Picard.get('/underscore_templates', function(){
return {
layout: 'application',
template: 'underscore',
name: 'Jean-Luc Picard',
- people: ['Riker', 'Crusher', 'Data'],
- _: _ // merge underscore in view scope
+ people: ['Riker', 'Crusher', 'Data']
}
})
View
@@ -0,0 +1,16 @@
+var Filter = {
+ before: function(matcher, cb){
+ if ( typeof matcher == 'function' ){
+ cb = matcher
+ matcher = '.*'
+ }
+ if ( !('befores' in this) ) this.befores = []
+
+ this.befores.push({
+ matcher: new RegExp(matcher), handler: cb
+ })
+ return this
+ }
+}
+
+module.exports = Filter
View
@@ -6,16 +6,6 @@ var sys = require('sys'),
Routes = require('./routing')
var RequestExtensions = {
- cookie: function(name, val, options){
- if ( val === undefined )
- return this.cookies[name]
-
- options = options || {}
- options.value = val
- options.path = options.path || "/"
-
- this.cookies[name] = options
- },
handleException: function(ex){
this.onScreen({
status: 500,
@@ -119,6 +109,33 @@ var RequestExtensions = {
for(i=0, l = match_data.length; i < l; i++)
this.captures[i] = match_data[i]
},
+ pass: function(){
+ try {
+ var req = this
+ req.parseCookies()
+
+ Routes.executeCallback(req, function(scope){
+ if( scope == 'static' )
+ scope = doc.serveStatic(req)
+ if ( scope == null || scope == undefined )
+ return
+ req.onScreen(scope)
+ })
+
+ } catch(ex) {
+ req.handleException(ex)
+ }
+ },
+ cookie: function(name, val, options){
+ if ( val === undefined )
+ return this.cookies[name]
+
+ options = options || {}
+ options.value = val
+ options.path = options.path || "/"
+
+ this.cookies[name] = options
+ },
parseCookies: function(){
try {
this.cookies = {}
@@ -134,21 +151,6 @@ var RequestExtensions = {
this.handleException(ex)
}
},
- pass: function(){
- try {
- this.parseCookies()
- var scope = Routes.executeCallback(this)
-
- if( scope == 'static' )
- scope = doc.serveStatic(this)
- if ( scope == null || scope == undefined )
- return
-
- this.onScreen(scope)
- } catch(ex) {
- this.handleException(ex)
- }
- },
setCookies: function(headers){
var ret, name, options
@@ -169,6 +171,25 @@ var RequestExtensions = {
headers.push([ "Set-Cookie", ret ])
}
return headers
+ },
+ filterDone: function(){
+ var filter = this.beforeFilters.shift(),
+ res, req = this
+
+ if ( filter ){
+ res = filter.handler(req) // call the filter
+
+ if ( res == false ){
+ req.handleNotFound()
+ } else if ( toString.call(res) == '[object Object]' ){
+ merge(req, res) // merge before filter result into env
+ req.filterDone()
+ } else if ( res != undefined ) { // not false or undefined, so keep going
+ req.filterDone()
+ }
+ } else { // we're done filtering
+ req.afterMainHandler(req.route.handler(req))
+ }
}
}
View
@@ -1,46 +1,67 @@
var http = require('http')
+var merge = require('./merge')
var Routes = {
- // API functions for merging into Picard
+ // API functions for merging into Picard and/or globalizing
publicFuncs: ['get', 'post', 'put', 'del', 'helpers', 'routeSet'],
init: function(){
- var methods = Routes.publicFuncs,
- RoutingAPI = {}
-
- for(var i=0, j = methods.length; i < j; i++ )
- RoutingAPI[methods[i]] = Routes[methods[i]]
+ var methods = Routes.publicFuncs.concat([
+ 'globalize', 'executeCallback', 'before', 'after'
+ ])
+
+ var routingAPI = {}
+
+ for(var i=0, j = methods.length; i < j; i++)
+ routingAPI[methods[i]] = Routes[methods[i]]
- RoutingAPI.globalize = Routes.globalize
- RoutingAPI.executeCallback = Routes.executeCallback
+ routingAPI.globalHelpers = Routes.globalHelpers // ???
- return RoutingAPI
+ return routingAPI
},
- executeCallback: function(request){
- var routesByType = Routes.byRestType(request)
- var route, matches
+
+ executeCallback: function(request, cb){
+ var routesByType = Routes.byRestType(request),
+ route, matches, path
for(var i=0, l = routesByType.length; i < l; i++){
route = routesByType[i]
- matches = request.parsedUrl().pathname.match(route.path)
+ path = request.parsedUrl().pathname
+ matches = path.match(route.path)
if( matches ){ // incoming request matches route
if ( request.route ){
if ( request.route == route )
- request.route = null
+ request.route = null // match the next route
continue
}
+
request.extractRouteParams(route, matches)
+
try {
- request.route = route
- return route.handler(request) // call programmer defined action
+ request.route = route
+
+ if ( route.routeSet ){
+
+ if ( route.routeSet.befores ){
+ route.routeSet.setMatchingBeforeFiltersOn(request, path)
+ request.afterMainHandler = cb
+ request.filterDone()
+ } else {
+ cb(route.handler(request)) // default
+ }
+
+ } else {
+ cb(route.handler(request)) // call programmer defined action
+ }
} catch(ex) {
request.handleException(ex)
}
}
}
- return 'static'
+ if ( !request.route )
+ cb('static')
},
byRestType: function(request){
switch( (request._method || request.method).toUpperCase() ) {
@@ -53,26 +74,31 @@ var Routes = {
add: function(path, handler, routeSet){
var keys = []
- if(path.constructor != RegExp){ // assume to be a String
+ if( toString.call(path) != '[object RegExp]' ){ // assume to be a String
var full_route = '^'+path+'/?$',
param_keys = path.match(/:[^/]+/g),
regexp_as_string = full_route.replace(/([^\*]):[^/]+/g, '$1([^/]+)')
- if (param_keys && path.match(/\*:\w+$/))
+ if ( param_keys && path.match(/\*:\w+$/) )
regexp_as_string = regexp_as_string.replace(/\*.+/, '(.+)')
path = new RegExp(regexp_as_string)
- if(param_keys)
+ if( param_keys )
for(var i=0, l = param_keys.length; i < l; i++)
keys[keys.length] = param_keys[i].replace(/^:/, '')
}
- return {
+ var route = new Route({
path: path,
handler: handler,
keys: keys,
routeSet: routeSet
- }
+ })
+
+ if ( typeof route.routeSet == 'undefined' )
+ route.helpers = Routes.helpers
+
+ return route
},
getRoutes: [],
postRoutes: [],
@@ -97,7 +123,7 @@ var Routes = {
return this
},
helpers: function(obj){
- if ( obj ) {
+ if ( obj ){
Routes.globalHelpers = obj
return this
}
@@ -119,12 +145,20 @@ var Routes = {
globalize: function(){
var methods = Routes.publicFuncs
for(var i=0, j = methods.length; i < j; i++ ){
- GLOBAL[methods[i]] = Routes[methods[i]]
+ global[methods[i]] = Routes[methods[i]]
}
return this;
}
}
+var Route = function(o){
+ this.path = o.path
+ this.handler = o.handler
+ this.keys = o.keys
+ this.routeSet = o.routeSet
+ return this
+}
+
var RouteSet = function(name){
this.name = name
this.pathPrefix = ''
@@ -155,7 +189,17 @@ RouteSet.prototype = {
del: function(path, handler){
Routes.del( this.pathPrefix + path, handler, this)
return this
+ },
+ setMatchingBeforeFiltersOn: function(req, path){
+ req.beforeFilters = []
+ for(var i=0, len = this.befores.length; i<len; i++){
+ if ( this.befores[i].matcher.test(path) ){
+ req.beforeFilters.push(this.befores[i])
+ }
+ }
}
}
+merge(RouteSet.prototype, require('./filters'))
+
module.exports = Routes.init()
View
@@ -3,7 +3,7 @@ var merge = require('./merge'),
fs = require('fs')
var Template = {
- cache: {},
+ cache: {},
ext: 'haml',
compile: require('./haml'),
@@ -75,23 +75,27 @@ var Template = {
return template(scope)
},
extendScope: function(req, scope){
- var sharedHelpers = {}
+ var globalHelpers = {}, routeSetHelpers = {}
- if ( typeof helpers == 'function' )
- sharedHelpers = helpers()
-
- if ( req.route && req.route.routeSet ){
- // merge route set helpers into view scope
- var mergedHelpers = merge({}, sharedHelpers, req.route.routeSet.helpers())
- scope = merge({}, mergedHelpers, scope)
+ if ( req.route ){
- // use route_set layout if none defined on this scope
- if ( typeof scope.layout == 'undefined' && req.route.routeSet.layout )
- scope.layout = req.route.routeSet.layout
-
- } else if ( Object.keys(sharedHelpers) != 0 ) {
- scope = merge({}, sharedHelpers, scope)
+ if ( req.route.helpers ) // helpers defined outside a route-set?
+ globalHelpers = req.route.helpers() || {}
+
+ if ( req.route.routeSet ){ // route set helpers defined?
+ routeSetHelpers = req.route.routeSet.helpers() || {}
+
+ // use routeSet layout if none defined on this scope
+ if ( typeof scope.layout == 'undefined' && req.route.routeSet.layout )
+ scope.layout = req.route.routeSet.layout
+ }
+
+ var externals = merge(globalHelpers, routeSetHelpers)
+
+ if ( Object.keys(externals).length != 0 )
+ scope = merge(externals, scope)
}
+
return scope
},
serveStatic: function(req, file){

0 comments on commit a566c3b

Please sign in to comment.