Created command line tooltags/v1.1.0
| @@ -461,6 +461,36 @@ These may be built using [Rake](http://rake.rubyforge.org/) and one of the follo | |||||
| $ rake yui3 | $ rake yui3 | ||||
| $ rake qooxdoo | $ rake qooxdoo | ||||
| ## Command line tool | |||||
| mustache.js is shipped with a node based command line tool. It might be installed as a global tool on your computer to render a mustache template of some kind | |||||
| ```bash | |||||
| $ npm install -g mustache | |||||
| $ mustache dataView.json myTemplate.mustache > output.html | |||||
| # also supports stdin | |||||
| $ cat dataView.json | mustache - myTemplate.mustache > output.html | |||||
| ``` | |||||
| or as a package.json `devDependency` in a build process maybe? | |||||
| ```bash | |||||
| $ npm install mustache --save-dev | |||||
| ``` | |||||
| ```json | |||||
| { | |||||
| "scripts": { | |||||
| "build": "mustache dataView.json myTemplate.mustache > public/output.html" | |||||
| } | |||||
| } | |||||
| ``` | |||||
| ```bash | |||||
| $ npm run build | |||||
| ``` | |||||
| The command line tool is basically a wrapper around `Mustache.render` so you get all the aformentioned features. | |||||
| ## Testing | ## Testing | ||||
| In order to run the tests you'll need to install [node](http://nodejs.org/). | In order to run the tests you'll need to install [node](http://nodejs.org/). | ||||
| @@ -0,0 +1,89 @@ | |||||
| #!/usr/bin/env node | |||||
| var fs = require('fs'); | |||||
| var Mustache = require('..'); | |||||
| var pkg = require('../package'); | |||||
| var viewArg = process.argv[2]; | |||||
| var templateArg = process.argv[3]; | |||||
| if (process.argv.indexOf('--version') > -1) { | |||||
| return console.log(pkg.version); | |||||
| } | |||||
| if (!templateArg || !viewArg) { | |||||
| console.error('Syntax: mustache <view> <template>'); | |||||
| process.exit(1); | |||||
| } | |||||
| run(readView, readTemplate, render, toStdout); | |||||
| /** | |||||
| * Runs a list of functions as a waterfall. | |||||
| * Functions are runned one after the other in order, providing each | |||||
| * function the returned values of all the previously invoked functions. | |||||
| * Each function is expected to exit the process if an error occurs. | |||||
| */ | |||||
| function run(/*args*/) { | |||||
| var values = []; | |||||
| var fns = Array.prototype.slice.call(arguments); | |||||
| function invokeNextFn(val) { | |||||
| values.unshift(val); | |||||
| if (fns.length == 0) return; | |||||
| invoke(fns.shift()); | |||||
| } | |||||
| function invoke(fn) { | |||||
| fn.apply(null, [invokeNextFn].concat(values)); | |||||
| } | |||||
| invoke(fns.shift()); | |||||
| } | |||||
| function readView(cb) { | |||||
| var view = isStdin(viewArg) ? process.openStdin() : fs.createReadStream(viewArg); | |||||
| streamToStr(view, function(str) { | |||||
| cb(JSON.parse(str)); | |||||
| }); | |||||
| } | |||||
| function readTemplate(cb) { | |||||
| var template = fs.createReadStream(templateArg); | |||||
| streamToStr(template, cb); | |||||
| } | |||||
| function render(cb, templateStr, jsonView) { | |||||
| cb(Mustache.render(templateStr, jsonView)); | |||||
| } | |||||
| function toStdout(cb, str) { | |||||
| cb(process.stdout.write(str)); | |||||
| } | |||||
| function streamToStr(stream, cb) { | |||||
| var data = ''; | |||||
| stream.on('data', function(chunk) { | |||||
| data += chunk; | |||||
| }).once('end', function() { | |||||
| cb(data.toString()); | |||||
| }).on('error', function(err) { | |||||
| if (wasNotFound(err)) { | |||||
| console.error('Could not find file:', err.path); | |||||
| } else { | |||||
| console.error('Error while reading file:', err.message); | |||||
| } | |||||
| process.exit(1); | |||||
| }); | |||||
| } | |||||
| function isStdin(viewArg) { | |||||
| return viewArg === '-'; | |||||
| } | |||||
| function wasNotFound(err) { | |||||
| return err.code && err.code === 'ENOENT'; | |||||
| } | |||||
| @@ -14,6 +14,9 @@ | |||||
| "ejs" | "ejs" | ||||
| ], | ], | ||||
| "main": "./mustache.js", | "main": "./mustache.js", | ||||
| "bin": { | |||||
| "mustache": "./bin/mustache" | |||||
| }, | |||||
| "volo": { | "volo": { | ||||
| "url": "https://raw.github.com/janl/mustache.js/{version}/mustache.js" | "url": "https://raw.github.com/janl/mustache.js/{version}/mustache.js" | ||||
| }, | }, | ||||
| @@ -0,0 +1,3 @@ | |||||
| { | |||||
| "name": "LeBron" | |||||
| } | |||||
| @@ -0,0 +1 @@ | |||||
| Howdy {{name}}, CLI rox | |||||
| @@ -0,0 +1 @@ | |||||
| Howdy LeBron, CLI rox | |||||
| @@ -0,0 +1,70 @@ | |||||
| require('./helper'); | |||||
| var fs = require('fs'); | |||||
| var path = require('path'); | |||||
| var _files = path.join(__dirname, '_files'); | |||||
| var cliTxt = path.resolve(_files, 'cli.txt'); | |||||
| var moduleVersion = require('../package').version; | |||||
| var exec = require('child_process').exec; | |||||
| describe('Mustache CLI', function () { | |||||
| var expectedOutput; | |||||
| before(function(done) { | |||||
| fs.readFile(cliTxt, function onFsEnd(err, data) { | |||||
| if (err) return done(err); | |||||
| expectedOutput = data.toString(); | |||||
| done(); | |||||
| }); | |||||
| }); | |||||
| it('writes syntax hints into stderr when runned with wrong number of arguments', function(done) { | |||||
| exec('bin/mustache', function(err, stdout, stderr) { | |||||
| assert.notEqual(stderr.indexOf('Syntax'), -1); | |||||
| done(); | |||||
| }); | |||||
| }); | |||||
| it('writes module version into stdout when runned with --version', function(done){ | |||||
| exec('bin/mustache --version', function(err, stdout, stderr) { | |||||
| assert.notEqual(stdout.indexOf(moduleVersion), -1); | |||||
| done(); | |||||
| }); | |||||
| }); | |||||
| it('writes rendered template into stdout when successfull', function(done) { | |||||
| exec('bin/mustache test/_files/cli.json test/_files/cli.mustache', function(err, stdout, stderr) { | |||||
| assert.equal(err, null); | |||||
| assert.equal(stderr, ''); | |||||
| assert.equal(stdout, expectedOutput); | |||||
| done(); | |||||
| }); | |||||
| }); | |||||
| it('reads view data from stdin when first argument equals "-"', function(done){ | |||||
| exec('cat test/_files/cli.json | bin/mustache - test/_files/cli.mustache', function(err, stdout, stderr) { | |||||
| assert.equal(err, null); | |||||
| assert.equal(stderr, ''); | |||||
| assert.equal(stdout, expectedOutput); | |||||
| done(); | |||||
| }); | |||||
| }); | |||||
| it('writes it couldnt find template into stderr when second argument doesnt resolve to a file', function(done) { | |||||
| exec('bin/mustache test/_files/cli.json test/_files/non-existing-template.mustache', function(err, stdout, stderr) { | |||||
| assert.notEqual(stderr.indexOf('Could not find file: test/_files/non-existing-template.mustache'), -1); | |||||
| done(); | |||||
| }); | |||||
| }); | |||||
| it('writes it couldnt find view into stderr when first argument doesnt resolve to a file', function(done) { | |||||
| exec('bin/mustache test/_files/non-existing-view.json test/_files/cli.mustache', function(err, stdout, stderr) { | |||||
| assert.notEqual(stderr.indexOf('Could not find file: test/_files/non-existing-view.json'), -1); | |||||
| done(); | |||||
| }); | |||||
| }); | |||||
| }); | |||||