Comparing version 1.1.13 to 1.1.14
@@ -8,4 +8,8 @@ #!/usr/bin/env node | ||
var package = require(process.cwd() + '/package.json'); | ||
if (package && !package.main) { | ||
console.log('Please fill `main` field in your `package.json` file'); | ||
process.exit(); | ||
} | ||
if (package.main.match(/\.coffee$/)) { | ||
require('coffee-script'); | ||
require('coffee-script/register'); | ||
} | ||
@@ -12,0 +16,0 @@ instantiateApp = require(process.cwd()); |
@@ -154,3 +154,3 @@ var fs = require('fs'), | ||
// run config/initializers/* | ||
if (isServerSide) { | ||
if (isServerSide && compound.app) { | ||
compound.runInitializers(root); | ||
@@ -278,8 +278,10 @@ } | ||
Compound.prototype.runInitializers = function runInitializers(root) { | ||
var queue, compound = this, initializersPath = path.join( | ||
var queue, pattern, compound = this, initializersPath = path.join( | ||
root || compound.root, 'config', 'initializers'); | ||
pattern = compound.app.get('ignore initializers pattern') || /^\./; | ||
if (existsSync(initializersPath)) { | ||
queue = fs.readdirSync(initializersPath).map(function(file) { | ||
if (file.match(/^\./)) return false; | ||
if (file.match(pattern)) return false; | ||
return requireFun(path.join(initializersPath, file)); | ||
@@ -286,0 +288,0 @@ }).filter(Boolean); |
@@ -231,2 +231,5 @@ var fs = require('fs'); | ||
} | ||
if (controllers[name].skipLogging) { | ||
Controller.skipLogging = controllers[name].skipLogging; | ||
} | ||
@@ -270,4 +273,8 @@ // add controller extensions | ||
var log = compound.utils.debug; | ||
var skipLogging = ctl.constructor.skipLogging; | ||
var logger = ctl.getLogger(); | ||
logger.on('beforeProcessing', function(ctl) { | ||
if (skipLogging && skipLogging.indexOf(ctl.actionName) > -1) { | ||
return; | ||
} | ||
var req = ctl.context.req; | ||
@@ -318,2 +325,5 @@ | ||
logger.on('afterProcessing', function(ctl, duration) { | ||
if (skipLogging && skipLogging.indexOf(ctl.actionName) > -1) { | ||
return; | ||
} | ||
var req = ctl.context.req; | ||
@@ -324,2 +334,5 @@ log('Handling ' + $(req.method).bold + ' ' + $(req.url).grey + | ||
logger.on('beforeHook', function(ctl, action) { | ||
if (skipLogging && skipLogging.indexOf(ctl.actionName) > -1) { | ||
return; | ||
} | ||
if (ctl.context.inAction) { | ||
@@ -332,5 +345,11 @@ log('>>> perform ' + $(action).bold.cyan); | ||
logger.on('afterHook', function(ctl, action, duration) { | ||
if (skipLogging && skipLogging.indexOf(ctl.actionName) > -1) { | ||
return; | ||
} | ||
log('<<< ' + action + ' [' + duration + ' ms]'); | ||
}); | ||
logger.on('render', function(file, layout, duration) { | ||
if (skipLogging && skipLogging.indexOf(ctl.actionName) > -1) { | ||
return; | ||
} | ||
log('Rendered ' + $(file).grey + ' using layout ' + $(layout).grey + | ||
@@ -337,0 +356,0 @@ ' in ' + duration + 'ms'); |
@@ -183,2 +183,68 @@ var fs = require('fs'), | ||
/** | ||
* Handle specific format. When 'format' present in req.param(), desired handler | ||
* called, otherwise default handler called. Default handler name can be specified | ||
* by setting `app.set('default format', 'xml')`. If not specified - default is html | ||
* | ||
* Example of usage: | ||
* | ||
* BlogController.prototype.index = function(c) { | ||
* Post.all(c.safe(function(post) { | ||
* c.format({ | ||
* json: function() {c.send(posts);}, | ||
* html: function() {c.render({posts: posts});} | ||
* }); | ||
* })); | ||
* }; | ||
* | ||
* @param {Object} handlers - hash of functions to handle each specific format | ||
*/ | ||
Controller.prototype.format = function format(handlers) { | ||
var requestedFormat = this.req.param('format'); | ||
if (requestedFormat in handlers) { | ||
return handlers[requestedFormat].call(this.locals); | ||
} | ||
var defaultFormat = this.req.app.get('default format') || 'html'; | ||
if (defaultFormat in handlers) { | ||
return handlers[defaultFormat].call(this.locals); | ||
} | ||
}; | ||
/** | ||
* Return safe callback. This is utility function which allows to reduce nesting | ||
* level and less code to track errors. | ||
* | ||
* Example of usage: | ||
* | ||
* CheckoutController.prototype.orderProducts = function(c) { | ||
* c.basket.createOrder(c.safe(function(order) { | ||
* this.order = order; // pass order to view | ||
* c.render('success'); | ||
* })); | ||
* }; | ||
* | ||
* // same as | ||
* | ||
* CheckoutController.prototype.orderProducts = function(c) { | ||
* c.basket.createOrder(function(err, order) { | ||
* if (err) { | ||
* c.next(err); | ||
* } else { | ||
* c.locals.order = order; // pass order to view | ||
* c.render('success'); | ||
* } | ||
* }); | ||
* }; | ||
* | ||
*/ | ||
Controller.prototype.safe = function safe(callback) { | ||
var c = this; | ||
return function safeCallback(err) { | ||
if (err) { | ||
return c.next(err); | ||
} | ||
callback.apply(c.locals, Array.prototype.slice.call(arguments, 1)); | ||
}; | ||
}; | ||
function ensureFlash(req) { | ||
@@ -185,0 +251,0 @@ if (req.flash) { |
@@ -50,3 +50,5 @@ /** | ||
} | ||
if (this.isBaseDirExists()) { | ||
return; | ||
} | ||
this.createDirectoryStructure(); | ||
@@ -53,0 +55,0 @@ this.copyFiles(); |
@@ -428,3 +428,3 @@ /** | ||
GeneratorUtilities.prototype.isEvalAllowed = function () { | ||
GeneratorUtilities.prototype.isEvalAllowed = function() { | ||
return !('noeval' in this.options); | ||
@@ -440,2 +440,10 @@ }; | ||
GeneratorUtilities.prototype.isBaseDirExists = function() { | ||
var exists = fs.existsSync(this.baseDir); | ||
if (exists) { | ||
this.log($('"' + this.baseDir + '" exists', this.baseDir).bold.red); | ||
} | ||
return exists; | ||
}; | ||
module.exports = GeneratorUtilities; |
var path = require('path'), | ||
net = require('net'), | ||
fs = require('fs'), | ||
os = require('os'), | ||
readline = require('readline'), | ||
@@ -147,2 +148,17 @@ childProcess = require('child_process'), | ||
repl.defineCommand('keys', { | ||
help: 'Iterates through a list of nested keys. Prints by default. Usage: keys(object, depth)', | ||
action: (this.keys = function keys(obj, depth, level, iterator) { | ||
iterator = iterator || console.log; | ||
for(var key in obj) { | ||
iterator((new Array(level || (level=0))).join('-'), '>', key); | ||
if(obj[key] && typeof(obj[key]) == 'object') { | ||
if(depth) { | ||
keys(obj[key], --depth, level+3, iterator); | ||
} | ||
} | ||
}; | ||
}) | ||
}); | ||
this.c = function() { | ||
@@ -180,5 +196,107 @@ var l = arguments.length, | ||
// Set up cli history | ||
var historyFile = path.join(os.tmpdir(), '.compound_history'); | ||
var historySearchMode = false; | ||
var historySearchString = ''; | ||
var historySearchPrompt = '(history-search)`%`:'; | ||
var _ttyWrite = repl.rli._ttyWrite; | ||
repl.rli.on('line', function(line) { | ||
// Write to history file | ||
fs.appendFile(historyFile, '\n' + line); | ||
}); | ||
fs.readFile(historyFile, {encoding: 'utf8'}, function(err, data) { | ||
if (err) { | ||
return; | ||
} | ||
// Remove the last element (newline) | ||
var history = data.split('\n').slice(1); | ||
repl.rli.history = history.reverse(); | ||
}); | ||
// Search through cli history | ||
repl.rli.input.on('keypress', function(s, key) { | ||
if (!key) return; | ||
if (historySearchMode) { | ||
if (key.name === 'return' || key.name === 'enter' || key.name === 'linefeed') { | ||
// Done searching, run command | ||
handleHistory(true); | ||
return; | ||
} | ||
if (key.name === 'left' || key.name === 'right') { | ||
handleHistory(false); | ||
return; | ||
} | ||
return; | ||
} | ||
if (key.ctrl && key.name === 'r') { | ||
repl.prompt = historySearchPrompt; | ||
repl.rli._ttyWrite = ttyWriteHistory; | ||
historySearchMode = true; | ||
historySearchString = repl.rli.line; | ||
repl.rli.line = ''; | ||
refreshHistoryPrompt(); | ||
return; | ||
} | ||
}); | ||
function ttyWriteHistory(s, key) { | ||
if (!key) { | ||
historySearchString += s; | ||
refreshHistoryPrompt(); | ||
return; | ||
} | ||
if (key.name.length === 1) { | ||
historySearchString += key.name; | ||
refreshHistoryPrompt(); | ||
return; | ||
} | ||
if (key.name === 'backspace') { | ||
historySearchString = historySearchString.substr(0, historySearchString.length - 1); | ||
refreshHistoryPrompt(); | ||
return; | ||
} | ||
if (key.name === 'space') { | ||
historySearchString += ' '; | ||
refreshHistoryPrompt(); | ||
return; | ||
} | ||
} | ||
function refreshHistoryPrompt() { | ||
repl.prompt = historySearchPrompt.split('%').join(historySearchString); | ||
repl.rli.line = matchHistory(historySearchString); | ||
repl.displayPrompt(); | ||
} | ||
function matchHistory(match) { | ||
if (match.length < 1) return ''; | ||
// Search through the repl.rli.history array for a match | ||
for (var i = 0; i < repl.rli.history.length; ++i) { | ||
if (repl.rli.history[i].match(match)) { | ||
repl.rli.historyIndex = i; | ||
return repl.rli.history[i]; | ||
} | ||
} | ||
return ''; | ||
} | ||
function handleHistory(run) { | ||
historySearchMode = false; | ||
repl.prompt = 'compound> '; | ||
repl.displayPrompt(); | ||
repl.rli._ttyWrite = _ttyWrite; | ||
if (run) { | ||
console.log(''); | ||
var cmd = repl.rli.line; | ||
repl.rli.line = ''; | ||
repl.rli._onLine(cmd); | ||
repl.displayPrompt(); | ||
} | ||
historySearchString = ''; | ||
} | ||
repl.on('exit', function() { | ||
console.log('Bye'); | ||
process.exit(0); | ||
// Overwrite history file to remove old data | ||
fs.writeFile(historyFile, '\n' + repl.rli.history.reverse().join('\n'), function(err) { | ||
if (err) { | ||
console.log('Could not write history file', err); | ||
} | ||
console.log('Bye'); | ||
process.exit(0); | ||
}); | ||
}); | ||
@@ -185,0 +303,0 @@ })(); |
{ | ||
"name": "compound", | ||
"version": "1.1.13", | ||
"version": "1.1.14", | ||
"author": "Anatoliy Chakkaev", | ||
@@ -37,3 +37,3 @@ "contributors": [ | ||
"yaml-js": ">= 0.0.2", | ||
"coffee-script": ">= 1.6.x", | ||
"coffee-script": "1.7.x", | ||
"ejs-ext": ">= 0.1.4-2", | ||
@@ -40,0 +40,0 @@ "jade-ext": ">= 0.0.5", |
@@ -172,3 +172,3 @@ About [<img src="https://secure.travis-ci.org/1602/compound.png" />](http://travis-ci.org/#!/1602/compound) | ||
Now we do not have to tediously describe REST rotes for each resource, enough to write in `config/routes.js` code like this: | ||
Now we do not have to tediously describe REST routes for each resource, enough to write in `config/routes.js` code like this: | ||
@@ -205,3 +205,3 @@ ```js | ||
and you can more finely tune the resources to specify certain actions, middleware, and other. Here example routes of [my blog][1]: | ||
and you can more finely tune the resources to specify certain actions, middleware, and other. Here are example routes for [my blog][1]: | ||
@@ -223,3 +223,3 @@ ```js | ||
since version 0.2.0 it is possible to use generic routes: | ||
since version 0.2.0, it is possible to use generic routes: | ||
@@ -398,3 +398,3 @@ ```js | ||
or it's shortcut | ||
or its shortcut | ||
@@ -405,9 +405,9 @@ ```sh | ||
It just simple node-js console with some Compound bindings, e.g. models. Just one note | ||
about working with console. Node.js is asynchronous by its nature, and it's great | ||
but it made console debugging much more complicated, because you should use callback | ||
to fetch result from database, for example. I have added one useful method to | ||
simplify async debugging using compound console. It's name `c`, you can pass it | ||
as parameter to any function requires callback, and it will store parameters passed | ||
to callback to variables `_0, _1, ..., _N` where N is index in `arguments`. | ||
It's just simple node-js console with some Compound bindings, e.g. models. Just one note | ||
about working with console: Node.js is asynchronous by its nature, and it's great | ||
but it made console debugging much more complicated, because you should use callbacks | ||
to fetch results from the database, for example. I have added one useful method to | ||
simplify async debugging using compound console. It's named `c`. You can pass it | ||
as a parameter to any function requiring callbacks, and it will store parameters passed | ||
to the callback as variables `_0, _1, ..., _N` where N is index in `arguments`. | ||
@@ -435,3 +435,3 @@ Example: | ||
To add another language to app just create yml file in `config/locales`, | ||
To add another language to app just create a .yml file in `config/locales`, | ||
for example `config/locales/jp.yml`, copy contents of `config/locales/en.yml` to new | ||
@@ -474,4 +474,4 @@ file and rename root node (`en` to `jp` in that case), also in `lang` section rename | ||
Enable controllers caching, should be turned on in prd. In development mode | ||
disabling cache allows to avoid server restarting after each model/controller change | ||
Enable controller caching, should be turned on in prod. In development mode, | ||
disabling the cache allows the avoidance of server restarts after each model/controller change. | ||
@@ -486,3 +486,3 @@ ```js | ||
Same option for models. When disabled model files evaluated per each request. | ||
Same option for models. When disabled, model files evaluated per each request. | ||
@@ -489,0 +489,0 @@ ```js |
@@ -41,5 +41,31 @@ var Compound = require('../').Compound; | ||
}).should.throw('Named function or jugglingdb model required'); | ||
}); | ||
describe('run initializers', function(){ | ||
var app, c, root, path = '/test'; | ||
before(function(done) { | ||
app = getApp(); | ||
c = app.compound; | ||
c.on('ready', function() { | ||
root = c.root + path; | ||
done(); | ||
}); | ||
}); | ||
it('should fail to initialize files with README files', function() { | ||
(function(){ | ||
c.runInitializers(root); | ||
}).should.throw(); | ||
}); | ||
it('should initialize files without README with config pattern', function() { | ||
app.set('ignore initializers pattern', /^\.|\.md$/); | ||
(function(){ | ||
c.runInitializers(root); | ||
}).should.not.throw(); | ||
}); | ||
}); | ||
}); |
@@ -16,15 +16,20 @@ var app = getApp(); | ||
describe('rendering', function() { | ||
var controller, rendered, params = {}, req = { | ||
app: app, | ||
param: function(what) { | ||
return params[what]; | ||
} | ||
}, res = { | ||
render: function (file, params, callback) { | ||
rendered.push(file); | ||
if (callback) callback(); | ||
} | ||
}; | ||
var controller, rendered, req = {}, res = { | ||
render: function (file, params, callback) { | ||
rendered.push(file); | ||
if (callback) callback(); | ||
} | ||
}; | ||
function declareAndRun(action, test) { | ||
controller.action(action.name, action); | ||
controller.perform(action.name, req, res, test); | ||
} | ||
function declareAndRun(action, test) { | ||
controller.action(action.name, action); | ||
controller.perform(action.name, req, res, test); | ||
} | ||
describe('rendering', function() { | ||
@@ -55,2 +60,83 @@ beforeEach(function() { | ||
describe('safe', function() { | ||
beforeEach(function() { | ||
controller = compound.controllerBridge.getInstance('ctl'); | ||
rendered = []; | ||
}); | ||
it('should call callback when no error', function(done) { | ||
var args; | ||
declareAndRun(function renderDifferentFormat(c) { | ||
doAsyncStuff(c.safe(function() { | ||
args = Array.prototype.slice.call(arguments); | ||
c.next(); | ||
})); | ||
}, function() { | ||
args.should.have.lengthOf(1); | ||
args[0].should.equal('he'); | ||
done(); | ||
}); | ||
function doAsyncStuff(cb) {process.nextTick(function(){cb(null, 'he')})} | ||
}); | ||
it('should call c.next(err) when error', function(done) { | ||
var called = false; | ||
declareAndRun(function renderDifferentFormat(c) { | ||
doAsyncStuff(c.safe(function() { | ||
called = true; | ||
})); | ||
}, function() { | ||
called.should.be.false; | ||
done(); | ||
}); | ||
function doAsyncStuff(cb) {process.nextTick(function(){cb(new Error)})} | ||
}); | ||
}); | ||
describe('format', function() { | ||
beforeEach(function() { | ||
controller = compound.controllerBridge.getInstance('ctl'); | ||
rendered = []; | ||
delete params.format; | ||
}); | ||
it('should render desired format', function(done) { | ||
var args; | ||
params.format = 'mobile'; | ||
declareAndRun(function renderDesiredFormat(c) { | ||
c.format({ | ||
mobile: function() { | ||
c.next(); | ||
} | ||
}); | ||
}, done) | ||
}); | ||
it('should render default format', function(done) { | ||
var args; | ||
params.format = 'unknown'; | ||
declareAndRun(function renderDefaultFormat(c) { | ||
c.format({ | ||
html: function() { | ||
c.next(); | ||
} | ||
}); | ||
}, done) | ||
}); | ||
it('should render customized default format', function(done) { | ||
var args; | ||
app.set('default format', 'json'); | ||
params.format = 'unknown'; | ||
declareAndRun(function renderDefaultFormat(c) { | ||
c.format({ | ||
json: function() { | ||
c.next(); | ||
delete app.settings['default format']; | ||
} | ||
}); | ||
}, done) | ||
}); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
522386
121
13767
+ Addedcoffee-script@1.7.1(transitive)
- Removedcoffee-script@1.12.7(transitive)
Updatedcoffee-script@1.7.x