Comparar commits

...

123 Commits

Autor SHA1 Mensagem Data
visionmedia 73c506f19c Release 0.7.0 2010-03-15 09:13:18 -07:00
visionmedia 79143f3334 Chat sample app using pass() 2010-03-15 09:10:50 -07:00
visionmedia 128ba9040e Refactored Router#matchingRoute() 2010-03-15 09:09:51 -07:00
visionmedia 300cfe74ad Request#pass() accepts a pathname string 2010-03-15 09:02:44 -07:00
visionmedia f008af05bd Merge branch 'pull' 2010-03-15 08:54:57 -07:00
Aaron Heckmann 3aa870d6bd return this in pass 2010-03-15 08:50:35 -07:00
Aaron Heckmann 25e1a8c001 add pass specs 2010-03-15 08:50:26 -07:00
Aaron Heckmann 0ba3b114b0 add pass support 2010-03-15 08:50:20 -07:00
visionmedia c429e88e8e Updated --version of node tested against in readme 2010-03-15 08:42:22 -07:00
Aaron Heckmann c7a2fe8440 remove profiler from plugins.js 2010-03-15 08:41:21 -07:00
Aaron Heckmann de237e760b remove Profiler 2010-03-15 08:41:03 -07:00
visionmedia 927f5c9883 Logger copyright 2010-03-12 07:36:50 -08:00
visionmedia 88f461baf2 Logger using Date#format() 2010-03-12 07:14:57 -08:00
visionmedia 3251ae26a0 Fixed plot format 2010-03-12 07:09:56 -08:00
visionmedia e84c81633e "combined" using printf() 2010-03-12 07:09:20 -08:00
visionmedia a2ec966ac7 "common" Logger format using printf() 2010-03-12 07:06:47 -08:00
visionmedia 69660fbfda Merge branch 'integration' 2010-03-12 06:58:34 -08:00
visionmedia dcedca1a80 Removed 'sinatra' logger, added duration to 'common' log format 2010-03-12 06:58:23 -08:00
visionmedia 6455e954fc Removed CommonLogger, use Logger 2010-03-12 06:53:17 -08:00
visionmedia 646904688f No need for utils.mixin() here 2010-03-11 11:16:48 -08:00
visionmedia 62779fc972 Doc typo 2010-03-11 11:14:33 -08:00
visionmedia fdee4cde26 Sample app in readme 2010-03-11 11:14:02 -08:00
visionmedia 0c18ac5adc Added kiwi installation docs 2010-03-11 11:05:41 -08:00
visionmedia 6da4a942ca Managing dependencies with the kiwi package manager. Closes #228
Merge branch 'kiwi'
2010-03-11 11:01:54 -08:00
visionmedia 565f68d2d7 Added kiwi.seed() calls to make them available via require()
This is needed since the view plugin uses
the regular require() and not kiwi.require()
2010-03-11 11:00:47 -08:00
visionmedia a7cee4c889 Removed references to submodules 2010-03-11 10:57:26 -08:00
visionmedia 4f315f9b11 Added haml / sass dependencies 2010-03-11 10:46:08 -08:00
visionmedia 51febfec2d Actually added seed.yml :) 2010-03-10 19:23:56 -08:00
visionmedia df8bd96b2e Added support for arbitrary view engines 2010-03-10 19:23:56 -08:00
visionmedia 9da9beb342 Added seed.yml for kiwi package management support 2010-03-10 19:23:56 -08:00
visionmedia f93af823df Fixed typo 2010-03-10 19:23:51 -08:00
Aaron Heckmann 5e74723a92 add logger 2010-03-10 22:09:07 -05:00
visionmedia ec77e1acea HTTP client appends query string when method is GET. Closes #205 2010-03-10 19:01:40 -08:00
visionmedia 1afad64972 Misc refactoring to http client 2010-03-10 18:53:12 -08:00
visionmedia a3365dda07 Removed usage of RESTful route funcs as http client 2010-03-10 18:49:04 -08:00
visionmedia 4c246a4cd1 Merge branch 'async-plugins' 2010-03-10 18:34:09 -08:00
visionmedia 934ffd0731 Fixed params in show-exception page 2010-03-10 18:32:25 -08:00
visionmedia 790e2c233d Inverted plugin async support. Return true WHEN async 2010-03-10 17:06:46 -08:00
visionmedia 9e9967381c Misc refactoring 2010-03-10 17:01:40 -08:00
visionmedia 891ed08827 Request#trigger() now supports callback as 2nd or 3rd arg 2010-03-10 17:01:08 -08:00
visionmedia 55d13a6f08 Doc typo 2010-03-10 16:58:53 -08:00
visionmedia 5569ea4397 Removed custom exceptions
because they are lame
2010-03-10 16:57:51 -08:00
visionmedia 693e37459a Removed InvalidResponseBody / InvalidStatusCode
stupid anyway, just dont fuck shit up :)
2010-03-10 16:46:47 -08:00
visionmedia 90de1fa55d Refactoring routing slightly 2010-03-10 16:34:21 -08:00
visionmedia 6d6e1557ce Refactored Request#trigger() 2010-03-10 16:26:20 -08:00
visionmedia 2d84f16dc0 Hooks do not support async at the moment anyway, return true 2010-03-10 16:14:54 -08:00
visionmedia 2f98ef9f6d Strict comparisons 2010-03-10 16:12:16 -08:00
visionmedia e0c07d2385 Fixed typo 2010-03-10 16:11:38 -08:00
ciaranj 0b2413d8c0 Missed a curly brace out 2010-03-10 23:52:31 +00:00
ciaranj e92b01f813 Change the approach to be truth based
Now just enforces that a plugin returns true, if it doesn't return true then
we assume the plugin is taking care of making sure that the plugin chain continues.

A sensible enhancement to this might be to improve the request.trigger function to timeout
after a fixed period, log a warning, then carry on as normal ??

I'm not too sure of what 'Hooks.js' does so I may haveconfigured that incorrectly, just FYI
2010-03-10 23:49:38 +00:00
ciaranj 27ff13459f Merge branch 'master' of git://github.com/visionmedia/express into async_plugins
Conflicts:
	lib/express/plugins/cookie.js
	lib/express/plugins/hooks.js
	lib/express/request.js
