Permalink
Browse files

Renovated tests, fixed function calls

  • Loading branch information...
1 parent 1742862 commit b9f679c1bde3de45f32cf3f73a83a56feaa33929 @chbrown committed Jan 10, 2013
View
@@ -66,13 +66,7 @@ function stringEval(context, expression) {
var parts = expression.split('.');
for (var i = 0, part; (part = parts[i]) !== undefined; i++) {
- var next = context[part];
- if (typeof(next) === 'function') {
- context = next();
- }
- else {
- context = next;
- }
+ var context = context[part];
if (context === undefined || context === null) {
return undefined;
}
@@ -98,34 +92,38 @@ function expressionEval(context, expression) {
else if (op === '>=') return left >= right;
else throw new Error("Unrecognized operator: " + op);
}
- else if (m = expression.match(/^\S\(\S*\)$/)) {
- // xxx: this TOTALLY needs fixing.
+ else if (m = expression.match(/^(\S+)\((\S*)\)$/)) {
+ // functions.
// open parens indicates function application,
// the entire following conditional is for functional application.
- var open_parens_index = new_node.val.indexOf('(');
// close_parens_index should be append_to_top.length - 1
- var close_parens_index = new_node.val.lastIndexOf(')');
// String.substring takes two indices (not a length)
- var argument_part = new_node.val.substring(open_parens_index + 1, close_parens_index);
+ // var argument_part = new_node.val.substring(open_parens_index + 1, close_parens_index);
// trim whitespace/quotes since arguments can only be strings or ints anyway. At least, for now.
// (todo: let them embed commas in strings)
- var argument_array = argument_part.split(',').map(function(s) {
- var trimmed_val = s.replace(/^\s+|\s+$/g, '');
- var type = 'variable';
- if (trimmed_val.match(/^['"].*['"]$/)) {
- type = 'static';
- trimmed_val = trimmed_val.slice(1, -1);
+ console.log('\nm:', m[1], '(', m[2], ')', context);
+ var func = stringEval(context, m[1]) || eval(m[1]);
+ console.log('func:', func);
+ var args = m[2].split(',').map(function(raw) {
+ var val = raw.replace(/^\s+|\s+$/g, '');
+ console.log('arg:', val);
+ if (val.match(/^('|").*\1$/)) { // string literal
+ val = val.slice(1, -1);
+ }
+ else if (val.match(/^-?\d+$/)) { // integer literal
+ val = parseInt(val, 10);
}
- else if (trimmed_val.match(/^-?\d+\.?\d*$/)) {
- // it's a number! but it's okay for it to stay a string, here.
- type = 'static';
+ else if (val.match(/^-?\d+\.\d+$/)) { // float literal
+ val = parseFloat(val);
}
- return {t: type, val: trimmed_val};
+ else if (val.match(/^\w+$/)) { // variable reference
+ val = stringEval(context, val);
+ }
+ return val;
});
- new_node.val = new_node.val.slice(0, open_parens_index);
- new_node['arguments'] = argument_array;
+ return func.apply(null, args);
}
else {
return stringEval(context, expression);
@@ -251,6 +249,10 @@ Renderer.prototype.renderTokens = function(tokens, context, callback) {
else {
(function bump() {
var value = expressionEval(context, node.val);
+ if (typeof(value) === 'function') {
+ value = value();
+ }
+
if (value === undefined && renderer.asap) {
// this.asap can be true if we want to wait,
// and false if we merely want to ignore the missing contxt variables.
@@ -1,72 +0,0 @@
-tests:
- - description: Very basic function calls
- context: |
- { status: 'paid', amount: '$314.15' }
- template: |
- {{#status.equals('owed')}}
- <span color="red">You owe {{amount}}</span>
- {{/}}
- {{#status.equals('paid')}}
- <span color="green">Thanks for paying {{amount}}!</span>
- {{/}}
- output: |
- <span color="green">Thanks for paying $314.15!</span>
- - description: String built-ins with multiple arguments
- context: |
- { phrase: 'Spitting game' }
- template: |
- {{phrase.substring(2)}}
- ;;
- {{phrase.slice(9, -2)}}
- ;;
- {{#phrase}}
- {{_.substr(-6)}}
- {{/phrase}}
- output: |
- itting game
- ;;
- ga
- ;;
- g game
- - description: Scalar sections
- context: |
- { animals: [
- {type: 'dog', color: 'Black', sound: 'Bark!'},
- {type: 'cat', color: 'White' }
- ],
- keeper: {name: 'Bob', nonspecializiation: 'dogs'}
- }
- template: |
- {{#animals}}
- Type: {{type}}
- -->
- {{#sound}}
- Sound: {{_}}
- {{/}}
- {{^sound}}
- [Silent]
- {{/}}
- {{/}}
- Keeper; {{keeper.name}}
- {{#keeper.specializiation}}
- Specialization: {{_}}
- {{/}}
- output: |
- Type: dog
- -->
- Sound: Bark!
- Type: cat
- -->
- [Silent]
- Keeper; Bob
- - description: Dynamic function arguments
- context: |
- { number: 3.141592654, precision: 2 }
- template: |
- {{number.toFixed(precision)}}
- ;;
- {{number.toFixed(5)}}
- output: |
- 3.14
- ;;
- 3.14159
View
@@ -1,64 +0,0 @@
-// var fs = require('fs'),
-// path = require('path'),
-// exec = require('child_process').exec,
-// Stream = require('stream').Stream,
-// EventEmitter = require('events').EventEmitter;
-
-// var StringStream = function() {
-// this.buffer = '';
-// this.writable = true;
-// };
-
-// StringStream.prototype = new EventEmitter();
-// StringStream.prototype.write = function(chunk) {
-// if (this.writable)
-// this.buffer += chunk;
-// else
-// throw new Error("Cannot write to unwritable StringStream.");
-// };
-// StringStream.prototype.end = function(arg0) {
-// this.writable = false;
-// this.emit('end', this.buffer);
-// };
-// StringStream.prototype.ondata = function(chunk) {
-// if (this.writable)
-// this.buffer += chunk;
-// else
-// throw new Error("Cannot write to unwritable StringStream.");
-// };
-// StringStream.prototype.onend = function() {
-// this.writable = false;
-// this.emit('end', this.buffer);
-// };
-// exports.StringStream = StringStream;
-
-// node.js sucks at reading yaml
-// exports.yaml2json = function(yaml, json, callback) {
-// if (!path.existsSync(json)) {
-// console.log("Json doesn't exist. Converting.");
-// return exec('yaml2json ' + yaml + ' > ' + json, callback);
-// }
-// else {
-// yaml_stats = fs.statSync(yaml);
-// json_stats = fs.statSync(json);
-// if (yaml_stats.mtime > json_stats.mtime) {
-// console.log('Yaml is newer than the json. Re-converting.');
-// return exec('yaml2json ' + yaml + ' > ' + json, callback);
-// }
-// }
-// return callback();
-// };
-
-// THE BELOW DOESN'T WORK!
-// function StringStream() {
-// this.buffer = '';
-// };
-// StringStream.prototype = new EventEmitter();
-// StringStream.prototype.write = function(chunk) {
-// this.buffer += chunk;
-// };
-// StringStream.prototype.end = function() {
-// };
-// StringStream.prototype.on = function(arg0, arg1) {
-// // console.log('StringStream.on', arg0, arg1);
-// };
View
@@ -0,0 +1,68 @@
+var fs = require('fs'),
+ yaml = require('js-yaml');
+ amulet = require('../lib/rendering'),
+ async = require('async'),
+ argv = require('optimist').default({'ignore-whitespace': true, extended: false}).argv;
+
+if (argv.extended) {
+ String.prototype.capitalize = function() {
+ return this.charAt(0).toUpperCase() + this.slice(1);
+ };
+ String.prototype.titleize = function() {
+ var result = [];
+ var parts = this.split(" ");
+ for (var ii in parts) {
+ result.push(capitalize(parts[ii]));
+ }
+ return result.join(" ");
+ };
+ String.prototype.humanize = function() {
+ return titleize(this.replace(/_/g, ' '));
+ };
+ String.prototype.equals = function(test) {
+ return this.valueOf() === test;
+ };
+}
+
+var successes = 0, failures = 0;
+
+function runTest(test, callback) {
+ var context = {};
+ process.stdout.write(' Spec: ' + test.description + ' ');
+ amulet.parseTemplate(test.description, test.template);
+
+ try {
+ context = eval('(' + test.context + ')');
+ }
+ catch (e) {
+ console.error('Reading context failed', e, test.context);
+ }
+
+ amulet.renderString(test.description, context, function(err, output) {
+ var matches = output == test.output;
+ if (argv['ignore-whitespace'] && !matches)
+ matches = output.replace(/\s+/g, '') == test.output.replace(/\s+/g, '');
+
+ if (matches) {
+ successes++;
+ process.stdout.write('[Success]\n');
+ }
+ else {
+ failures++;
+ process.stdout.write('[Failed]\n Expected:\n' + test.output + '\n Actual:\n' + output + '\n');
+ }
+
+ callback(err);
+ });
+}
+
+// runSpec('extended_spec.yaml');
+var full_spec = yaml.load(fs.readFileSync('local_spec.yaml', 'utf8'));
+var tests = full_spec.tests;
+if (argv.extended) {
+ tests.push.apply(tests, full_spec.extended_tests);
+}
+async.forEachSeries(tests, runTest, function(callback) {
+ var success_rate = successes / (successes + failures);
+ console.log((success_rate * 100 | 0) + '% success');
+});
Oops, something went wrong.

0 comments on commit b9f679c

Please sign in to comment.