Skip to content

Commit

Permalink
Multi-level middleware working
Browse files Browse the repository at this point in the history
  • Loading branch information
agnoster committed Oct 10, 2012
1 parent 2258c7f commit 21e1f76
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 24 deletions.
71 changes: 54 additions & 17 deletions lib/index.js
Expand Up @@ -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 = []
Expand All @@ -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
}

Expand All @@ -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)
}
}

Expand All @@ -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() {
Expand Down
7 changes: 5 additions & 2 deletions lib/plugins/debug.js
Expand Up @@ -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()
}
}
2 changes: 1 addition & 1 deletion lib/plugins/http.js
Expand Up @@ -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)
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/plugins/markdown.js
Expand Up @@ -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/)
Expand All @@ -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)
Expand Down
11 changes: 11 additions & 0 deletions 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()
}
2 changes: 1 addition & 1 deletion lib/plugins/readfile.js
Expand Up @@ -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()

Expand Down
4 changes: 3 additions & 1 deletion package.json
Expand Up @@ -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",
Expand Down
50 changes: 50 additions & 0 deletions 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()
})
})
})

0 comments on commit 21e1f76

Please sign in to comment.