2010-03-10 23:36:18 +00:00
ciaranj 3e80915454 Oops, still had some proto code in there 2010-03-10 23:23:37 +00:00
ciaranj 4063d2e2c4 Initial stab at async plugin execution 2010-03-10 23:16:31 +00:00
visionmedia ce9416857b Renamed params -> keys now that ext.js is fixed 2010-03-10 13:39:49 -08:00
visionmedia 575d5e8e57 Updated ext.js. Closes #227 2010-03-10 13:38:07 -08:00
visionmedia 14ceb8c046 Release 0.5.0 2010-03-10 13:17:57 -08:00
visionmedia c6c29ca505 Styling 2010-03-10 13:07:04 -08:00
visionmedia c551226504 More refactoring 2010-03-10 13:06:10 -08:00
visionmedia fcbc09543c More refactoring 2010-03-10 13:04:12 -08:00
visionmedia 6d83bb0026 Misc refactoring 2010-03-10 13:00:43 -08:00
visionmedia 0784a513c9 configure() using each() 2010-03-10 12:48:48 -08:00
visionmedia ebcdec0860 Misc refactoring 2010-03-10 12:43:40 -08:00
visionmedia 6805e4f28f Kinda updated feature list a bit 2010-03-10 12:30:50 -08:00
visionmedia 962f5fa412 Removed extname() / basename() utils. Using path module 2010-03-10 12:27:49 -08:00
visionmedia 1385988ab8 Better escape() util 2010-03-10 12:24:08 -08:00
visionmedia 6cc80f8c54 Removed toArray() util. use arguments.values 2010-03-10 12:23:45 -08:00
visionmedia d6c843962d Removed escapeRegexp() util 2010-03-10 12:22:25 -08:00
visionmedia 247e6ad9ab Removed process.mixin() dependency 2010-03-10 12:17:10 -08:00
visionmedia 364c131a4e Merge branch 'ext' 2010-03-10 12:04:38 -08:00
visionmedia b047325033 Updated ext and removed Collection 2010-03-10 12:03:26 -08:00
visionmedia 0894cfe058 Removed more Collection usage 2010-03-10 11:21:29 -08:00
visionmedia f4a9d7e70b Removed more Collection usage 2010-03-10 11:18:14 -08:00
visionmedia 593634fb5d Started removing usage of Collection 2010-03-10 11:16:26 -08:00
visionmedia 2932bf5006 make test / make init distinction 2010-03-10 11:12:12 -08:00
visionmedia 4b1c39fe41 Removed Collection specs 2010-03-10 11:10:12 -08:00
visionmedia ee91e3a139 Started removal of Collection 2010-03-10 11:08:20 -08:00
visionmedia e287b854a2 Added ext.js submodule 2010-03-09 08:31:17 -08:00
visionmedia 5458e5dd00 Misc refactoring 2010-03-09 08:07:55 -08:00
visionmedia ed30f37ca9 Fixing some comments 2010-03-09 08:02:44 -08:00
visionmedia 9e495f6bb8 Misc refactoring to multi-part handling 2010-03-09 07:57:57 -08:00
Aaron Heckmann 21566c49f0 update node version in readme
push the stream.part bugfix from previous commit
2010-03-09 07:54:50 -08:00
Aaron Heckmann 0a225c13a4 refactor run callback
add Server.error
fix bug in run callback (accepts not defined)
fix bug in stream.body event (part is undefined)
2010-03-09 07:54:46 -08:00
Aaron Heckmann 680c07a030 ensure uploaded files close before routing 2010-03-09 07:54:41 -08:00
visionmedia 8ee66dca22 Updated HTTP client. Closes #221
Merge branch 'update-http-client'
2010-03-08 18:43:38 -08:00
visionmedia 60393f07ef Removed debugging data 2010-03-08 18:43:05 -08:00
visionmedia 34418b03fb HTTP client is resolving callback function amoung other args 2010-03-08 18:42:28 -08:00
visionmedia ce2f161f08 Implemented max redirects option for http client. Closes #204 2010-03-08 18:33:23 -08:00
visionmedia d5ca1ea152 Started fixing HTTP client 2010-03-08 18:08:09 -08:00
visionmedia c3fec8225a Removed http client allowData 2010-03-08 17:51:32 -08:00
visionmedia bfff00826e Styling 2010-03-08 17:11:16 -08:00
visionmedia 61cb50b2bd Styling 2010-03-08 17:09:36 -08:00
visionmedia c8d3bfabc7 Styling 2010-03-08 17:01:35 -08:00
visionmedia 1ce212d33d Styling 2010-03-08 17:00:56 -08:00
visionmedia 3682f4f06a Styling 2010-03-08 16:57:49 -08:00
visionmedia 0f74408b0e Styling 2010-03-08 16:56:31 -08:00
visionmedia f7d7c4a8e0 Merge branch 'node-0.1.30' 2010-03-08 16:42:41 -08:00
visionmedia 0cb8d12796 Removed ElementCollection support
this will become another library
2010-03-08 16:40:23 -08:00
ciaranj 9586ecfd58 Multipart form-data / File uploading now works again
Haven't re-implemented a timeout, wasn't sure what behaviour was wanted here...should
be easy enough to do, wish I could get local tests working again :(
2010-03-09 00:13:00 +00:00
ciaranj 86217867f9 Now working on node 0.1.30 but using custom mixin 2010-03-08 22:00:09 +00:00
Aaron Heckmann 496de51a11 Common log client address instead of server address 2010-03-05 07:38:08 -08:00
visionmedia 38591d06a0 Deep copy request 2010-03-05 07:32:57 -08:00
visionmedia 91805f7da4 Shameless self promotion of ebook 2010-02-22 14:48:43 -08:00
visionmedia 7bd8340a8b Fixed Collection#clone() 2010-02-22 13:30:46 -08:00
visionmedia 4817007097 Re-throwing errors 2010-02-22 13:26:35 -08:00
visionmedia d5003feb39 Fixed mocks to match node api 2010-02-22 08:08:51 -08:00
visionmedia f03e460ca5 Started converting fs module 2010-02-22 08:05:13 -08:00
visionmedia 347c8847b0 Removed addErrback() from render()
throws with latest node
2010-02-12 10:36:23 -08:00
visionmedia 9f48b32329 Benchmarks link 2010-02-12 09:34:40 -08:00
visionmedia 2f6dfbc165 Release 0.4.0 2010-02-11 17:02:30 -08:00
visionmedia 49cb53d735 Merge branch 'route-http-client-security' 2010-02-11 16:36:47 -08:00
visionmedia 54f1a51a10 Throwing error when routes are added at runtime
Since it doubles as an http client, without this
someone could arbitrarily create routes.. haha not good!
2010-02-11 16:36:38 -08:00
visionmedia c6a2674c2b Merge branch 'http' 2010-02-11 16:15:42 -08:00
visionmedia 282a10ec83 RESTful route functions double as HTTP clients. Closes #69
For example:
  get("http://google.com").addCallback(function(content){
    puts(content)
  })
2010-02-11 16:15:37 -08:00
visionmedia 50276a06df Merge branch 'http-client' 2010-02-11 16:11:00 -08:00
visionmedia f452250f88 Added high level restful http client 2010-02-11 16:10:43 -08:00
visionmedia 9d44e237a5 Added status code string to error 2010-02-11 15:30:16 -08:00
visionmedia 9f0e5899c2 Fixed Host header issue 2010-02-11 15:11:06 -08:00
visionmedia e351a02a06 Merge branch 'flash' 2010-02-11 14:22:59 -08:00
visionmedia cd167ec777 Added flash() example to sample upload app 2010-02-11 14:22:55 -08:00
visionmedia 3290412477 Updated haml 2010-02-11 14:02:26 -08:00
visionmedia acf0128fb4 Merge branch 'view-context' 2010-02-11 13:57:33 -08:00
visionmedia e91ee22a89 Defaulting render() context to the current Request. Closes #197 2010-02-11 13:57:26 -08:00
visionmedia 8e91d2039a Started high level HTTP api 2010-02-05 15:16:48 -08:00
53 arquivos alterados com 722 adições e 2225 exclusões
+2
Ver Arquivo
@@ -1 +1,3 @@
.DS_Store
*.seed
*.log
-12
Ver Arquivo
@@ -1,12 +0,0 @@
[submodule "spec/support/libxmljs"]
path = spec/support/libxmljs
url = git://github.com/sprsquish/libxmljs.git
[submodule "lib/support/haml"]
path = lib/support/haml
url = git://github.com/creationix/haml-js.git
[submodule "lib/support/js-oo"]
path = lib/support/js-oo
url = git://github.com/visionmedia/js-oo.git
[submodule "lib/support/sass"]
path = lib/support/sass
url = git://github.com/visionmedia/sass.js.git
+47
Ver Arquivo
@@ -1,4 +1,51 @@
0.7.0 / 2010-03-15
==================
* Added Request#pass() support (finds the next matching route, or the given path)
* Added Logger plugin (default "common" format replaces CommonLogger)
* Removed Profiler plugin
* Removed CommonLogger plugin
0.6.0 / 2010-03-11
==================
* Added seed.yml for kiwi package management support
* Added HTTP client query string support when method is GET. Closes #205
* Added support for arbitrary view engines.
For example "foo.engine.html" will now require('engine'),
the exports from this module are cached after the first require().
* Added async plugin support
* Removed usage of RESTful route funcs as http client
get() etc, use http.get() and friends
* Removed custom exceptions
0.5.0 / 2010-03-10
==================
* Added ext dependency (library of js extensions)
* Removed extname() / basename() utils. Use path module
* Removed toArray() util. Use arguments.values
* Removed escapeRegexp() util. Use RegExp.escape()
* Removed process.mixin() dependency. Use utils.mixin()
* Removed Collection
* Removed ElementCollection
* Shameless self promotion of ebook "Advanced JavaScript" (http://dev-mag.com) ;)
0.4.0 / 2010-02-11
==================
* Added flash() example to sample upload app
* Added high level restful http client module (express/http)
* Changed; RESTful route functions double as HTTP clients. Closes #69
* Changed; throwing error when routes are added at runtime
* Changed; defaulting render() context to the current Request. Closes #197
* Updated haml submodule
0.3.0 / 2010-02-11
==================
+2 -18
Ver Arquivo
@@ -3,18 +3,9 @@ NODE = node
all: test
init:
@git submodule init && git submodule update
test: init spec/support/libxmljs/libxmljs.node
test:
@$(NODE) spec/node.js all
test-independant: init
@$(NODE) spec/node.js independant
test-dependant: init spec/support/libxmljs/libxmljs.node
@$(NODE) spec/node.js dependant
app: app-chat
app-chat:
@@ -23,11 +14,4 @@ app-chat:
app-upload:
@$(NODE) examples/upload/app.js
benchmark:
@$(NODE) benchmarks/collection.js
@$(NODE) benchmarks/views.js
spec/support/libxmljs/libxmljs.node:
@scons -C spec/support/libxmljs libxmljs.node
.PHONY: init test benchmark app
.PHONY: test app
+20 -58
Ver Arquivo
@@ -14,88 +14,50 @@
* Session support
* Mime helpers
* Redirection helpers
* Nested parameter parsing
* Full test coverage
* Extremely readable specs
* Multipart file upload support
* Test helpers (mock requests etc)
* Environment based configuration
* Light-weight JavaScript class implementation via js-oo
* Collections and chainable iterators
* ElementCollections / markup parsing via libxmljs and css selector traversal support via css2xpath
* View support (ejs, haml, sass, etc)
* Full test coverage
* Extremely readable specs
## Installation
Currently Express must be cloned (or downloaded), you can use the following command to
get rolling and initialize the submodule dependencies:
$ git clone git://github.com/visionmedia/express.git && cd express && git submodule update --init && make app
Or with the [gh](http://github.com/visionmedia/gh) utility:
$ gh clone visionmedia express && cd express && git submodule update --init && make app
Install the [Kiwi package manager for nodejs](http://github.com/visionmedia/kiwi)
and run:
$ kiwi -v install express
## Performance
Extensive benchmarking will wait until a development version
has been released.
Extensive performance enhancements have not yet been made,
since we are focusing on the framework it-self at the moment.
Currently Express can chew through a request with a two Haml views (*page and layout*)
requested **2000** times with concurrency of **80** in **2.4** seconds and **814**
requests per second. With no caching involved.
An identical Sinatra application was served with the **Thin** HTTP server
and scored **8.3** seconds and **238** requests per second. In this situation
Express is currently **3.5** times faster than Sinatra.
However if you are interested view the premature [benchmarks for Express framework](http://vision-media.ca/resources/nodejs/express-nodejs-web-development-framework-performance).
## Examples
Below is a minimal app example when express is already within your load path.
Below is a tiny Express application. View the [Wiki](http://wiki.github.com/visionmedia/express/) for detailed information.
require('express')
require('express/plugins')
configure(function(){
use(MethodOverride)
use(ContentLength)
set('root', __dirname)
})
get('/hello', function(){
var kiwi = require('kiwi'),
express = kiwi.require('express')
get('/hello-world', function(){
this.contentType('html')
return '<h1>World<h1>'
return '<h1>Hello World</h1>'
})
get('/user/:id?', function(id) {
this.render('user.haml.html', {
locals: {
name: id ? 'User ' + id : 'You'
}
})
})
run()
## Running Tests
Express uses the [JSpec](http://jspec.info) BDD JavaScript testing
framework to write and run elegant spec suites. JSpec is frozen
to spec/lib and does not require separate installation.
To run all specifications run the following command. This will ensure
git submodules are initialized and updated, as well as building test
related dependencies such as libxmljs.
to spec/lib and **does not** require separate installation.
$ make test
To run independent specs (which do not require building of external apis etc) use:
$ make test-independant
To run dependent specs (which require building of external apis etc) use:
$ make test-dependant
Run individual suites:
$ node spec/node.js core
@@ -104,13 +66,13 @@ Run individual suites:
...
Express is currently being developed with node --version:
v0.1.27
v0.1.32
## More Information
* [JavaScript Extensions &amp; Utilities](http://github.com/visionmedia/ext.js)
* [JavaScript Sass](http://github.com/visionmedia/sass.js)
* [Scons Build System](http://www.scons.org/) (some development dependencies rely on this, ex libxmljs)
* Featured in [Advanced JavaScript e-book](http://www.dev-mag.com/2010/02/18/advanced-javascript/) for only $4
## Contributors
-83
Ver Arquivo
@@ -1,83 +0,0 @@
;(function(){
var currentSuite
/**
* Contents of _fn_. Strips function literal and signature.
*
* @param {function} fn
* @return {string}
* @api private
*/
function contentsOf(fn) {
return fn.toString().match(/^[^\{]*{((.*\n*)*)}/m)[1]
}
/**
* Pad _str_ to _len_.
*
* @param {string} str
* @param {integer} len
* @return {string}
* @api private
*/
function pad(str, len) {
return str + (new Array(len - str.length)).join(' ')
}
/**
* Time the execution of _fn_
*
* @param {function} fn
* @return {float}
* @api private
*/
function time(fn) {
var start = Number(new Date)
fn()
return (Number(new Date) - start) / 1000
}
/**
* Benchmark _fn_ with the given _label_.
*
* @param {string} label
* @param {function} fn
* @api public
*/
function benchmark(label, fn) {
var duration = time(function(){
for (var i = 0; i < currentSuite.times; ++i)
fn()
}).toFixed(3)
print(pad(' ' + label, 50 - duration.toString().length) + duration + ' |')
}
/**
* Create a benchmark suite with the given _label_, which
* will run each benchmark n _times_. If _times_ is omitted
* then it defaults to 1.
*
* @param {string} label
* @param {integer, function} times
* @param {function} fn
* @api public
*/
suite = function(label, times, fn) {
currentSuite = this
if (typeof times == 'function')
this.times = 1, fn = times
else
this.times = times
print('\n ' + pad(label, 42 - this.times.toString().length) + this.times + ' time(s)')
print(' -------------------------------------------------')
eval(contentsOf(fn))
print('')
}
})()
-111
Ver Arquivo
@@ -1,111 +0,0 @@
require.paths.unshift('lib')
require.paths.unshift('benchmarks')
process.mixin(GLOBAL, require('sys'))
process.mixin(GLOBAL, require('benchmark'))
require('express')
print = puts
range = function(a, b) {
var array = []
while (a++ < b)
array.push(a-1)
return array
}
suite('Collection with [0..10,000]', 100, function(){
array = range(0, 10000)
benchmark('for', function(){
for (var i = 0, len = array.length; i < len; ++i) ;
})
benchmark('for uncached', function(){
for (var i = 0; i < array.length; ++i) ;
})
benchmark('forEach()', function(){
array.forEach(function(){})
})
benchmark('#each()', function(){
$(array).each(function(){})
})
benchmark('#map()', function(){
$(array).map(function(n){ return n += 1 })
})
benchmark('#map() with shorthand', function(){
$(array).map('a += 1')
})
benchmark('#find()', function(){
$(array).find(function(n){ return n > 5000 })
})
benchmark('#select()', function(){
$(array).select(function(n){ return n % 2 })
})
benchmark('#first()', function(){
$(array).first(5000)
})
benchmark('#slice()', function(){
$(array).slice(100, 5000)
})
benchmark('#drop()', function(){
$(array).drop(5000)
})
benchmark('#length()', function(){
$(array).length()
})
benchmark('#keys()', function(){
$(array).keys()
})
benchmark('#toArray()', function(){
$(array).toArray()
})
benchmark('#min()', function(){
$(array).min()
})
benchmark('#max()', function(){
$(array).max()
})
benchmark('#sum()', function(){
$(array).sum()
})
benchmark('#avg()', function(){
$(array).avg()
})
benchmark('#clone()', function(){
$(array).clone()
})
benchmark('#merge()', function(){
$(array).merge({ foo: 'bar' })
})
benchmark('#sample()', function(){
$(array).sample()
})
benchmark('#chunk()', function(){
$(array).chunk(5)
})
benchmark('#at()', function(){
$(array).at(5000)
})
})
-56
Ver Arquivo
@@ -1,56 +0,0 @@
require.paths.unshift('lib')
require.paths.unshift('benchmarks')
process.mixin(GLOBAL, require('sys'))
process.mixin(GLOBAL, require('benchmark'))
require('express')
print = puts
engine = {
ejs: require('ejs'),
haml: require('haml'),
sass: require('sass')
}
options = { locals: { article: { title: 'Foo', body: 'bar' }}}
ejs = ' \n\
<div id="primary"> \n\
<div class="block first"> \n\
<h1><%= article.title %></h1> \n\
<p><%= article.body %></p> \n\
</div> \n\
</div> \n\
'
haml = ' \n\
#primary \n\
.block.first \n\
%h1= article.title \n\
%p= article.body \n\
'
sass = ' \n\
red: #ff0000 \n\
body \n\
ul \n\
li \n\
a \n\
:color !red \n\
:list-style none \n\
'
suite('Template Engines', 1000, function(){
benchmark('ejs', function(){
engine.ejs.render(ejs, options)
})
benchmark('haml', function(){
engine.haml.render(haml, options)
})
benchmark('sass', function(){
engine.sass.render(sass)
})
})
+8 -5
Ver Arquivo
@@ -3,23 +3,26 @@ require.paths.unshift('lib')
require('express')
require('express/plugins')
var messages = [],
utils = require('express/utils'),
kiwi = require('kiwi')
configure(function(){
var fiveMinutes = 300000,
oneMinute = 60000
kiwi.seed('haml')
kiwi.seed('sass')
use(MethodOverride)
use(ContentLength)
use(CommonLogger)
use(Cookie)
use(Cache, { lifetime: fiveMinutes, reapInterval: oneMinute })
use(Session, { lifetime: fiveMinutes, reapInterval: oneMinute })
use(Logger)
set('root', __dirname)
})
var messages = [],
utils = require('express/utils')
get('/', function(){
this.redirect('/chat')
this.pass('/chat')
})
get('/chat', function(){
+18 -6
Ver Arquivo
@@ -3,10 +3,17 @@ require.paths.unshift('lib')
require('express')
require('express/plugins')
var kiwi = require('kiwi')
configure(function(){
kiwi.seed('haml')
kiwi.seed('sass')
use(MethodOverride)
use(ContentLength)
use(CommonLogger)
use(Cookie)
use(Session)
use(Flash)
use(Logger)
set('root', __dirname)
})
@@ -15,13 +22,18 @@ get('/', function(){
})
get('/upload', function(){
this.render('upload.haml.html')
this.render('upload.haml.html', {
locals: {
flashes: this.flash('info')
}
})
})
post('/upload', function(){
$(this.param('images')).each(function(image){
puts('uploaded ' + image.filename + ' to ' + image.tempfile)
})
post('/upload', function(){
this.param('images').each(function(image){
puts(image.filename + ' -> ' + image.tempfile)
this.flash('info', 'Uploaded ' + image.filename)
}, this)
this.redirect('/upload')
})
+7 -1
Ver Arquivo
@@ -5,4 +5,10 @@
%script{ src: '/public/javascripts/app.js' }
%link{ rel: 'stylesheet', href: '/style.css' }
%body
#wrapper= body
#wrapper
%h1 Upload
:if flashes
%ul.messages.info
:each msg in flashes
%li= msg
.body= body
+10 -1
Ver Arquivo
@@ -56,4 +56,13 @@ form
.panel
:float left
:width 100%
:margin-bottom 15px
:margin-bottom 15px
.messages
:margin 0
:padding 0
:border 1px solid #eee
=box-shadow 2px 2px 5px #eee
li
:padding 5px 10px
:list-style none
-1
Ver Arquivo
@@ -1,4 +1,3 @@
%h1 Upload
:if typeof images !== 'undefined'
.images
:each img in images
+3 -5
Ver Arquivo
@@ -1,7 +1,5 @@
require.paths.unshift(__dirname + '/support/js-oo/lib')
require.paths.unshift(__dirname + '/support/ejs/lib')
require.paths.unshift(__dirname + '/support/haml/lib')
require.paths.unshift(__dirname + '/support/sass/lib')
require('oo')
var kiwi = require('kiwi')
kiwi.require('oo', '>= 1.2.0')
kiwi.require('ext', '>= 0.2.2')
require('express/core')
-543
Ver Arquivo
@@ -1,543 +0,0 @@
// Express - Collection - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
/**
* Throw $break in order to stop iteration.
*/
$break = '__break__'
var property = /^\w+$/,
method = /^\w+\(/
/**
* Normalize callback _fn_. When a string is
* passed convert the shorthand expr to a function.
*
* - Functions are passed through un-touched
* - Strings with length of < 4 are considered operators between a and b
* - Single words are considered properties on a
* - Single functions are considered method calls on a
* - Larger strings are considered return expressions
*
* @param {string, function} fn
* @return {function}
* @api private
*/
function callback(fn) {
if (fn === undefined) return
if (fn instanceof Function) return fn
if (fn.length < 4) return Function('a, b, c', 'return a ' + fn + ' b')
if (property.test(fn) || method.test(fn)) fn = 'a.' + fn
return Function('a, b, c', 'return ' + fn)
}
// --- Collection
Collection = Class({
/**
* Initialize collection with an array-like object.
*
* @param {object} arr
* @api private
*/
init: function(arr) {
this.arr = arr || []
},
/**
* Return the value of _index_ or null.
*
* @param {int} index
* @return {mixed}
* @api public
*/
at: function(index) {
if ('length' in this.arr)
return this.arr[index]
var result, i = 0
this.each(function(val){
if (i++ == index) {
result = val
throw $break
}
})
return result
},
/**
* Iterate collection using callback _fn_,
* passing both the value and index.
*
* @param {function} fn
* @return {Collection}
* @api public
*/
each: function(fn) {
try {
if (this.arr.forEach)
this.arr.forEach(fn)
else
for (var key in this.arr)
if (this.arr.hasOwnProperty(key))
fn(this.arr[key], key)
}
catch (e) {
if (e != $break) throw e
}
return this
},
/**
* Reverse a collection.
*
* @return {Collection}
* @api public
*/
reverse: function() {
if (this.arr.reverse)
return $(this.arr.reverse())
return this
},
/**
* Join a collection with the given _str_ or ''.
*
* @param {string} str
* @return {string}
* @api public
*/
join: function(str) {
return this.toArray().join(str || '')
},
/**
* Sort collection with optional _fn_.
*
* @param {function} fn
* @return {Collection}
* @warn converts to array
* @api public
*/
sort: function(fn) {
fn = callback(fn)
return $(this.toArray().sort(fn))
},
/**
* Iterate with _memo_ using callback _fn_.
* The _memo_ object is passed as the first
* argument, and the return value of _fn_ becomes
* the value of _memo_ providing a functional
* approach to reducing a collection.
*
* @param {mixed} memo
* @param {function} fn
* @return {mixed}
* @api public
*/
reduce: function(memo, fn) {
fn = callback(fn)
if (this.arr.reduce)
return this.arr.reduce(fn, memo)
this.each(function(val, key){
memo = fn(memo, val, key)
})
return memo
},
/**
* Map using callback _fn_, returning a
* new collection of return values.
*
* @param {function} fn
* @return {Collection}
* @api public
*/
map: function(fn) {
fn = callback(fn)
if (this.arr.map)
return $(this.arr.map(fn))
return $(this.reduce([], function(array, val, key){
array.push(fn(val, key))
return array
}))
},
/**
* Return collection of values when _fn_ evaluates
* to true.
*
* @param {function} fn
* @return {Collection}
* @api public
*/
select: function(fn) {
fn = callback(fn)
return $(this.reduce([], function(array, val, key){
if (fn(val, key))
array.push(val)
return array
}))
},
/**
* Return collection of values when _fn_ evaluates
* to false.
*
* @param {function} fn
* @return {Collection}
* @api public
*/
reject: function(fn) {
fn = callback(fn)
return $(this.reduce([], function(array, val, key){
if (!fn(val, key))
array.push(val)
return array
}))
},
/**
* Check if all arguments passed are found within
* the collection using the === operator.
*
* @return {bool}
* @api public
*/
includes: function() {
var self = this
return $(arguments).all(function(arg){
return self.any(function(val){
return val === arg
})
})
},
/**
* Return the first _n_ value(s), defaults to 1.
*
* @param {int} n
* @return {mixed}
* @api public
*/
first: function(n) {
return n ?
this.slice(0, n) :
this.at(0)
},
/**
* Return the last _n_ value(s), defaults to -1.
*
* @param {int} n
* @return {mixed}
* @api public
*/
last: function(n) {
var len = this.length()
return n ?
this.slice(len - n, len) :
this.at(--len)
},
/**
* Drop the first _n_ values, returning the others.
*
* @param {int} n
* @return {Collection}
* @api public
*/
drop: function(n) {
return this.slice(n, this.length())
},
/**
* Return a slice of values from _start_ to _end_.
*
* @param {int} start
* @param {int} end
* @return {Collection}
* @api public
*/
slice: function(start, end) {
if (this.arr.slice)
return $(this.arr.slice(start, end))
var i = 0
return $(this.reduce([], function(array, val){
if (i++ >= start)
if (i <= end)
array.push(val)
else
throw $break
return array
}))
},
/**
* Iterate until _fn_ evaluates to true, then
* return the matching value.
*
* @param {function} fn
* @return {mixed}
* @api public
*/
find: function(fn) {
var result, fn = callback(fn)
this.each(function(val, key){
if (fn(val, key)) {
result = val
throw $break
}
})
return result
},
/**
* Return true if _fn_ ever evaluates to true, otherwise
* returns false.
*
* @param {function} fn
* @return {bool}
* @api public
*/
any: function(fn) {
fn = callback(fn)
if (this.arr.some)
return this.arr.some(fn)
return !! this.find(fn)
},
/**
* Returns true if _fn_ always evaluates to true, otherwise
* returns false.
*
* @param {function} fn
* @return {bool}
* @api public
*/
all: function(fn) {
fn = callback(fn)
if (this.arr.every)
return this.arr.every(fn)
return this.reduce(true, function(state, val, key){
if (!state) throw $break
return !! fn(val, key)
})
},
/**
* Select values matching _pattern_
*
* @param {regexp} pattern
* @return {Collection}
* @api public
*/
grep: function(pattern) {
return this.select(function(val){
return pattern.exec(val)
})
},
/**
* Return keys as a collection.
*
* @return {Collection}
* @api public
*/
keys: function() {
return $(Object.keys(this.arr))
},
/**
* Convert a collection to a true array.
* Works recursively
*
* @return {array}
* @api public
*/
toArray: function() {
return this.reduce([], function(array, val){
val instanceof Collection ?
array.push(val.toArray()) :
array.push(val)
return array
})
},
/**
* Return the lowest number in the collection.
*
* @return {number}
* @api public
*/
min: function() {
return this.reduce(null, function(min, val){
return min === null ? val :
val < min ? val :
min
})
},
/**
* Return the largest number in the collection.
*
* @return {number}
* @api public
*/
max: function() {
return this.reduce(null, function(max, val){
return max === null ? val :
val > max ? val :
max
})
},
/**
* Group collection into several collections grouped by _size_.
*
* @param {int} size
* @return {Collection}
* @api public
*/
chunk: function(size) {
var len = this.arr.length,
chunks = [], chunk = [], i = 0
this.each(function(val, key){
chunk.push(val)
if (i++ > 0 && (i % size == 0 || i == len))
chunks.push($(chunk)),
chunk = []
})
return $(chunks)
},
/**
* Return the length of this collection.
*
* @return {int}
* @api public
*/
length: function() {
if ('length' in this.arr)
return this.arr.length
return this.reduce(0, function(len){
return ++len
})
},
/**
* Return the sum of numeric values in this collection.
*
* @return {number}
* @api public
*/
sum: function() {
return this.reduce(0, function(sum, n){
return sum + n
})
},
/**
* Return the average of numeric values in this collection.
*
* @return {number}
* @api public
*/
avg: function() {
return this.sum() / this.length()
},
/**
* Merge _other_ with this collection.
*
* @param {mixed} other
* @return {Collection}
* @api public
*/
merge: function(other) {
if (this.arr instanceof Array)
return $($(other).reduce(this.arr, function(array, val){
array.push(val)
return array
}))
else
return $(process.mixin(this.arr, $(other).arr))
},
/**
* Clone the collection.
*
* @return {Collection}
* @api public
*/
clone: function() {
return this.merge({})
},
/**
* Return the value of a random index.
*
* @return {mixed}
* @api public
*/
sample: function() {
return this.at(Math.floor(Math.random() * this.length()))
},
/**
* Convert collection to a string.
*
* @return {string}
* @api public
*/
toString: function() {
return '[Collection ' + this.arr + ']'
}
})
/**
* Create a new collection from an array-like object.
*
* @param {object} arr
* @return {Collection}
* @api public
*/
var $ = exports.$ = function(arr) {
if (arr instanceof Collection) return arr
return new Collection(arr)
}
+107 -83
Ver Arquivo
@@ -1,23 +1,21 @@
// Express - Core - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
process.mixin(require('sys'))
process.mixin(require('express/exceptions'))
process.mixin(require('express/collection'))
process.mixin(require('express/event'))
process.mixin(require('express/request'))
process.mixin(require('express/plugin'))
process.mixin(require('express/dsl'))
/**
* Module dependencies.
*/
var multipart = require('multipart'),
utils = require('express/utils'),
events = require('events'),
File = require('file').File,
utils = require('express/utils')
fs = require('fs')
global.merge(require('sys'))
global.merge(require('express/event'))
global.merge(require('express/request'))
global.merge(require('express/plugin'))
global.merge(require('express/dsl'))
// --- Route
Route = Class({
@@ -71,7 +69,7 @@ Route = Class({
var self = this
this.keys = []
if (path instanceof RegExp) return path
return new RegExp('^' + utils.escapeRegexp(normalizePath(path), '.')
return new RegExp('^' + RegExp.escape(normalizePath(path), '.')
.replace(/\*/g, '(.+)')
.replace(/(\/|\\\.):(\w+)\?/g, function(_, c, key){
self.keys.push(key)
@@ -106,10 +104,19 @@ Router = Class({
* @api private
*/
route: function(){
var route = this.matchingRoute()
if (route)
return route.fn.apply(this.request, this.request.captures.slice(1))
route: function() {
var body,
route = this.matchingRoute()
if (route) {
body = route.fn.apply(this.request, this.request.captures.slice(1));
if (this.request.passed) {
if (typeof this.request.passed === 'string')
this.request.url.pathname = this.request.passed
this.request.passed = false
return this.route()
}
return body
}
else if (this.request.accepts('html') && set('helpful 404'))
this.request.halt(404, require('express/pages/not-found').render(this.request))
else
@@ -123,11 +130,13 @@ Router = Class({
* @api private
*/
matchingRoute: function(){
var self = this
return $(Express.routes).find(function(route){
return self.match(route)
})
matchingRoute: function() {
this.lastMatchingRoute = this.lastMatchingRoute || 0
var routes = Express.routes, route
while (route = routes[this.lastMatchingRoute++])
if (this.match(route))
break
return route
},
/**
@@ -149,17 +158,16 @@ Router = Class({
/**
* Map #request.captures to #request.params.path based on the
* given _route_ keys.
* given _route_ params.
*
* @param {Route} route
* @api private
*/
mapParams: function(route) {
var self = this
$(route.keys).each(function(key, i){
self.request.params.path[key] = self.request.captures[++i]
})
route.keys.each(function(key, i){
this.request.params.path[key] = this.request.captures[++i]
}, this)
}
})
@@ -201,6 +209,7 @@ Server = Class({
run: function(port, host, backlog){
var self = this
this.running = true
if (host !== undefined) this.host = host
if (port !== undefined) this.port = port
if (backlog !== undefined) this.backlog = backlog
@@ -208,51 +217,50 @@ Server = Class({
.createServer(function(request, response){
request.body = ''
request.setBodyEncoding('binary')
function callback(e, result) {
if (e)
self.error(e, request, response)
else if (!pendingFiles)
self.route(request, response)
}
if (request.headers['content-type'] &&
request.headers['content-type'].indexOf('multipart/form-data') !== -1) {
var stream = new multipart.Stream(request),
promise = new events.Promise,
request.headers['content-type'].includes('multipart/form-data')) {
var stream = multipart.parse(request),
pendingFiles = 0
request.params = { post: {}}
promise.timeout(set('upload timeout') || 5000)
stream.addListener('part', function(part){
if (part.filename) {
var file = new File(part.tempfile = '/tmp/express-' + Number(new Date) + utils.uid(), 'w', { encoding: 'binary' })
++pendingFiles
part.pos = 0
part.addListener('body', function(chunk){
file.write(chunk, part.pos, 'binary').addErrback(function(){
promise.emitError.apply(promise, arguments)
})
part.pos += chunk.length
})
.addListener('complete', function(){
file.close().addCallback(function(){
if (!--pendingFiles)
promise.emitSuccess()
}).addErrback(function(){
promise.emitError.apply(promise, arguments)
})
utils.mergeParam(part.name, part, request.params.post)
})
}
else
part.buf = '',
part
.addListener('body', function(chunk){ part.buf += chunk })
.addListener('complete', function(){
if (part.buf.length)
utils.mergeParam(part.name, part.buf, request.params.post)
})
}).addListener('complete', function(){
if (!pendingFiles) promise.emitSuccess()
promise.addCallback(function(){ self.route(request, response) })
})
stream
.addListener('partBegin', function(part) {
if (part.filename)
++pendingFiles,
part.tempfile = '/tmp/express-' + Number(new Date) + utils.uid(),
part.fileStream = fs.createWriteStream(part.tempfile)
else
part.buf = ''
})
.addListener('body', function(chunk) {
if (stream.part.fileStream)
stream.part.fileStream.write(chunk)
else
stream.part.buf += chunk
})
.addListener('partEnd', function(part) {
if (!part.name) return
if (part.fileStream)
part.fileStream.close(function(){
--pendingFiles
callback()
}),
utils.mergeParam(part.name, { filename: part.filename, tempfile: part.tempfile }, request.params.post)
else
utils.mergeParam(part.name, part.buf, request.params.post)
})
.addListener('error', callback)
.addListener('complete', callback)
}
else
request
.addListener('body', function(chunk){ request.body += chunk })
.addListener('complete', function(){ self.route(request, response) })
.addListener('data', function(chunk){ request.body += chunk })
.addListener('end', callback)
})
.listen(this.port, this.host, this.backlog)
puts('Express started at http://' + this.host + ':' + this.port + '/ in ' + Express.environment + ' mode')
@@ -267,30 +275,46 @@ Server = Class({
*/
route: function(request, response){
request = new Request(request, response)
request.trigger('request')
if (request.response.finished) return
try {
if (typeof (body = (new Router(request)).route()) == 'string')
request.halt(200, body)
}
catch (e) {
if (e instanceof ExpressError)
throw e
if (request.accepts('html') && set('show exceptions'))
request.halt(500, require('express/pages/show-exceptions').render(request, e))
else
request.halt(500)
if (set('throw exceptions'))
throw e
}
var self = this,
request = new Request(request, response)
request.trigger('request', function(e) {
try {
if (e) throw e
if (request.response.finished) return
if (typeof (body = (new Router(request)).route()) === 'string')
request.halt(200, body)
} catch (e) {
self.error(e, request)
}
})
},
/**
* Handle errors.
*
* @param {Error} e
* @param {object} request
* @param {object} response
* @api private
*/
error: function (e, request, response) {
if (!(request instanceof Request))
request = new Request(request, response),
request.trigger('request')
if (request.accepts('html') && set('show exceptions'))
request.halt(500, require('express/pages/show-exceptions').render(request, e))
else
request.halt(500)
if (set('throw exceptions'))
throw e
}
})
// --- Express
Express = {
version: '0.3.0',
version: '0.7.0',
config: [],
routes: [],
plugins: [],
+24 -20
Ver Arquivo
@@ -13,7 +13,10 @@ function route(method) {
return function(path, options, fn){
if (options instanceof Function)
fn = options, options = {}
Express.routes.push(new Route(method, path, fn, options))
if (!Express.server.running)
Express.routes.push(new Route(method, path, fn, options))
else
throw new Error('cannot create route ' + method.toUpperCase() + " `" + path + "' at runtime")
}
}
@@ -28,11 +31,11 @@ function route(method) {
*/
exports.set = function(option, val) {
return val === undefined ?
Express.settings[option] instanceof Function ?
Express.settings[option]() :
Express.settings[option] :
Express.settings[option] = val
return val === undefined
? Express.settings[option] instanceof Function
? Express.settings[option]()
: Express.settings[option]
: Express.settings[option] = val
}
/**
@@ -68,8 +71,8 @@ exports.disable = function(option) {
*/
exports.run = function() {
configure(Express.environment = process.ENV.EXPRESS_ENV || 'development')
$(Express.plugins).each(function(plugin){
configure(Express.environment = process.env.EXPRESS_ENV || 'development')
Express.plugins.each(function(plugin){
if ('init' in plugin.klass)
plugin.klass.init(plugin.options)
})
@@ -77,7 +80,7 @@ exports.run = function() {
}
/**
* Configure _environment_ with _fn_.
* Configure _env_ with _fn_.
*
* Global configuration, disregards which
* environment is active:
@@ -96,22 +99,23 @@ exports.run = function() {
*
* configure('development')
*
* @param {string, function} environment
* @param {string, function} env
* @param {function} fn
* @api public
*/
exports.configure = function(environment, fn) {
if (environment instanceof Function)
fn = environment, environment = 'all'
exports.configure = function(env, fn) {
if (env instanceof Function)
fn = env, env = 'all'
if (fn instanceof Function)
return Express.config.push([environment, fn])
if (typeof environment != 'string')
return Express.config.push([env, fn])
if (typeof env !== 'string')
throw new Error('environment required')
for (var i = 0, len = Express.config.length; i < len; ++i)
if (Express.config[i][0] == environment ||
Express.config[i][0] == 'all')
Express.config[i][1].call(Express)
Express.config.each(function(conf){
if (conf[0] === env ||
conf[0] === 'all')
conf[1].call(Express)
})
}
// --- Routing API
@@ -119,4 +123,4 @@ exports.configure = function(environment, fn) {
exports.get = exports.view = route('get')
exports.post = exports.create = route('post')
exports.del = exports.destroy = route('delete')
exports.put = exports.update = route('put')
exports.put = exports.update = route('put')
-179
Ver Arquivo
@@ -1,179 +0,0 @@
// Express - ElementCollection - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
/**
* Module dependencies.
*/
var libxml = require('libxmljs')
// --- css2xpath
/** version 0.1 2009-04-30
* @author Andrea Giammarchi
* @license Mit Style License
* @project http://code.google.com/p/css2xpath/
*/
var css2xpath=(function(){var b=[/\[([^\]~\$\*\^\|\!]+)(=[^\]]+)?\]/g,"[@$1$2]",/\s*,\s*/g,"|",/\s*(\+|~|>)\s*/g,"$1",/([a-zA-Z0-9\_\-\*])~([a-zA-Z0-9\_\-\*])/g,"$1/following-sibling::$2",/([a-zA-Z0-9\_\-\*])\+([a-zA-Z0-9\_\-\*])/g,"$1/following-sibling::*[1]/self::$2",/([a-zA-Z0-9\_\-\*])>([a-zA-Z0-9\_\-\*])/g,"$1/$2",/\[([^=]+)=([^'|"][^\]]*)\]/g,"[$1='$2']",/(^|[^a-zA-Z0-9\_\-\*])(#|\.)([a-zA-Z0-9\_\-]+)/g,"$1*$2$3",/([\>\+\|\~\,\s])([a-zA-Z\*]+)/g,"$1//$2",/\s+\/\//g,"//",/([a-zA-Z0-9\_\-\*]+):first-child/g,"*[1]/self::$1",/([a-zA-Z0-9\_\-\*]+):last-child/g,"$1[not(following-sibling::*)]",/([a-zA-Z0-9\_\-\*]+):only-child/g,"*[last()=1]/self::$1",/([a-zA-Z0-9\_\-\*]+):empty/g,"$1[not(*) and not(normalize-space())]",/([a-zA-Z0-9\_\-\*]+):not\(([^\)]*)\)/g,function(f,e,d){return e.concat("[not(",a(d).replace(/^[^\[]+\[([^\]]*)\].*$/g,"$1"),")]")},/([a-zA-Z0-9\_\-\*]+):nth-child\(([^\)]*)\)/g,function(f,e,d){switch(d){case"n":return e;case"even":return"*[position() mod 2=0 and position()>=0]/self::"+e;case"odd":return e+"[(count(preceding-sibling::*) + 1) mod 2=1]";default:d=(d||"0").replace(/^([0-9]*)n.*?([0-9]*)$/,"$1+$2").split("+");d[1]=d[1]||"0";return"*[(position()-".concat(d[1],") mod ",d[0],"=0 and position()>=",d[1],"]/self::",e)}},/:contains\(([^\)]*)\)/g,function(e,d){return"[contains(string(.),'"+d+"')]"},/\[([a-zA-Z0-9\_\-]+)\|=([^\]]+)\]/g,"[@$1=$2 or starts-with(@$1,concat($2,'-'))]",/\[([a-zA-Z0-9\_\-]+)\*=([^\]]+)\]/g,"[contains(@$1,$2)]",/\[([a-zA-Z0-9\_\-]+)~=([^\]]+)\]/g,"[contains(concat(' ',normalize-space(@$1),' '),concat(' ',$2,' '))]",/\[([a-zA-Z0-9\_\-]+)\^=([^\]]+)\]/g,"[starts-with(@$1,$2)]",/\[([a-zA-Z0-9\_\-]+)\$=([^\]]+)\]/g,function(f,e,d){return"[substring(@".concat(e,",string-length(@",e,")-",d.length-3,")=",d,"]")},/\[([a-zA-Z0-9\_\-]+)\!=([^\]]+)\]/g,"[not(@$1) or @$1!=$2]",/#([a-zA-Z0-9\_\-]+)/g,"[@id='$1']",/\.([a-zA-Z0-9\_\-]+)/g,"[contains(concat(' ',normalize-space(@class),' '),' $1 ')]",/\]\[([^\]]+)/g," and ($1)"],c=b.length;return function a(e){var d=0;while(d<c){e=e.replace(b[d++],b[d++])}return"//"+e}})();
// --- ElementCollection
ElementCollection = Collection.extend({
/**
* Initialize with string of _markup_.
*
* @param {string} markup
* @api private
*/
init: function(markup) {
if (typeof markup != 'string')
return this.__super__(markup)
if (!(/<html>/.test(markup)))
markup = '<html><body>' + markup + '</body></html>'
this.document = libxml.parseHtmlString(markup)
this.arr = [this.document.root()]
},
/**
* Return the first element's name.
*
* @return {string}
* @api public
*/
name: function() {
return this.at(0).name()
},
/**
* Search child elements with the given _xpath_.
*
* @param {string} xpath
* @return {ElementCollection}
* @api public
*/
xpath: function(xpath) {
// TODO: refactor with flatten()
return $(this.reduce([], function(array, e){
$(e.find(xpath)).each(function(child){
array.push(child)
})
return array
}))
},
/**
* Search child elements with the given css _selector_
*
* @param {string} selector
* @return {ElementCollection}
* @api public
*/
search: function(selector) {
return this.xpath(css2xpath(selector))
},
/**
* Return collection of children.
*
* @return {ElementCollection}
* @api public
*/
children: function() {
// TODO: refactor with flatten()
return $(this.reduce([], function(array, e){
$(e.children()).each(function(child){
array.push(child)
})
return array
}))
},
/**
* Return collection of parents.
*
* @return {ElementCollection}
* @api public
*/
parents: function() {
return this.map(function(e){
return e.parent()
})
},
/**
* Return the first element's parent.
*
* @return {ElementCollection}
* @api public
*/
parent: function() {
return $([this.at(0).parent()])
},
/**
* Return the prev element.
*
* @return {ElementCollection}
* @api public
*/
prev: function() {
return $([this.at(0).prevSibling()])
},
/**
* Return the next element.
*
* @return {ElementCollection}
* @api public
*/
next: function() {
return $([this.at(0).nextSibling()])
},
/**
* Return the first element's text content.
*
* @return {string}
* @api public
*/
text: function() {
return this.at(0).text()
},
/**
* Convert collection to a string.
*
* @return {string}
* @api public
*/
toString: function() {
if (this.at(0) && this.at(0).doc)
return '[Collection <elements>]'
return this.__super__()
}
})
/**
* Add markup support to $().
*
* @param {object} arr
* @return {Collection, ElementCollection}
* @api public
*/
var $ = exports.$ = function(arr) {
if (arr instanceof Collection) return arr
return new ElementCollection(arr)
}
+1 -1
Ver Arquivo
@@ -13,7 +13,7 @@ exports.Event = Class({
init: function(name, data) {
this.name = name
process.mixin(this, data)
this.merge(data || {})
},
/**
-14
Ver Arquivo
@@ -1,14 +0,0 @@
// Express - Exceptions - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
// --- ExpressError
ExpressError = Class({
name: 'ExpressError',
init: function(message) {
this.message = message
},
toString: function() {
return this.name + ': ' + this.message
}
})
+94
Ver Arquivo
@@ -0,0 +1,94 @@
// Express - HTTP - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
/**
* Module dependencies.
*/
var http = require('http'),
utils = require('express/utils'),
parse = require('url').parse,
queryString = require('querystring')
/**
* Mega super awesome private request utility.
*
* @param {string} method
* @param {string} url
* @param {hash} data
* @param {hash} headers
* @param {function} fn
* @param {number} redirects
* @api private
*/
function request(method, url, data, headers, fn, redirects) {
var buf = '',
redirects = redirects || 3,
url = parse(url),
path = url.pathname || '/',
search = url.search || '',
hash = url.hash || '',
port = url.port || 80,
headers = { host: url.hostname }.merge(headers || {}),
client = http.createClient(port, url.hostname)
if (headers.redirect)
redirects = headers.redirect,
delete headers.redirect
if (data) {
data = queryString.stringify(data)
if (method === 'GET')
search += (search ? '&' : '?') + data
else
headers['content-length'] = data.length,
headers['content-type'] = 'application/x-www-form-urlencoded'
}
var req = client.request(method, path + search + hash, headers)
if (data && method !== 'GET') req.write(data)
req.addListener('response', function(res){
if (req.statusCode < 200 || req.statusCode >= 400)
fn(new Error('request failed with status ' + res.statusCode + ' "' + http.STATUS_CODES[res.statusCode] + '"'))
else if (res.statusCode >= 300 && res.statusCode < 400)
if (--redirects)
request(method, res.headers.location, headers, data, fn, redirects)
else
fn(new Error('maximum number of redirects reached'))
else {
res.setBodyEncoding('utf8')
res
.addListener('data', function(chunk){ buf += chunk })
.addListener('end', function(){ fn(null, buf, res) })
}
})
req.close()
}
/**
* Return HTTP Client function for the given _method_.
*
* @param {string} method
* @return {function}
* @api private
*/
function client(method) {
return function() {
var headers, data,
args = Array.prototype.slice.call(arguments),
url = args.shift(),
fn = args.pop(),
data = args.shift(),
headers = args.shift()
if (typeof fn !== 'function')
throw new TypeError('http client requires a callback function')
return request(method.toUpperCase(), url, data, headers, fn)
}
}
// --- Public API
exports.get = exports.view = client('get')
exports.post = exports.create = client('post')
exports.put = exports.update = client('put')
exports.del = exports.destroy = client('delete')
+2 -2
Ver Arquivo
@@ -5,7 +5,7 @@
* Module dependencies.
*/
var utils = require('express/utils')
var extname = require('path').extname
/**
* Mime type lookup table.
@@ -364,7 +364,7 @@ exports.types = {
exports.type = function(path) {
return exports.types[path] ||
exports.types[utils.extname(path)] ||
exports.types[extname(path).substr(1)] ||
set('default mime type') ||
'application/octet-stream'
}
+6 -6
Ver Arquivo
@@ -13,7 +13,7 @@ var style = require('express/pages/style').style
function stack(e) {
if (e.stack)
return $(e.stack.split('\n').slice(1)).map(function(val, i){
return e.stack.split('\n').slice(1).map(function(val, i){
if (!i)
return '<li>' + val.replace(/^(.*?):/, '<span class="path">$1</span>:') + '</li>'
return '<li>' + val
@@ -32,8 +32,8 @@ function stack(e) {
*/
function hash(hash) {
if (!$(hash).length()) return '<tr><td class="empty" colspan="2">Empty</td></tr>'
return $(hash).map(function(val, key){
if (!hash || !hash.values.length) return '<tr><td class="empty" colspan="2">Empty</td></tr>'
return hash.map(function(val, key){
return '<tr><td>' + key + ':</td><td>' + JSON.encode(val) + '</td></tr>'
}).join('\n')
}
@@ -62,15 +62,15 @@ exports.render = function(request, e) {
</table> \n\
<h3>Params</h3> \n\
<table id="route-params"> \n\
' + hash(request.params) + ' \n\
' + hash(request.params.path) + ' \n\
</table> \n\
<h3>GET</h3> \n\
<table id="get-params"> \n\
' + hash(request.url.params) + ' \n\
' + hash(request.params.get) + ' \n\
</table> \n\
<h3>POST</h3> \n\
<table id="post-params"> \n\
' + hash(request.url.post) + ' \n\
' + hash(request.params.post) + ' \n\
</table> \n\
</div> \n\
</body> \n\
+10 -4
Ver Arquivo
@@ -1,6 +1,12 @@
// Express - Plugin - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
/**
* Module dependencies.
*/
var utils = require('express/utils');
/**
* Push _plugin_ with _options_ to the plugin stack.
* If _plugin_ has already been pushed, then it's options
@@ -14,7 +20,7 @@
exports.use = function(plugin, options) {
if (Express.environment === 'test' && 'init' in plugin)
plugin.init(options)
$(Express.plugins).each(function(other, i){
Express.plugins.each(function(other, i){
if (other.klass === plugin)
delete Express.plugins[i]
})
@@ -37,7 +43,7 @@ exports.Plugin = Class({
init: function(options) {
if (options)
process.mixin(this, options)
utils.mixin(this, options)
},
/**
@@ -47,9 +53,9 @@ exports.Plugin = Class({
* @api private
*/
trigger: function(event) {
trigger: function(event, callback) {
if ('on' in this)
if (event.name in this.on)
this.on[event.name].call(this, event)
return this.on[event.name].call(this, event, callback)
}
})
+8 -9
Ver Arquivo
@@ -1,12 +1,11 @@
// Express - Plugins - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
process.mixin(require('express/plugins/hooks'))
process.mixin(require('express/plugins/flash'))
process.mixin(require('express/plugins/cache'))
process.mixin(require('express/plugins/cookie'))
process.mixin(require('express/plugins/session'))
process.mixin(require('express/plugins/profiler'))
process.mixin(require('express/plugins/common-logger'))
process.mixin(require('express/plugins/content-length'))
process.mixin(require('express/plugins/method-override'))
global.merge(require('express/plugins/hooks'))
global.merge(require('express/plugins/flash'))
global.merge(require('express/plugins/cache'))
global.merge(require('express/plugins/cookie'))
global.merge(require('express/plugins/session'))
global.merge(require('express/plugins/logger'))
global.merge(require('express/plugins/content-length'))
global.merge(require('express/plugins/method-override'))
+7 -1
Ver Arquivo
@@ -1,8 +1,14 @@
// Express - BodyDecoder - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
/**
* Module dependencies.
*/
var queryString = require('querystring')
// --- BodyDecoder
exports.BodyDecoder = Plugin.extend({
on: {
@@ -15,7 +21,7 @@ exports.BodyDecoder = Plugin.extend({
request: function(event) {
var request = event.request
if (request.header('content-type') &&
request.header('content-type').indexOf('application/x-www-form-urlencoded') > -1)
request.header('content-type').includes('application/x-www-form-urlencoded'))
request.params.post = queryString.parseQuery(request.body)
}
}
+8 -6
Ver Arquivo
@@ -30,7 +30,8 @@ exports.Store = Class({
*/
set: function(key, val) {
if (typeof key !== 'string') throw new Error(this.name + ' store #set() key must be a string')
if (typeof key !== 'string')
throw new Error(this.name + ' store #set() key must be a string')
},
/**
@@ -42,7 +43,8 @@ exports.Store = Class({
*/
get: function(key) {
if (typeof key !== 'string') throw new Error(this.name + 'store #get() key must be a string')
if (typeof key !== 'string')
throw new Error(this.name + 'store #get() key must be a string')
},
/**
@@ -114,11 +116,11 @@ exports.Store.Memory = exports.Store.extend({
this.data[key].val :
null
var regexp = this.normalize(key)
return $(this.data).reduce({}, function(vals, cache){
return this.data.reduce(function(vals, cache){
if (regexp.test(cache.key))
vals[cache.key] = cache.val
return vals
})
}, {})
},
/**
@@ -153,7 +155,7 @@ exports.Store.Memory = exports.Store.extend({
reap: function(ms) {
var self = this,
threshold = Number(new Date(Number(new Date) - ms))
$(this.data).each(function(cache){
this.data.each(function(cache){
if (cache.created < threshold)
self.clear(cache.key)
})
@@ -194,7 +196,7 @@ exports.Cache = Plugin.extend({
*/
init: function(options) {
process.mixin(this, options)
this.merge(options || {})
this.store = new (this.dataStore || exports.Store.Memory)(options)
Request.include({ cache: this.store })
this.startReaper()
-50
Ver Arquivo
@@ -1,50 +0,0 @@
// Express - CommonLogger - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
/**
* Months.
*/
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
/**
* Format _date_.
*
* @param {Date} date
* @return {string}
* @api private
*/
function format(date) {
var d = date.getDate(),
m = months[date.getMonth()],
y = date.getFullYear(),
h = date.getHours(),
mi = date.getMinutes(),
s = date.getSeconds()
return (d < 10 ? '0' : '') + d + '/' + m + '/' + y + ' ' +
(h < 10 ? '0' : '') + h + ':' + (mi < 10 ? '0' : '') +
mi + ':' + (s < 10 ? '0' : '') + s
}
// --- CommonLogger
exports.CommonLogger = Plugin.extend({
on: {
/**
* Output log data.
*/
response: function(event) {
puts([event.request.headers.host,
'-',
'-',
'[' + format(new Date) + ']',
'"' + event.request.method.toUpperCase() + ' ' + (event.request.url.pathname || '/') +
' HTTP/' + event.request.httpVersion + '"',
event.request.response.status,
event.request.response.headers['content-length'] || 0].join(' '))
}
}
})
+7 -7
Ver Arquivo
@@ -10,11 +10,11 @@
*/
exports.parseCookie = function(cookie) {
return $(cookie.replace(/^ *| *$/g, '').split(/ *; */)).reduce({}, function(hash, pair){
return cookie.replace(/^ *| *$/g, '').split(/ *; */).reduce(function(hash, pair){
var parts = pair.split(/ *= */)
hash[parts[0]] = parts[1]
return hash
})
}, {})
}
/**
@@ -29,14 +29,14 @@ exports.parseCookie = function(cookie) {
exports.compileCookie = function(name, val, options) {
if (!options) return name + '=' + val
return name + '=' + val + '; ' + $(options).map(function(val, key){
return name + '=' + val + '; ' + options.map(function(val, key){
if (val instanceof Date)
val = val.toString()
.replace(/^(\w+)/, '$1,')
.replace(/(\w+) (\d+) (\d+)/, '$2-$1-$3')
.replace(/GMT.*$/, 'GMT')
return val === true ? key : key + '=' + val
}).toArray().join('; ')
}).join('; ')
}
// --- Cookie
@@ -93,9 +93,9 @@ exports.Cookie = Plugin.extend({
request: function(event) {
event.request.response.cookies = []
event.request.cookies = event.request.headers.cookie ?
exports.parseCookie(event.request.headers.cookie) :
{}
event.request.cookies = event.request.headers.cookie
? exports.parseCookie(event.request.headers.cookie)
: {}
},
/**
+10 -4
Ver Arquivo
@@ -1,6 +1,10 @@
// Express - Hooks - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
/**
* Callbacks.
*/
exports.callbacks = { before: [], after: [] }
/**
@@ -35,8 +39,10 @@ exports.Hooks = Plugin.extend({
*/
init: function() {
process.mixin(GLOBAL, { before: exports.before,
after: exports.after })
global.merge({
before: exports.before,
after: exports.after
})
}
},
@@ -49,7 +55,7 @@ exports.Hooks = Plugin.extend({
*/
request: function(event) {
$(exports.callbacks.before).each(function(fn){
exports.callbacks.before.each(function(fn){
fn.call(event.request, event.request)
})
},
@@ -59,7 +65,7 @@ exports.Hooks = Plugin.extend({
*/
response: function(event) {
$(exports.callbacks.after).each(function(fn){
exports.callbacks.after.each(function(fn){
fn.call(event.request, event.request)
})
}
+80
Ver Arquivo
@@ -0,0 +1,80 @@
// Express - Logger - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
/**
* Module dependencies.
*/
var sys = require('sys')
/**
* Log formats
*/
var formats = {
common: function(event, start) {
printf('%s - - [%s] "%s %s HTTP/%d" %s %d %0.3f',
event.request.connection.remoteAddress,
(new Date).format('%d/%b/%Y %H:%M:%S'),
event.request.method.uppercase,
event.request.url.pathname || '/',
event.request.httpVersion,
event.request.response.status,
event.request.response.headers['content-length'] || 0,
(Number(new Date) - start) / 1000)
},
combined: function(event, start) {
formats.common(event, start)
printf('"%s" "%s"',
event.request.headers['referrer'] || event.request.headers['referer'] || '-',
event.request.headers['user-agent'])
},
plot: function(event, start) {
sys.print(Number(new Date) - start)
}
}
// --- Logger
exports.Logger = Plugin.extend({
extend: {
/**
* Initialize logger options.
*
* Options:
*
* - format
* 'common' outputs log in CommonLog format (DEFAULT)
* 'combined' outputs log in Apache Combined format
* 'plot' outputs request duration in milliseconds only
*
* @param {hash} options
* @api private
*/
init: function(options) {
this.merge(options || {})
}
},
on: {
/**
* Start timer.
*/
request: function(event) {
this.start = Number(new Date)
},
/**
* Output log data.
*/
response: function(event) {
formats[exports.Logger.format || 'common'](event, this.start)
sys.print('\n')
}
}
})
-51
Ver Arquivo
@@ -1,51 +0,0 @@
// Express - Profiler - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
var n = 0
exports.Profiler = Plugin.extend({
extend: {
/**
* Initialize profiler options.
*
* Options:
*
* - format 'plot' outputs request duration in milliseconds only
*
* @param {hash} options
* @api private
*/
init: function(options) {
process.mixin(this, options)
}
},
// --- Events
on: {
/**
* Start timer.
*/
request: function(event) {
this.start = Number(new Date)
},
/**
* Output duration.
*/
response: function(event) {
if (exports.Profiler.format === 'plot')
puts(Number(new Date) - this.start)
else
puts(event.request.method + ' ' +
event.request.url.pathname + ': ' +
(Number(new Date) - this.start) + ' ms' +
' #' + ++n)
}
}
})
+1 -1
Ver Arquivo
@@ -32,7 +32,7 @@ exports.Redirect = Plugin.extend({
*/
redirect: function(url, code) {
if (url == 'back' || url == 'home') url = this[url]
if (url === 'back' || url === 'home') url = this[url]
this.header('location', url)
this.halt(code || 303)
}
+6 -7
Ver Arquivo
@@ -118,7 +118,7 @@ exports.Store.Memory = exports.Store.extend({
*/
length: function() {
return $(this.store).length()
return this.store.values.length
},
/**
@@ -129,12 +129,11 @@ exports.Store.Memory = exports.Store.extend({
*/
reap: function(ms) {
var self = this,
threshold = Number(new Date(Number(new Date) - ms))
$(this.store).each(function(session, sid){
var threshold = Number(new Date(Number(new Date) - ms))
this.store.each(function(session, sid){
if (session.lastAccess < threshold)
self.destroy(sid)
})
this.destroy(sid)
}, this)
}
})
@@ -157,7 +156,7 @@ exports.Session = Plugin.extend({
*/
init: function(options) {
process.mixin(this, options)
this.merge(options || {})
this.store = new (this.dataStore || exports.Store.Memory)(options)
this.startReaper()
},
+16 -18
Ver Arquivo
@@ -5,18 +5,15 @@
* Module dependencies.
*/
var posix = require('posix'),
utils = require('express/utils')
var utils = require('express/utils'),
extname = require('path').extname,
fs = require('fs')
/**
* Supported template engines.
* Cache supported template engine exports.
*/
var engine = {
ejs: require('ejs'),
haml: require('haml'),
sass: require('sass')
}
var engines = {}
// --- View
@@ -52,8 +49,9 @@ exports.View = Plugin.extend({
* Options:
*
* - layout: The layout to use, none when falsey. Defaults to 'layout'
* - context: Most engines support an evaluation context (the 'this' keyword)
* - locals: Most engines support a hash of local variable names / values.
* - context: Most engines support an evaluation context (the 'this' keyword).
* Defaults to the current Request instance.
*
* @param {string} view
* @param {hash} options
@@ -66,13 +64,14 @@ exports.View = Plugin.extend({
options = options || {},
path = set('views') + '/' + view,
type = path.split('.').slice(-2)[0],
ext = utils.extname(path),
ext = extname(path),
layout = options.layout === undefined ? 'layout' : options.layout
options.context = options.context || this
self.contentType(ext)
function render(content) {
content = engine[type].render(content, options)
content = (engines[type] = engines[type] || require(type)).render(content, options)
if (layout)
self.render(layout + '.' + type + '.' + ext, process.mixin(true, options, {
self.render(layout + '.' + type + ext, utils.mixin(true, options, {
layout: false,
locals: {
body: content
@@ -84,12 +83,11 @@ exports.View = Plugin.extend({
if (set('cache view contents') && self.cache.get(path))
render(self.cache.get(path))
else
posix.cat(path).addCallback(function(content){
set('cache view contents') ?
render(self.cache.set(path, content)) :
render(content)
}).addErrback(function(e){
throw e
fs.readFile(path, function(e, content){
if (e) throw e
set('cache view contents')
? render(self.cache.set(path, content))
: render(content)
})
}
})
+69 -56
Ver Arquivo
@@ -9,26 +9,9 @@ var StaticFile = require('express/static').File,
statusBodies = require('http').STATUS_CODES,
queryString = require('querystring'),
mime = require('express/mime'),
utils = require('express/utils'),
url = require('url')
// --- InvalidStatusCode
InvalidStatusCode = ExpressError.extend({
name: 'InvalidStatusCode',
init: function(status) {
this.message = status + ' is an invalid HTTP response code'
}
})
// --- InvalidResponseBody
InvalidResponseBody = ExpressError.extend({
name: 'InvalidResponseBody',
init: function(request) {
this.message = request.method + ' ' + JSON.encode(request.url.pathname) + ' did not respond with a body string'
}
})
// --- Helpers
/**
@@ -63,7 +46,7 @@ exports.Request = Class({
*/
init: function(request, response) {
process.mixin(true, this, request)
utils.mixin(true, this, request)
response.headers = {}
this.response = response
this.url = url.parse(this.url)
@@ -72,7 +55,7 @@ exports.Request = Class({
this.params.path = {}
this.params.get = this.url.query ? queryString.parseQuery(this.url.query) : {}
this.params.post = this.params.post || {}
this.plugins = $(Express.plugins).map(function(plugin){
this.plugins = Express.plugins.map(function(plugin){
return new plugin.klass(plugin.options)
})
},
@@ -88,9 +71,9 @@ exports.Request = Class({
*/
header: function(key, val) {
return val === undefined ?
this.headers[key.toLowerCase()] :
this.response.headers[key.toLowerCase()] = val
return val === undefined
? this.headers[key.toLowerCase()]
: this.response.headers[key.toLowerCase()] = val
},
/**
@@ -132,13 +115,13 @@ exports.Request = Class({
accepts: function() {
var accept = this.header('accept')
return accept ?
$(arguments).any(function(path){
var type = mime.type(path)
return accept.indexOf(type) !== -1 ||
accept.indexOf(type.split('/')[0]+'/*') !== -1
}) :
true
return accept
? arguments.any(function(path){
var type = mime.type(path)
return accept.indexOf(type) !== -1 ||
accept.indexOf(type.split('/')[0]+'/*') !== -1
})
: true
},
/**
@@ -160,9 +143,6 @@ exports.Request = Class({
* default to the default body associated with the response
* _code_.
*
* When an invalid status _code_ is passed, InvalidStatusCode
* will be thrown.
*
* @param {int} code
* @param {string} body
* @param {string} encoding
@@ -170,11 +150,10 @@ exports.Request = Class({
* @api public
*/
halt: function(code, body, encoding) {
halt: function(code, body, encoding, callback) {
this.status(code = code || 404)
if (body = body || statusBodies[code])
return this.respond(body, encoding)
throw new InvalidStatusCode(code)
return this.respond(body, encoding, callback)
},
/**
@@ -186,14 +165,33 @@ exports.Request = Class({
* @api private
*/
respond: function(body, encoding) {
respond: function(body, encoding, callback) {
var self = this
this.response.body = body
this.trigger('response')
if (typeof this.response.body != 'string') throw new InvalidResponseBody(this)
if (typeof this.response.status != 'number') throw new InvalidStatusCode(this.response.status)
this.response.sendHeader(this.response.status, this.response.headers)
this.response.sendBody(this.response.body, encoding)
this.response.finish()
this.trigger('response', function(e) {
if (e)
if (callback !== undefined) callback(e)
else throw e
self.response.writeHeader(self.response.status, self.response.headers)
self.response.write(self.response.body, encoding)
self.response.close()
});
},
/**
* Pass control to the next matching route, or
* the given _path_.
*
* NOTE: _path_ may be the request pathname only,
* and may not contain a query string etc.
*
* @param {string} path
* @api public
*/
pass: function(path) {
this.passed = path || true
return this
},
/**
@@ -211,22 +209,37 @@ exports.Request = Class({
},
/**
* Trigger even _name_ with optional _data_.
* Trigger event _name_ with optional _data_ and _callback_ function.
* The _callback_ function may be the second or third argument.
*
* @param {string} name
* @param {hash} data
* @param {object} data
* @param {function} callback
* @return {Request}
* @api public
*/
trigger: function(name, data) {
data = process.mixin(data || {}, {
request: this,
response: this.response
})
this.plugins.each(function(plugin){
plugin.trigger(new Event(name, data))
})
trigger: function(name, data, callback) {
if (data instanceof Function)
callback = data,
data = null
data = data || {}
data.merge({ request: this, response: this.response })
var self = this,
complete = 0,
total = this.plugins.length
;(function next(e) {
if (e || complete === total)
callback(e)
else {
try {
if (self.plugins.at(complete++).trigger(new Event(name, data), next) !== true)
next()
} catch(e) {
next(e)
}
}
})()
return this
},
@@ -253,9 +266,9 @@ exports.Request = Class({
*/
attachment: function(path) {
this.header('content-disposition', path ?
'attachment; filename="' + path + '"' :
'attachment')
this.header('content-disposition', path
? 'attachment; filename="' + path + '"'
: 'attachment')
return this
},
+10 -4
Ver Arquivo
@@ -1,6 +1,12 @@
// Express - MockRequest - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
/**
* Module dependencies.
*/
var utils = require('express/utils')
// --- MockRequest
var MockRequest = Class({
@@ -33,7 +39,7 @@ var MockRequest = Class({
'accept-language': 'en-us',
'connection': 'keep-alive'
}
process.mixin(true, this, options)
utils.mixin(true, this, options)
}
})
@@ -45,7 +51,7 @@ var MockResponse = Class({
* Store _code_ and _headers_.
*/
sendHeader: function(code, headers) {
writeHeader: function(code, headers) {
this.status = code
this.headers = headers
},
@@ -54,7 +60,7 @@ var MockResponse = Class({
* Store _body_.
*/
sendBody: function(body) {
write: function(body) {
this.body = body
},
@@ -62,7 +68,7 @@ var MockResponse = Class({
* Flag response as finished.
*/
finish: function() {
close: function() {
this.finished = true
}
})
+12 -14
Ver Arquivo
@@ -1,18 +1,13 @@
// Express - Static - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
var path = require('path'),
posix = require('posix')
// --- InvalidPathError
/**
* Module dependencies.
*/
InvalidPathError = ExpressError.extend({
name: 'InvalidPathError',
init: function(path) {
this.message = "`" + path + "' is not a valid path"
}
})
var path = require('path'),
fs = require('fs')
// --- File
exports.File = Class({
@@ -26,7 +21,8 @@ exports.File = Class({
init: function(path) {
this.path = path
if (path.indexOf('..') != -1) throw new InvalidPathError(path)
if (path.indexOf('..') != -1)
Error.raise('InvalidPathError', "`" + path + "' is not a valid path")
},
/**
@@ -49,9 +45,11 @@ exports.File = Class({
request.halt(200, cache.content, 'binary')
path.exists(file, function(exists){
if (!exists) return request.halt()
posix.stat(file).addCallback(function(stats){
fs.stat(file, function(e, stats){
if (e) throw e
if (!stats.isFile()) return request.halt()
posix.cat(file, 'binary').addCallback(function(content){
fs.readFile(file, 'binary', function(e, content){
if (e) throw e
request.contentType(file)
if (set('cache static files'))
request.cache.set(file, { type: file, content: content })
+82 -65
Ver Arquivo
@@ -28,32 +28,6 @@ exports.uid = function() {
return uid
}
/**
* Return the extension name of the given _path_,
* or null when not present.
*
* @param {string} path
* @return {string}
* @api public
*/
exports.extname = function(path) {
if (path.lastIndexOf('.') < 0) return
return path.slice(path.lastIndexOf('.') + 1)
}
/**
* Return the basename of the given _path_.
*
* @param {string} path
* @return {string}
* @api public
*/
exports.basename = function(path) {
return path.split('/').slice(-1)[0]
}
/**
* Escape special characters in _html_.
*
@@ -63,45 +37,13 @@ exports.basename = function(path) {
*/
exports.escape = function(html) {
return html.toString()
return String(html)
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
}
/**
* Convert native array-like objects into an
* array with optional _offset_.
*
* @param {object} arr
* @param {int} offset
* @return {array}
* @api public
*/
exports.toArray = function(arr, offset) {
return Array.prototype.slice.call(arr, offset)
}
/**
* Escape RegExp _chars_ in _string_. Where _chars_
* defaults to regular expression special characters.
*
* _chars_ should be a space delimited list of characters,
* for example '[ ] ( )'.
*
* @param {string} string
* @param {string} chars
* @return {Type}
* @api public
*/
exports.escapeRegexp = function(string, chars) {
var specials = (chars || '/ . * + ? | ( ) [ ] { } \\').split(' ').join('|\\')
return string.replace(new RegExp('(\\' + specials + ')', 'g'), '\\$1')
}
/**
* Merge param _key_ and _val_ into _params_. Key
* should be a query string key such as 'user[name]',
@@ -118,17 +60,92 @@ exports.mergeParam = function(key, val, params) {
var orig = params,
keys = key.trim().match(/\w+/g),
array = /\[\]$/.test(key)
$(keys).reduce(queryString.parseQuery(key), function(parts, key, i){
keys.reduce(function(parts, key, i){
if (i === keys.length - 1)
if (key in params)
params[key] instanceof Array ?
params[key].push(val) :
params[key] = [params[key], val]
params[key] instanceof Array
? params[key].push(val)
: params[key] = [params[key], val]
else
params[key] = array ? [val] : val
if (!(key in params)) params[key] = {}
params = params[key]
return parts[key]
})
}, queryString.parseQuery(key))
return orig
}
}
/**
* Return a clone of _obj_.
*
* @param {mixed} obj
* @return {mixed}
* @api public
*/
function Clone() {}
exports.clone = function(obj) {
Clone.prototype = obj
return new Clone
}
// From jQuery.extend in the jQuery JavaScript Library v1.3.2
// Copyright (c) 2009 John Resig
// Dual licensed under the MIT and GPL licenses.
// http://docs.jquery.com/License
// Modified for node.js (formely for copying properties correctly)
exports.mixin = function() {
// copy reference to target object
var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, source;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !(typeof target === 'function') )
target = {};
// mixin process itself if only one argument is passed
if ( length == i ) {
target = GLOBAL;
--i;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (source = arguments[i]) != null ) {
// Extend the base object
Object.getOwnPropertyNames(source).forEach(function(k){
var d = Object.getOwnPropertyDescriptor(source, k) || {value: source[k]};
if (d.get) {
target.__defineGetter__(k, d.get);
if (d.set) {
target.__defineSetter__(k, d.set);
}
}
else {
// Prevent never-ending loop
if (target !== d.value) {
if (deep && d.value && typeof d.value === "object") {
target[k] = exports.mixin(deep,
// Never move original objects, clone them
target[k] || (d.value.length != null ? [] : {})
, d.value);
}
else {
target[k] = d.value;
}
}
}
});
}
}
// Return the modified object
return target;
};
-53
Ver Arquivo
@@ -1,53 +0,0 @@
/* Ejs template parser for CommonJS
*
* Copyright (c) 2009, Howard Rauscher
* Licensed under the MIT License
*
* base on:
* Simple JavaScript Templating (http://ejohn.org/blog/javascript-micro-templating/)
* John Resig - http://ejohn.org/ - MIT Licensed
*/
(function(){
var cache = {};
var ejs = this.ejs = {};
ejs.parse = function tmpl(str, options) {
options = options || {};
options.context = options.context || {};
options.locals = options.locals || {};
// Figure out if we're getting a template, or if we need to
// load the template - and be sure to cache the result.
var fn = cache[str] ||
// Generate a reusable function that will serve as a template
// generator (and which will be cached).
new Function("obj",
"var p=[];" +
// Introduce the data as local variables using with(){}
"with(obj){p.push('" +
// Convert the template into pure JavaScript
str
.replace(/\-%>(\n|\r)/g, "%>")
.replace(/[\t\b\f]/g, " ")
.replace(/[\n\r]/g, "\f")
.split("<%").join("\t")
.replace(/((^|%>)[^\t]*)'/g, "$1\r")
.replace(/\t=(.*?)%>/g, "',$1,'")
.split("\t").join("');")
.split("%>").join("p.push('")
.split("\r").join("\\'").replace(/\f+/g, '\\n') +
"');}return p.join('');");
cache[str] = fn;
// Provide some basic currying to the user
return fn.call(options.context, options.locals);
};
})();
exports.render = ejs.parse;
+9
Ver Arquivo
@@ -0,0 +1,9 @@
---
name: Express
description: Sinatra inspired web development framework
version: 0.7.0
dependencies:
- ext >= 0.2.2
- oo >= 1.2.0
- sass >= 0.3.0
- haml >= 0.1.2
+4 -25
Ver Arquivo
@@ -1,21 +1,12 @@
require.paths.unshift('spec', 'lib', 'spec/lib', 'spec/support/libxmljs')
require.paths.unshift('spec', 'lib', 'spec/lib')
require("jspec")
require("express")
require("express/spec")
quit = process.exit
print = puts
readFile = function(path) {
var result
require('posix')
.cat(path, "utf8")
.addCallback(function(contents){ result = contents })
.addErrback(function(){ throw new Error("failed to read file `" + path + "'") })
.wait()
return result
}
quit = process.exit
readFile = require('fs').readFileSync
function run(specs) {
specs.forEach(function(spec){
@@ -31,11 +22,9 @@ specs = {
'request',
'mime',
'static',
'collection',
'plugins',
'plugins.cache',
'plugins.view',
'plugins.common-logger',
'plugins.content-length',
'plugins.method-override',
'plugins.body-decoder',
@@ -44,22 +33,12 @@ specs = {
'plugins.cookie',
'plugins.session',
'plugins.flash',
],
dependant: [
'element-collection'
]
]
}
switch (process.ARGV[2]) {
case 'independant':
run(specs.independant)
break
case 'dependant':
run(specs.dependant)
break
case 'all':
run(specs.independant)
run(specs.dependant)
break
default:
run([process.ARGV[2]])
-472
Ver Arquivo
@@ -1,472 +0,0 @@
process.mixin(require('express/collection'))
describe 'Express'
describe 'Collection'
describe '$(array)'
it 'should return a Collection'
$(['foo', 'bar']).should.be_an_instance_of Collection
end
end
describe '$(object)'
it 'should return a Collection'
$({ foo: 'bar' }).should.be_an_instance_of Collection
end
end
describe '$(Collection)'
it 'should return the collection passed'
var collection = $(['foo'])
$(collection).should.equal collection
end
end
describe 'shorthand expressions'
describe 'with 3 or less chars'
it 'should be considered binary operator between a / b'
$(5..1).sort('-').toArray().should.eql 1..5
$(5..1).reduce(0, '+').should.eql 15
end
end
describe 'with over 3 chars'
it 'should be considered a return expression'
$(5..1).sort('a - b').toArray().should.eql 1..5
$(5..1).reduce(0, 'a + b').should.eql 15
end
it 'should consider a single word a property on a'
$(['foo', 'foobar']).map('length').toArray().should.eql [3, 6]
end
it 'should consider a single function a method on a'
$(['foo', 'foobar']).map('charAt(0)').toArray().should.eql ['f', 'f']
end
end
end
describe '#at()'
it 'should return the value at the given index'
$(['foo', 'bar']).at(0).should.eql 'foo'
$(['foo', 'bar']).at(1).should.eql 'bar'
$(['foo', 'bar']).at(2).should.be_null
end
it 'should work with objects'
$({ foo: 'bar', baz: 'raz' }).at(0).should.eql 'bar'
$({ foo: 'bar', baz: 'raz' }).at(1).should.eql 'raz'
$({ foo: 'bar', baz: 'raz' }).at(2).should.be_null
end
end
describe '#each()'
it 'should iterate passing index and value'
var result = []
$(['foo', 'bar']).each(function(val, i){
result.push(i, val)
})
result.should.eql [0, 'foo', 1, 'bar']
end
it 'should work with objects'
var result = []
$({ foo: 'bar', baz: 'raz' }).each(function(val, key){
result.push(key, val)
})
result.should.eql ['foo', 'bar', 'baz', 'raz']
end
it 'should return the collection'
$([]).each(function(){}).should.be_an_instance_of Collection
end
end
describe '#reduce()'
it 'should iterate with memo object'
var sum = $([1,2,3]).reduce(0, function(sum, n){ return sum + n })
sum.should.eql 6
end
it 'should allow shorthand expressions'
$([1,2,3]).reduce(0, '+').should.eql 6
$([1,2,3]).reduce(0, 'a + b').should.eql 6
end
end
describe '#map()'
it 'should iterate collecting results into a new collection'
var collection = $(['foo', 'bar']).map(function(val){ return val.toUpperCase() })
collection.at(0).should.eql 'FOO'
collection.at(1).should.eql 'BAR'
end
it 'should work with objects'
var collection = $({ foo: 'bar', baz: 'raz' }).map(function(val){ return val.toUpperCase() })
collection.at(0).should.eql 'BAR'
collection.at(1).should.eql 'RAZ'
end
it 'should allow shorthand expressions'
$(['foo', 'bar']).map('a.toUpperCase()').toArray().should.eql ['FOO', 'BAR']
end
end
describe '#first()'
it 'should return the first value'
$(['foo']).first().should.eql 'foo'
end
it 'should return the first n values'
$([5,4,3,2,1]).first(2).at(0).should.eql 5
$([5,4,3,2,1]).first(2).at(1).should.eql 4
end
it 'should work with objects'
$({ foo: 'bar' }).first().should.eql 'bar'
end
end
describe '#last()'
it 'should return the last value'
$(['foo', 'bar']).last().should.eql 'bar'
end
it 'should return the last n values'
$([5,4,3,2,1]).last(2).at(0).should.eql 2
$([5,4,3,2,1]).last(2).at(1).should.eql 1
end
it 'should work with objects'
$({ a: 'foo', b: 'bar' }).last(2).at(0).should.eql 'foo'
$({ a: 'foo', b: 'bar' }).last(2).at(1).should.eql 'bar'
$({ a: 'foo', b: 'bar' }).last().should.eql 'bar'
end
end
describe '#drop()'
it 'should drop the first n values'
$(1..5).drop(2).arr.should.eql 3..5
end
end
describe '#find()'
it 'should return the value of the first match'
var result = $(['foo', 'bar']).find(function(val){ return val.charAt(0) == 'b' })
result.should.eql 'bar'
end
it 'should return null when nothing matches'
var result = $(['foo', 'bar']).find(function(val){ return val.charAt(0) == 'a' })
result.should.be_null
end
it 'should work with objects'
var result = $({ foo: 'bar', baz: 'raz' }).find(function(val, key){
return val.charAt(0) == 'r'
})
result.should.eql 'raz'
end
it 'should allow shorthand expressions'
$(['foo', 'bar']).find("a.charAt(0) == 'b'").should.eql 'bar'
end
end
describe '#all()'
it 'should return true when all evaluate to true'
$(['foo', 'foobar']).all(function(val){ return val.charAt(0) == 'f' }).should.be_true
end
it 'should return false when any evaluate to false'
$(['foo', 'bar', 'foobar']).all(function(val){ return val.charAt(0) == 'f' }).should.be_false
end
it 'should work with objects'
$({ a: 'foo', b: 'foobar' }).all(function(val){ return val.charAt(0) == 'f' }).should.be_true
end
it 'should allow shorthand expressions'
$(['foo', 'bar']).all('a.length > 2').should.be_true
end
end
describe '#any()'
it 'should return true when found'
$(['foo', 'bar']).any(function(val){ return val.charAt(0) == 'b' }).should.be_true
end
it 'should return false when not found'
$(['foo', 'bar']).any(function(val){ return val.charAt(0) == 'r' }).should.be_false
end
it 'should work with objects'
$({ foo: 'bar' }).any(function(val){ return val.charAt(0) == 'b' }).should.be_true
$({ foo: 'bar' }).any(function(val){ return val.charAt(0) == 'c' }).should.be_false
end
it 'should allow shorthand expressions'
$(['foo', 'bar']).any('a.length > 2').should.be_true
end
end
describe '#select()'
it 'should return values which evaluate to true'
var result = $([1,2,3,4,5]).select(function(n){ return n % 2 })
result.at(0).should.eql 1
result.at(1).should.eql 3
result.at(2).should.eql 5
end
it 'should return a Collection'
var result = $([1,2,3,4,5]).select(function(n){ return n % 2 })
result.should.be_an_instance_of Collection
end
it 'should allow shorthand expressions'
$([1,2,3,4,5]).select('a % 2').toArray().should.eql [1,3,5]
end
end
describe '#reject()'
it 'should return values which evaluate to false'
var result = $([1,2,3,4,5,6]).reject(function(n){ return n % 2 })
result.at(0).should.eql 2
result.at(1).should.eql 4
result.at(2).should.eql 6
end
it 'should return a Collection'
var result = $([1,2,3,4,5]).reject(function(n){ return n % 2 })
result.should.be_an_instance_of Collection
end
it 'should allow shorthand expressions'
$(['foo', 'bar']).reject('a.charAt(0) == "b"').toArray().should.eql ['foo']
end
end
describe '#slice()'
it 'should return a slice of values'
var collection = $(['foo', 'bar', 'baz']).slice(1, 3)
collection.at(0).should.eql 'bar'
collection.at(1).should.eql 'baz'
end
it 'should work with objects'
var collection = $({ foo: 1, bar: 2, baz: 3, raz: 4 }).slice(1, 3)
collection.at(0).should.eql 2
collection.at(1).should.eql 3
end
end
describe '#grep()'
it 'should select values matching the regular expression passed'
var result = $(['foo', 'bar', 'foobar', 'baz']).grep(/foo(bar)?/)
result.at(0).should.eql 'foo'
result.at(1).should.eql 'foobar'
result.at(2).should.be_null
end
end
describe '#keys()'
it 'should return indices when array-like'
$(['foo', 'bar']).keys().at(0).should.eql '0'
$(['foo', 'bar']).keys().at(1).should.eql '1'
end
it 'should return keys when an object'
$({ foo: 'bar', baz: 'raz' }).keys().at(0).should.eql 'foo'
$({ foo: 'bar', baz: 'raz' }).keys().at(1).should.eql 'baz'
end
end
describe '#toArray()'
it 'should return an array'
$(['foo', 'bar']).keys().toArray().should.eql ['0', '1']
end
it 'should work on nested collections'
$([$(['foo']), $(['bar'])]).toArray().should.eql [['foo'], ['bar']]
end
it 'should work with objects'
$({ foo: 'bar', baz: { name: 'wahoo' }}).toArray().should.eql ['bar', { name: 'wahoo' }]
end
end
describe '#min()'
it 'should return the min value'
$([4,5,2,3,62]).min().should.eql 2
end
end
describe '#max()'
it 'should return the max value'
$([3,5,2,3,43,2]).max().should.eql 43
end
end
describe '#length()'
it 'should work with arrays'
$([1,2,3]).length().should.eql 3
end
it 'should work with objects'
$({ a: 'b', c: 'd', e: 'f' }).length().should.eql 3
end
end
describe '#chunk()'
it 'should group into chunks of the given size'
$([1,1,2,2,3,3]).chunk(2).toArray().should.eql [[1,1],[2,2],[3,3]]
$([1,1,2,2,3,3]).chunk(4).toArray().should.eql [[1,1,2,2],[3,3]]
end
end
describe '#sum()'
it 'should return the sum of the numeric values'
$([1,2,3]).sum().should.eql 6
end
end
describe '#avg()'
it 'should return the average of numeric values'
$([3,1]).avg().should.eql 2
end
end
describe '#merge()'
it 'should merge two array collections'
var a = $([1,2,3])
var b = $([4,5,6])
a.merge(b).toArray().should.eql [1,2,3,4,5,6]
var a = $([1,2,3])
var b = [4,5,6]
a.merge(b).toArray().should.eql [1,2,3,4,5,6]
end
it 'should merge two object collections'
var a = $({ a: 'b' })
var b = $({ c: 'd' })
a.merge(b).arr.should.eql { a: 'b', c: 'd' }
var a = $({ a: 'b' })
var b = { c: 'd' }
a.merge(b).arr.should.eql { a: 'b', c: 'd' }
end
it 'should merge an array and object collection'
var a = $([1,2])
var b = $({ a: 'b', c: 'd' })
a.merge(b).arr.should.eql [1, 2, 'b', 'd']
var a = $([1,2])
var b = { a: 'b', c: 'd' }
a.merge(b).arr.should.eql [1, 2, 'b', 'd']
end
it 'should merge an object and array collection'
var a = $({ a: 'b', c: 'd' })
var b = $([1,2])
a.merge(b).arr.should.eql { a: 'b', c: 'd', 0: 1, 1: 2 }
var a = $({ a: 'b', c: 'd' })
var b = [1,2]
a.merge(b).arr.should.eql { a: 'b', c: 'd', 0: 1, 1: 2 }
end
end
describe '#clone()'
it 'should clone an array collection'
var a = $([1,2,3])
var b = a.clone()
a.should.not.equal b
b.arr.should.eql [1,2,3]
end
it 'should clone an object collection'
var a = $({ foo: 'bar' })
var b = a.clone()
a.should.not.equal b
b.arr.should.eql { foo: 'bar' }
end
end
describe '#sample()'
it 'should return a random value'
Math.stub('random').and_return(0.1)
$([1,2,3,4]).sample().should.eql 1
end
end
describe '#reverse()'
it 'should reverse a collection'
$([1,2,3]).reverse().toArray().should.eql [3,2,1]
end
end
describe '#sort()'
it 'should sort a collection'
$([3,1,2]).sort().toArray().should.eql [1,2,3]
end
it 'should sort with a function'
$([3,1,2]).sort(function(a, b){ return b - a }).toArray().should.eql [3,2,1]
end
it 'should allow shorthand expressions'
$([3,1,2]).sort('-').toArray().should.eql [1,2,3]
end
end
describe '#join()'
it 'should join a collection with "" by default'
$([1,2,3]).join().should.eql '123'
end
it 'should join with an arbitrary string'
$([1,2,3]).join(' ').should.eql '1 2 3'
end
it 'should work with objects'
$({ foo: 'bar', baz: 'raz' }).join(' ').should.eql 'bar raz'
end
end
describe '#includes()'
it 'should return true when the value is present'
$([1,2,3]).includes(2).should.be_true
end
it 'should return true when all values are present'
$([1,2,3]).includes(2, 3).should.be_true
end
it 'should return false when the value is not present'
$([1,2,3]).includes(4).should.be_false
end
it 'should return false when the any value is not present'
$([1,2,3]).includes(1,2,4).should.be_false
$([1,2,3]).includes(1,4,2).should.be_false
end
end
describe '#toString()'
it 'should output [Collection ...] for array'
$([1,2,3]).toString().should.eql '[Collection 1,2,3]'
end
it 'should output [Collection [object Object]] for object'
$({ foo: "bar" }).toString().should.eql '[Collection [object Object]]'
end
it 'should output [Collection [[Collection ...]]] for nested collections'
$([$([1,2,3])]).toString().should.eql '[Collection [Collection 1,2,3]]'
end
end
end
end
-83
Ver Arquivo
@@ -1,83 +0,0 @@
process.mixin(require('express/collection'))
process.mixin(require('express/element-collection'))
describe 'Express'
describe 'ElementCollection'
describe '$("markup string")'
it 'should return a ElementCollection'
$('<p>foo</p>').should.be_an_instance_of Collection
$('<p>foo</p>').should.be_an_instance_of ElementCollection
end
it 'should wrap with <html><body>.. when not present'
$('<p>foo</p>').at(0).name().should.eql 'html'
end
it 'should not wrap with <html><body> when already present'
$('<html><body></body></html>').at(0).name().should.eql 'html'
end
end
describe '#name()'
it 'should return the first elements name'
$('<html><body></body></html>').name().should.eql 'html'
end
end
describe '#xpath()'
it 'should find children matching the given xpath'
$('<li>1</li><li>2</li>').xpath('descendant-or-self::li').length().should.eql 2
$('<li>1</li><li>2</li>').xpath('descendant-or-self::li').at(0).name().should.eql 'li'
var items = $('<li><p>Foo</p></li><li><p>Bar</p></li>').xpath('descendant-or-self::li')
items.xpath('descendant-or-self::p').length().should.eql 2
end
end
describe '#search()'
it 'should find children matching the given css selector'
$('<ul><li>foo</li><li>bar</li></ul>').search('ul > li:nth-child(2)').text().should.eql 'bar'
end
end
describe '#children()'
it 'should return children'
$('<p><em>foo</em><strong>bar</strong></p>').children().length().should.eql 1
$('<p><em>foo</em><strong>bar</strong></p>').xpath('descendant-or-self::p').children().length().should.eql 2
end
end
describe '#parents()'
it 'should return parents'
$('<ul><li></li></ul><ul><li></li></ul>').xpath('descendant-or-self::li').parents().length().should.eql 2
$('<ul><li></li></ul><ul><li></li></ul>').xpath("descendant-or-self::*/*[name() = 'ul' and (position() = 1)]/descendant::li").parents().length().should.eql 1
end
end
describe '#parent()'
it 'should return the first parent'
$('<ul><li></li></ul><ul><li></li></ul>').xpath('descendant-or-self::li').parent().length().should.eql 1
end
end
describe '#text()'
it 'should return an elements text'
$('<p>foo bar</p>').text().should.eql 'foo bar'
end
end
describe '#next()'
it 'should return the next element'
$('<em>foo</em><p>bar</p>').xpath('descendant-or-self::em').next().text().should.eql 'bar'
end
end
describe '#prev()'
it 'should return the previous element'
$('<em>foo</em><p>bar</p>').xpath('descendant-or-self::p').prev().text().should.eql 'foo'
end
end
end
end
-23
Ver Arquivo
@@ -1,23 +0,0 @@
describe 'Express'
before_each
reset()
use(require('express/plugins/common-logger').CommonLogger)
end
describe 'CommonLogger'
describe 'on'
describe 'response'
it 'should output in common log format'
GLOBAL.stub('puts')
GLOBAL.should.receive('puts')
get('/style.css', function(){
this.contentType('css')
return 'body { background: #000; }'
})
get('/style.css')
end
end
end
end
end
+28 -13
Ver Arquivo
@@ -107,18 +107,6 @@ describe 'Express'
get('/user').body.should.include('Oh noes!')
end
end
describe 'when given an invalid status code'
it 'should throw an InvalidStatusCode exception'
// TODO: use throw_error when fixed...
get('/user', function(){ this.halt(123123) })
try { get('/user') }
catch (e) {
e.should.be_an_instance_of ExpressError
e.should.be_an_instance_of InvalidStatusCode
}
end
end
end
describe '#contentType()'
@@ -210,6 +198,33 @@ describe 'Express'
})
get('/public/app.js').body.should.eql 'public, app, js'
end
end
end
describe '#pass()'
it 'should pass control to the next matching route'
get('/user', function(){
this.pass()
})
get('/user', function(){
this.pass()
return 'nodejs'
})
get('/user', function(){ return 'success'})
get('/user').body.should.eql 'success'
end
describe 'given a string'
it 'should pass to the given route'
get('/user', function(){
this.pass('/user/1')
})
get('/user/:id', function(){
return 'Supa doopa usa'
})
get('/user').body.should.eql 'Supa doopa usa'
end
end
end
end
end
-13
Ver Arquivo
@@ -84,19 +84,6 @@ describe 'Express'
end
end
describe 'with no response body'
it 'should throw a InvalidResponseBody'
// TODO: use throw_error when fixed...
get('/user', function(){
this.respond()
})
try { get('/user') }
catch (e) {
e.should.be_an_instance_of InvalidResponseBody
}
end
end
describe 'with regular expression'
it 'should match'
get(/^\/user\/(\d+)\/(\w+)/, function(id, operation){
+2 -1
Ver Arquivo
@@ -14,7 +14,8 @@ describe 'Express'
// TODO: use throw_error when fixed...
try { new StaticFile('/../foobar') }
catch (e) {
e.should.be_an_instance_of InvalidPathError
e.name.should.eql 'InvalidPathError'
e.message.should.eql "`/../foobar' is not a valid path"
}
end
end
+2 -36
Ver Arquivo
@@ -4,21 +4,6 @@ describe 'Express'
utils = require('express/utils')
end
describe 'toArray()'
describe 'when given an array'
it 'should return the array'
utils.toArray([1,2,3]).should.eql [1,2,3]
end
end
describe 'when given an object with indexed values and length'
it 'should return an array'
var args = -{ return arguments }('foo', 'bar')
utils.toArray(args).should.eql ['foo', 'bar']
end
end
end
describe 'escape()'
it 'should escape html'
utils.escape('<p>this & that').should.eql '&lt;p&gt;this &amp; that'
@@ -32,31 +17,12 @@ describe 'Express'
end
end
describe 'extname()'
it 'should return the a files extension'
utils.extname('image.png').should.eql 'png'
utils.extname('image.large.png').should.eql 'png'
utils.extname('/path/to/image.large.png').should.eql 'png'
end
it 'should return null when not found'
utils.extname('path').should.be_null
utils.extname('/just/a/path').should.be_null
end
end
describe 'basename()'
it 'should return a files basename'
utils.basename('foo/bar/baz.image.png').should.eql 'baz.image.png'
end
end
describe 'mergeParam()'
describe 'with empty params'
it 'should merge the given key and value'
params = {}
utils.mergeParam('user[names][first]', 'tj', params)
params.user.names.first.should.eql 'tj'
utils.mergeParam('user[names][firstName]', 'tj', params)
params.user.names.firstName.should.eql 'tj'
end
end