From 21e1f7682da10e2fe38742a21b5119bbc2778967 Mon Sep 17 00:00:00 2001 From: Isaac Wolkerstorfer Date: Wed, 10 Oct 2012 14:14:04 +0200 Subject: [PATCH] Multi-level middleware working --- lib/index.js | 71 ++++++++++++++++++++++++++-------- lib/plugins/debug.js | 7 +++- lib/plugins/http.js | 2 +- lib/plugins/markdown.js | 4 +- lib/plugins/markdown_output.js | 11 ++++++ lib/plugins/readfile.js | 2 +- package.json | 4 +- test/readfile.js | 50 ++++++++++++++++++++++++ 8 files changed, 127 insertions(+), 24 deletions(-) create mode 100644 lib/plugins/markdown_output.js create mode 100644 test/readfile.js diff --git a/lib/index.js b/lib/index.js index cbb2f5c..0d3b66f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -6,6 +6,12 @@ var fs = require('fs') , debug = require('debug')('literapi') , path = require('path') +var levelName = ["books", "documents", "examples"] +var levelIdx = levelName.reduce(function(acc, name, i){ + acc[name] = i + return acc +}, {}) + function LiterAPI(options) { this.options = options this.stack = [] @@ -14,8 +20,16 @@ function LiterAPI(options) { LiterAPI.prototype = {} +function plugin_min_level(plugin){ + for (var i = 0; i < levelName.length; i++) { + if (plugin.hasOwnProperty(levelName[i])) return i + } +} + LiterAPI.prototype.use = function use(plugin) { + debug("use", plugin) this.stack.push(plugin) + plugin.min_level = plugin_min_level(plugin) return this } @@ -26,35 +40,54 @@ LiterAPI.prototype.run = function run(cb) { LiterAPI.prototype.runBook = function runBook(book, cb) { debug('runBook', book) - async.mapSeries(book.documents, function (doc, cb) { + async.forEachSeries(book.documents, function (doc, cb) { doc.book = book - this.runDocument(doc, cb) + doc.context = {} + this.runLevel(levelIdx["documents"], 0, doc, cb) }.bind(this), cb) } -LiterAPI.prototype.runDocument = function runDocument(doc, cb) { - debug('runDocument', doc) +LiterAPI.prototype.runLevel = function runLevel(level, layer, el, cb) { + var lname = levelName[level] + debug('runLevel', level, lname, layer, el) - var stack = this.stack - , layer = 0 + var self = this function next(err) { - var plugin = stack[layer++] + var plugin = self.stack[layer] + + debug("next", layer, plugin) // No more plugins to run - if (!plugin) { - debug('no more plugins', layer) - return cb(err, doc) + if (!plugin || plugin.min_level < level) { + debug('no more plugins (at this level)', level, layer) + return cb(err, layer) } + // Errors pop right up if (err) { - next(err) - } else { - try { - plugin.document(doc, next) - } catch (e) { - next(err) + cb(err) + } + + try { + if (plugin.min_level == level) { + // Keep processing at this level + layer++ + plugin[lname](el, next) + } else { + // Move one level up + debug("up", level, plugin.min_level) + async.mapSeries(el[levelName[level + 1]], function(el, cb) { + self.runLevel(level + 1, layer, el, cb) + }, function(err, results) { + layer = results[0] + debug("Moved back to level", level, "at layer", layer) + next(err) + }) } + } catch (err) { + debug("Caught error", err) + next(err) } } @@ -77,7 +110,11 @@ function literapi(options) { } literapi.withDefaultPlugins = function (options) { - return literapi(options).use(literapi.readfile).use(literapi.markdown) + return (literapi(options) + .use(literapi.readfile) + .use(literapi.markdown) + .use(literapi.debug) + .use(literapi.markdown_output)) } literapi.__defineGetter__('version', function() { diff --git a/lib/plugins/debug.js b/lib/plugins/debug.js index abbcc80..2b516a9 100644 --- a/lib/plugins/debug.js +++ b/lib/plugins/debug.js @@ -2,7 +2,10 @@ if (global.GENTLY) require = GENTLY.hijack(require) module.exports = { - "document": function(doc, next) { - console("Document: ", doc) + "examples": function debug(el, next) { + console.log('*** DEBUG ***') + console.log(el) + console.log('*** DEBUG ***') + next() } } diff --git a/lib/plugins/http.js b/lib/plugins/http.js index b056b26..9082b92 100644 --- a/lib/plugins/http.js +++ b/lib/plugins/http.js @@ -112,7 +112,7 @@ function http(options, example, next) { module.exports = function(options) { return { - example: function(example, next) { + examples: function http(example, next) { return http(options, example, next) } } diff --git a/lib/plugins/markdown.js b/lib/plugins/markdown.js index 51fd381..bbacd45 100644 --- a/lib/plugins/markdown.js +++ b/lib/plugins/markdown.js @@ -30,7 +30,7 @@ function examples(tokens) { tokens.forEach(function(token) { if (token.type == 'code_block') { - tags = token.tags || '' + var tags = token.tags || '' examples.push( { text: token.content , pending: !!tags.match(/\bpending\b/) @@ -42,7 +42,7 @@ function examples(tokens) { return examples } -module.exports.document = function(doc, next) { +module.exports.documents = function markdown(doc, next) { debug('parsing text') parse(doc.text, function(err, parsed) { if (err) return next(err) diff --git a/lib/plugins/markdown_output.js b/lib/plugins/markdown_output.js new file mode 100644 index 0000000..72d83d1 --- /dev/null +++ b/lib/plugins/markdown_output.js @@ -0,0 +1,11 @@ +// Gently, see https://github.com/felixge/node-gently#gentlyhijackrealrequire +if (global.GENTLY) require = GENTLY.hijack(require) + +var Markdownstream = require('markdownstream') + , debug = require('debug')('literapi:plugin:markdown_output') + +module.exports.documents = function markdown_output(doc, next) { + doc.text = doc.markdown.parsed.join('') + debug("Created markdown output", doc.text) + next() +} diff --git a/lib/plugins/readfile.js b/lib/plugins/readfile.js index e780ef1..cf0e39b 100644 --- a/lib/plugins/readfile.js +++ b/lib/plugins/readfile.js @@ -8,7 +8,7 @@ var fs = require('fs') * readfile is a document plugin that reads the file given in doc.filename and saves * the contents as doc.text */ -module.exports.document = function(doc, next) { +module.exports.documents = function readfile(doc, next) { // Need a filename to load if (!doc.filename) return next() diff --git a/package.json b/package.json index b8bb599..cc98039 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,9 @@ }, "devDependencies": { "express": "~3.0", - "gently": "~0.9.2" + "gently": "~0.9.2", + "should": "~1.2.0", + "mocha": "~1.6.0" }, "engines": { "node": ">0.6.0", diff --git a/test/readfile.js b/test/readfile.js new file mode 100644 index 0000000..673d661 --- /dev/null +++ b/test/readfile.js @@ -0,0 +1,50 @@ +var gently = global.GENTLY = new (require('gently')) + , readfile = require('../lib/plugins/readfile').document + , should = require('should') + , fs = require('fs') + +describe("Readfile plugin", function() { + it("inserts the right content into the document", function(done) { + + var doc = { filename: 'hello.txt' } + + gently.expect(fs, 'readFile', function(filename, encoding, cb) { + filename.should.equal(doc.filename) + encoding.should.equal('utf8') + cb(null, "hello world") + }) + + readfile(doc, function(err) { + should.not.exist(err) + doc.text.should.equal("hello world") + done() + }) + }) + + it("propagates errors correctly", function(done) { + + var doc = { filename: 'foobar.txt' } + + gently.expect(fs, 'readFile', function(filename, encoding, cb) { + filename.should.equal(doc.filename) + cb("What file?") + }) + + readfile(doc, function(err) { + err.should.equal("What file?") + done() + }) + }) + + it("skips the document if no filename given", function(done) { + + gently.expect(fs, 'readFile', 0, function(filename, encoding, cb) { + should.not.exist("We should never reach this") + }) + + readfile({}, function(err) { + should.not.exist(err) + done() + }) + }) +})