diff --git a/Makefile b/Makefile index 14ba05a..4f9b7ed 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,39 @@ -.PHONY: lib test +.PHONY: lib test library docs -lib_sources:= $(wildcard src/*.coffee) -lib_objects:= $(subst src/, lib/, $(lib_sources:%.coffee=%.js)) +COFFEE= ./node_modules/.bin/coffee +PEGJS= ./node_modules/.bin/pegjs +DOCCO= ./node_modules/.bin/docco +MOCHA= ./node_modules/.bin/mocha + +cof_sources:= $(wildcard src/*.coffee) +cof_objects:= $(subst src/, lib/, $(cof_sources:%.coffee=%.js)) + +peg_sources:= $(wildcard src/*.peg) +peg_objects:= $(subst src/, lib/, $(peg_sources:%.peg=%.js)) + +library: $(cof_objects) $(peg_objects) default: build -build: $(lib_objects) lib/tokenizer.js +build: $(lib_objects) lib: mkdir -p lib -lib/tumble.js: lib src/tumble.peg - ./node_modules/.bin/pegjs src/tumble.peg lib/tumble.js - -$(lib_objects): $(lib_sources) +$(cof_objects): $(cof_sources) @mkdir -p $(@D) - coffee -o $(@D) -c $< + $(COFFEE) -o $(@D) -c $< + +$(peg_objects): $(peg_sources) + @mkdir -p $(@D) + $(PEGJS) $< $@ + +docs: + $(DOCCO) $(cof_sources) + +echo: + echo $(cof_sources) + echo $(cof_objects) 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/bin/activate b/bin/activate new file mode 100644 index 0000000..d074497 --- /dev/null +++ b/bin/activate @@ -0,0 +1,8 @@ +#!/bin/bash + +# /bin comes before /node_modules/.bin because sometimes I want to +# override the behaviors provided. + +PROJECT_ROOT=`pwd` +PATH="$PROJECT_ROOT/bin:$PROJECT_ROOT/node_modules/.bin:$PATH" +export PATH diff --git a/bin/devserver b/bin/devserver new file mode 100755 index 0000000..defee27 --- /dev/null +++ b/bin/devserver @@ -0,0 +1,16 @@ +#!/usr/bin/env coffee + +staticserver = require('node-static') +files = new(staticserver.Server)('./dist') + +require('http').createServer((request, response) -> + request.addListener 'end', -> + files.serve request, response, (err, res) -> + if (err) + console.error("> Error serving " + request.url + " - " + err.message) + response.writeHead(err.status, err.headers) + response.end() + else + console.log("> " + request.url + " - " + res.message) +).listen(8081) +console.log("> node-static is listening on http://127.0.0.1:8081") diff --git a/src/parser.coffee b/src/parser.coffee index f2645d9..78eee0f 100644 --- a/src/parser.coffee +++ b/src/parser.coffee @@ -9,42 +9,58 @@ class Contexter @depth = 0 has_any: (name) -> - _.find this.stack, (o) -> _.has(o, name) + # Scan the parse stack from more recent to most distant, + # return the reference that contains this name. + _.find @stack, (o) -> _.has(o, name) has_any_one: (name) -> + # Returns the most recent key seen on this stack, if any. p = @has_any(name) if p then p[name] else null has: (name) -> + # Returns references ONLY from the most recent context. if @stack[0][name]? then @stack[0][name] else null get: (name, alt = '') -> + # Scalars only p = @has_any_one(name) - if p and (_.isString(p) or _.isNumber(p)) then p else alt + return p if p and (_.isString(p) or _.isNumber(p)) + return @render(p) once: (obj, cb) -> + # Create a new context, execute the block associated with that + # context, pop the context, and return the production. @stack.unshift obj - r = cb this + r = cb @ @stack.shift() r if: (name, cb) -> + # Execute and return this specifiecd block if and only if the + # requested context is valid. p = @has_any_one(name) - if p then cb(this) else '' + if p then cb(@) else '' block: (name, cb) -> + # Execute and return this specified block if and only if the + # requested context is valid and entrant. p = @has_any_one(name) if p and _.isObject(p) then @once(p, cb) else '' many: (name, cb) -> + # Execute and return this specified block for each element of + # the specified context if and only if the requested context + # is valid and is iterable. ps = @has(name) if not (ps and _.isArray(ps)) return "" (_.map ps, (p) => @once(p, cb)).join('') - templatize: (name, cb) -> + template: (name, cb) -> + # Store the specified block under a name. No production. @templates[name] = cb - "" + return "" render: (name) -> if @templates[name]? and _.isfunction(@templates[name]) then @templates[name](@) else ""