Browse files

Added more filters.

  • Loading branch information...
1 parent b5c437e commit baf18d604c5507fecf6e5b4e96b8bb6459a0e0f0 Anders Hellerup Madsen committed Dec 13, 2009
Showing with 237 additions and 31 deletions.
  1. +30 −0 regression.py
  2. +4 −3 template/template.js
  3. +6 −0 template/template.test.js
  4. +125 −27 template/template_defaults.js
  5. +61 −0 template/template_defaults.test.js
  6. +7 −1 utils/string.js
  7. +4 −0 utils/test.js
View
30 regression.py
@@ -0,0 +1,30 @@
+#!/usr/bin/python
+import re, os
+
+print ""
+
+cmd = 'find . -name "*.test.js"';
+files = [file.rstrip('\n') for file in os.popen(cmd).readlines()]
+
+failed_list = []
+
+for file in files:
+ output = os.popen('node ' + file).readlines()
+ result = [line.rstrip('\n') for line in output if line.startswith('Total')][0]
+ (total, failed, error) = re.split(r':|,', result)[1::2]
+
+ if int(failed) > 0 or int(error) > 0:
+ failed_list.append(file)
+
+ print file
+ print '\t', result
+
+if failed_list:
+ print '\nWARNING! There were failed tests:'
+ for file in failed_list:
+ print file
+ print ""
+ exit(1)
+print ""
+exit(0)
+
View
7 template/template.js
@@ -17,8 +17,9 @@ function tokenize(input) {
function consume_until() {
var next, s = '';
+ var slice = Array.prototype.slice;
while (next = consume(re, input)) {
- if (Array.prototype.slice.apply(arguments).indexOf(next) > -1) {
+ if (slice.apply(arguments).indexOf(next) > -1) {
return [s, next];
}
s += next;
@@ -101,7 +102,7 @@ process.mixin(Parser.prototype, {
callback = this.callbacks[token.type];
if (callback && typeof callback === 'function') {
- node_list.push( callback.call(null, this, token) );
+ node_list.push( callback(this, token) );
} else {
//throw parser_error('Unknown tag: ' + token[0]);
node_list.push( template_defaults.TextNode('[[ UNKNOWN ' + token.type + ' ]]'));
@@ -131,7 +132,7 @@ function normalize(value) {
if (value === 'true') { return true; }
if (value === 'false') { return false; }
- if (/^\d/.exec(value)) { return Number(value); }
+ if (/^\d/.exec(value)) { return value - 0; }
var isStringLiteral = /^(["'])(.*?)\1$/.exec(value);
if (isStringLiteral) { return isStringLiteral.pop(); }
View
6 template/template.test.js
@@ -102,8 +102,14 @@ testcase('Context test');
});
test('test push and pop', function (tc) {
+ assertEquals(tc.plain.a, tc.context.get('a'));
+
tc.context.push();
+
assertEquals(tc.plain.a, tc.context.get('a'));
+ tc.context.set('a', tc.plain.a + 18);
+ assertEquals(tc.plain.a + 18, tc.context.get('a'));
+
tc.context.pop();
assertEquals(tc.plain.a, tc.context.get('a'));
});
View
152 template/template_defaults.js
@@ -1,24 +1,59 @@
+"use strict";
/*jslint laxbreak: true, eqeqeq: true, undef: true, regexp: false */
/*global require, process, exports */
-var sys = require('sys');
+var sys = require('sys')
+
var template = require('./template');
var utils = require('../utils/utils');
+/* TODO: Missing filters
+
+ Don't know how:
+ iriencode
+
+ Autoescaping:
+ escape
+ safe
+ safeseq
+
+ Not implemented (yet):
+ slugify
+ stringformat
+ striptags
+ time
+ timesince
+ timeuntil
+ title
+ truncatewords
+ truncatewords_html
+ unordered_list
+ upper
+ urlencode
+ urlize
+ urlizetrunc
+ wordcount
+ wordwrap
+ yesno
+
+*/
var filters = exports.filters = {
- add: function (value, arg) { return (typeof value === 'number' && typeof arg === 'number') ? (value + arg) : ''; },
- addslashes: function (value, arg) { return utils.string.add_slashes(value.toString()); },
- capfirst: function (value, arg) { return utils.string.cap_first(value.toString()); },
- center: function (value, arg) { return utils.string.center(value.toString(), arg); },
- cut: function (value, arg) { return value.toString().replace(new RegExp(arg, 'g'), ""); },
+ add: function (value, arg) {
+ value = value - 0, arg = arg - 0;
+ return (isNaN(value) || isNaN(arg)) ? '' : (value + arg);
+ },
+ addslashes: function (value, arg) { return utils.string.add_slashes("" + value); },
+ capfirst: function (value, arg) { return utils.string.cap_first("" + value); },
+ center: function (value, arg) { return utils.string.center("" + value, arg); },
+ cut: function (value, arg) { return ("" + value).replace(new RegExp(arg, 'g'), ""); },
date: function (value, arg) { return (value instanceof Date) ? utils.date.date(arg, value) : ''; },
'default': function (value, arg) { return value ? value : arg; },
default_if_none: function (value, arg) { return (value === null || value === undefined) ? arg : value; },
dictsort: function (value, arg) {
var clone = value.slice(0);
- clone.sort(function (a, b) { return a[arg] < b[arg] ? -1 : a[arg] > b[arg] ? 1 : 0 });
+ clone.sort(function (a, b) { return a[arg] < b[arg] ? -1 : a[arg] > b[arg] ? 1 : 0; });
return clone;
},
@@ -35,7 +70,7 @@ var filters = exports.filters = {
},
escapejs: function (value, arg) { return escape(value || ''); },
filesizeformat: function (value, arg) {
- var bytes = Number(value);
+ var bytes = value - 0;
if (isNaN(bytes)) { return "0 bytes"; }
if (bytes <= 1) { return '1 byte'; }
if (bytes < 1024) { return bytes.toFixed(0) + ' bytes'; }
@@ -44,27 +79,27 @@ var filters = exports.filters = {
return (bytes / (1024 * 1024 * 1024)).toFixed(1) + 'GB';
},
first: function (value, arg) { return (value instanceof Array) ? value[0] : ""; },
- fix_ampersands: function (value, arg) { return value.toString().replace('&', '&amp;'); },
+ fix_ampersands: function (value, arg) { return ("" + value).replace('&', '&amp;'); },
floatformat: function (value, arg) {
- var num = Number(value),
- arg = arg || -1,
- show_zeores = arg > 0,
+ arg = arg || -1;
+ var num = value - 0,
+ show_zeroes = arg > 0,
fix = Math.abs(arg);
if (isNaN(num)) {
return '';
}
var s = num.toFixed(fix);
- if (!show_zeores && Number(s) % 1 === 0) {
+ if (!show_zeroes && s % 1 === 0) {
return num.toFixed(0);
}
return s;
},
- force_escape: function (value, arg) { return utils.html.escape(value.toString()); },
+ force_escape: function (value, arg) { return utils.html.escape("" + value); },
get_digit: function (value, arg) {
if (typeof value !== 'number' || typeof arg !== 'number' || typeof arg < 1) { return value; }
- var s = value.toString();
- return Number(s[s.length - arg]);
+ var s = "" + value;
+ return s[s.length - arg] - 0;
},
iriencode: function (value, arg) {
// TODO: implement iriencode filter
@@ -74,26 +109,90 @@ var filters = exports.filters = {
last: function (value, arg) { return (value instanceof Array && value.length) ? value[value.length - 1] : ''; },
length: function (value, arg) { return value.hasOwnProperty('length') ? value.length : 0; },
length_is: function (value, arg) { return value.hasOwnProperty('length') && value.length === arg; },
- linebreaks: function (value, arg) { return utils.html.linebreaks(value.toString()); },
- linebreaksbr: function (value, arg) { return value.toString().replace(/\n/g, '<br />'); },
+ linebreaks: function (value, arg) { return utils.html.linebreaks("" + value); },
+ linebreaksbr: function (value, arg) { return "" + value.replace(/\n/g, '<br />'); },
linenumbers: function (value, arg) {
- var lines = value.toString().split('\n');
- var zeroes = new Array(lines.length.toString().length + 1).join('0');
+ var lines = ("" + value).split('\n');
+ var zeroes = "", len = ("" + lines.length).length;
+ while (len--) { zeroes += "0"; }
+
lines = lines.map( function (s, idx) {
- var num = (idx + 1).toString();
+ var num = "" + (idx + 1);
return zeroes.slice(0, zeroes.length - num.length) + num + '. ' + s;
});
return lines.join('\n');
},
ljust: function (value, arg) {
if (typeof arg !== 'number') { return ''; }
if (arg <= value.length) { return value.slice(0, arg); }
- var spaces = new Array(arg + 1).join(' ');
- return value + spaces.slice(0, arg - value.length);
+
+ var spaces = "", len = arg - value.length;
+ while (len--) { spaces += ' '; }
+ return value + spaces;
},
lower: function (value, arg) { return typeof value === 'string' ? value.toLowerCase() : ''; },
+ make_list: function (value, arg) { return String(value).split(''); },
+ phone2numeric: function (value, arg) {
+ value = String(value).toLowerCase();
+ return value.replace(/[a-pr-y]/g, function (x) {
+ var code = x.charCodeAt(0) - 91;
+ if (code > 22) { code = code - 1; }
+ return Math.floor(code / 3);
+ });
+ },
+ pluralize: function (value, arg) {
+ value = Number(value);
+ var plural = arg ? String(arg).split(',') : ['', 's'];
+ if (plural.length === 1) { plural.unshift(''); }
+ if (isNaN(value)) { return ''; }
+ return value === 1 ? plural[0] : plural[1];
+ },
+ pprint: function (value, arg) { return JSON.stringify(value); },
+ random: function (value, arg) {
+ return (value instanceof Array) ? value[ Math.floor( Math.random() * 4 ) ] : '';
+ },
+ removetags: function (value, arg) {
+ return String(value).replace(/<(.|\n)*?>/g, '');
+ },
+ rjust: function (value, arg) {
+ if (typeof arg !== 'number') { return ''; }
+ if (arg <= value.length) { return value.slice(0, arg); }
+
+ var spaces = "", len = arg - value.length;
+ while (len--) { spaces += ' '; }
+ return spaces + value;
+ },
+ safe: function (value, arg) {
+ // TODO: implement autoescaping
+ throw "safe is not implemented";
+ },
+ safeseq: function (value, arg) {
+ // TODO: implement autoescaping
+ throw "safeseq is not implemented";
+ },
+ slice: function (value, arg) {
+ if (!(value instanceof Array)) { return []; }
+ var parts = (arg || '').split(/:/g);
+
+ if (parts[1] === '') {
+ parts[1] = value.length;
+ }
+ parts = parts.map(Number);
+
+ if (!parts[2]) {
+ return value.slice(parts[0], parts[1]);
+ }
+ var out = [], i = parts[0], end = parts[1];
+ for (;i < end; i += parts[2]) {
+ out.push(value[i]);
+ }
+ return out;
+
+ },
+ title: function (value, arg) {
+ throw "Not implemented"; /* http://ejohn.org/blog/title-capitalization-in-javascript/ */
+ }
- sub: function (value, arg) { return value - arg; }
};
@@ -181,7 +280,7 @@ var callbacks = exports.callbacks = {
var parts = template.split_token(token.contents);
if (parts[0] !== 'for' || parts[2] !== 'in' || (parts[4] && parts[4] !== 'reversed')) {
- throw 'unexpected syntax in "for" tag' + sys.inspect(parts);
+ throw 'unexpected syntax in "for" tag: ' + token.contents;
}
var itemname = parts[1],
@@ -232,10 +331,9 @@ var callbacks = exports.callbacks = {
node_list = parser.parse('else', 'endif');
if (parser.next_token().type === 'else') {
else_list = parser.parse('endif');
+ parser.delete_first_token();
}
- parser.delete_first_token();
-
return nodes.IfNode(item_names, not_item_names, operator, node_list, else_list);
}
};
View
61 template/template_defaults.test.js
@@ -5,6 +5,7 @@ process.mixin(GLOBAL, require('./template_defaults'));
testcase('add')
test('should add correctly', function () {
assertEquals(6, filters.add(4, 2));
+ assertEquals(6, filters.add('4', 2));
assertEquals('', filters.add('a', 2));
assertEquals('', filters.add(2, 'a'));
});
@@ -209,6 +210,66 @@ testcase('lower')
assertEquals('somewhere over the rainbow', filters.lower('Somewhere Over the Rainbow'));
assertEquals('', filters.lower(19));
});
+testcase('make_list');
+ test('work as expected', function () {
+ assertEquals(['J', 'o', 'e', 'l'], filters.make_list('Joel'));
+ assertEquals(['1', '2', '3'], filters.make_list('123'));
+ });
+testcase('phone2numeric')
+ test('convert letters to numbers phone number style', function () {
+ assertEquals('800-2655328', filters.phone2numeric('800-COLLECT'));
+ assertEquals('2223334445556667q77888999z', filters.phone2numeric('abcdefghijklmnopqrstuvwxyz'));
+ });
+testcase('pluralize');
+ test('pluralize correctly', function() {
+ assertEquals('', filters.pluralize('sytten'));
+ assertEquals('', filters.pluralize(1));
+ assertEquals('s', filters.pluralize(2));
+ assertEquals('', filters.pluralize(1, 'es'));
+ assertEquals('es', filters.pluralize(2, 'es'));
+ assertEquals('y', filters.pluralize(1, 'y,ies'));
+ assertEquals('ies', filters.pluralize(2, 'y,ies'));
+ });
+testcase('pprint');
+ test("should not throw and not return ''", function () {
+ var response = filters.pprint( filters );
+ if (!response) { fail('response is empty!'); }
+ });
+testcase('random');
+ test('should return an element from the list', function () {
+ var arr = ['h', 'e', 's', 't'];
+ var response = filters.random(arr);
+ if (arr.indexOf(response) < 0) {
+ fail('returned element not in array!');
+ }
+ });
+ test('should return empty string when passed non array', function () {
+ assertEquals('', filters.random( 25 ));
+ });
+testcase('removetags');
+ test('should remove tags', function () {
+ assertEquals('jeg har en dejlig hest.', filters.removetags('<p>jeg har en <strong\n>dejlig</strong> hest.</p>'));
+ });
+testcase('rjust')
+ test('should right justify value in correctly sized field', function () {
+ assertEquals(' hest', filters.rjust('hest', 10));
+ assertEquals('', filters.rjust('hest'));
+ assertEquals('he', filters.rjust('hest', 2));
+ });
+testcase('slice')
+ var arr = [0,1,2,3,4,5,6,7,8,9];
+ test('slice should slice like python', function () {
+ assertEquals([0,1,2,3], filters.slice(arr, ":4"));
+ assertEquals([6,7,8,9], filters.slice(arr, "6:"));
+ assertEquals([2,3,4], filters.slice(arr, "2:5"));
+ assertEquals([2,5,8], filters.slice(arr, "2::3"));
+ assertEquals([2,5], filters.slice(arr, "2:6:3"));
+ });
+ test('slice should handle bad values', function () {
+ assertEquals([], filters.slice(36, ":4"));
+ assertEquals([0,1,2,3,4,5,6,7,8,9], filters.slice(arr, 'hest'));
+ assertEquals([0,1,2,3,4,5,6,7,8,9], filters.slice(arr));
+ });
run();
View
8 utils/string.js
@@ -44,7 +44,13 @@ function center(s, width) {
if (s.length > width) { return s; }
var right = Math.round((width - s.length) / 2);
var left = width - (s.length + right);
- return (new Array(left + 1)).join(' ') + s + (new Array(right + 1)).join(' ');
+ var out = '';
+
+ while (left--) { out += ' '; }
+ out += s;
+ while (right--) { out += ' '; }
+
+ return out;
}
exports.center = center;
View
4 utils/test.js
@@ -129,6 +129,10 @@ exports.dsl = {
} catch (e) {
throw new AssertFailedException('Caught <' + e + '>');
}
+ },
+
+ fail: function (message) {
+ throw new AssertFailedException(message);
}
};

0 comments on commit baf18d6

Please sign in to comment.