diff --git a/.gitignore b/.gitignore index 7847ea0..e19f199 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ npm-debug.log node_modules/* lib/ +tmp/ diff --git a/Makefile b/Makefile index 54703ae..14ba05a 100644 --- a/Makefile +++ b/Makefile @@ -13,11 +13,11 @@ lib: lib/tumble.js: lib src/tumble.peg ./node_modules/.bin/pegjs src/tumble.peg lib/tumble.js -$(lib_objects): lib lib/%.js: src/%.coffee +$(lib_objects): $(lib_sources) @mkdir -p $(@D) coffee -o $(@D) -c $< -test: test/[0-9]*_mocha.coffee lib/tumble.js +test: test/[0-9]*_mocha.coffee lib/tumble.js lib/parser.js ./node_modules/.bin/mocha -R tap -C --compilers coffee:coffee-script -u tdd $< diff --git a/src/parser.coffee b/src/parser.coffee new file mode 100644 index 0000000..f2645d9 --- /dev/null +++ b/src/parser.coffee @@ -0,0 +1,63 @@ +_ = require 'underscore' +util = require 'util' + +class Contexter + + constructor: (@content) -> + @stack = [@content] + @templates = {} + @depth = 0 + + has_any: (name) -> + _.find this.stack, (o) -> _.has(o, name) + + has_any_one: (name) -> + p = @has_any(name) + if p then p[name] else null + + has: (name) -> + if @stack[0][name]? then @stack[0][name] else null + + get: (name, alt = '') -> + p = @has_any_one(name) + if p and (_.isString(p) or _.isNumber(p)) then p else alt + + once: (obj, cb) -> + @stack.unshift obj + r = cb this + @stack.shift() + r + + if: (name, cb) -> + p = @has_any_one(name) + if p then cb(this) else '' + + block: (name, cb) -> + p = @has_any_one(name) + if p and _.isObject(p) then @once(p, cb) else '' + + many: (name, cb) -> + ps = @has(name) + if not (ps and _.isArray(ps)) + return "" + (_.map ps, (p) => @once(p, cb)).join('') + + templatize: (name, cb) -> + @templates[name] = cb + "" + + render: (name) -> + if @templates[name]? and _.isfunction(@templates[name]) then @templates[name](@) else "" + + +module.exports = (ast, data) -> + context = new Contexter(data) + + cmd = (o) -> + switch o.unit + when 'variable' then (context) -> context.get(o.name) + when 'text' then (context) -> o.content + when 'block' then (context) -> context[o.type] o.name, (context) -> + (cmd(p)(context) for p in o.content).join("") + + (cmd(o)(context) for o in ast.content).join("") diff --git a/src/tumble.peg b/src/tumble.peg index a9388d0..422a5d2 100644 --- a/src/tumble.peg +++ b/src/tumble.peg @@ -2,7 +2,7 @@ document = ps:part* - { return ps; } + { return { unit: "block", name: "document", content: ps }; } part = block / variable / text diff --git a/test/01_basics_mocha.coffee b/test/01_basics_mocha.coffee index a4451ae..faa352f 100644 --- a/test/01_basics_mocha.coffee +++ b/test/01_basics_mocha.coffee @@ -5,6 +5,7 @@ should = chai.should() util = require 'util' tumble = require('../lib/tumble').parse; +parse = require('../lib/parser'); test_data = [ { @@ -98,7 +99,7 @@ describe "Basic Functionality", -> do (data) -> it "should work with #{data.description}", -> r = tumble(data.input) - r = r(data.data) + r = parse(r, data.data) r.should.equal data.output describe "Check for recursion", -> @@ -111,7 +112,8 @@ describe "Check for recursion", -> do (data) -> it "should catch an exception", -> try - r = tumble(data.input)(data.data) + r = tumble(data.input) + r = parse(r, data.data) assert.ok false, "It did not throw the exception" catch err - assert.ok true, "Recursion depth exeception thrown." + assert.ok err.id == 'recursion-error', "Recursion depth exeception thrown."