Implemented url and regroup tags

This commit is contained in:
Anders Hellerup Madsen 2010-02-25 23:56:02 +01:00
Родитель abad5beb35
Коммит 3ccef9d7cc
7 изменённых файлов: 181 добавлений и 22 удалений

Просмотреть файл

@ -94,7 +94,8 @@ exports.makeApp = function(urls, options) {
options = options || {};
var show_404 = (options.show_404 || default_show_404);
var show_500 = (options.show_500 || default_show_500);
return function(req, res) {
var app = function(req, res) {
debuginfo.last_request = req;
debuginfo.last_response = res;
var path = url.parse(req.url)["pathname"];
@ -120,6 +121,9 @@ exports.makeApp = function(urls, options) {
show_500(req, res, e);
}
}
app.urls = {};
urls.forEach(function (item) { app.urls[item[2]] = item[0]; });
return app;
}
function default_show_404(req, res) {

Просмотреть файл

@ -1,4 +1,4 @@
var dj = require('djangode');
var dj = require('./djangode');
var app = dj.makeApp([
['^/$', function(req, res) {

Просмотреть файл

@ -23,17 +23,12 @@ NOTE:
Missing tags:
ssi (will require ALLOWED_INCLUDE_ROOTS somehow)
debug
regroup
widthratio
url
NOTE:
cycle tag does not support legacy syntax (row1,row2,row3)
load takes a path - like require. Loaded module must expose tags and filters objects.
url tag relies on app being set in process.djangode_app_config
*/
var filters = exports.filters = {
@ -590,8 +585,43 @@ var nodes = exports.nodes = {
callback(false, Math.round(current_val / max_val * constant_val) + "");
}
}
},
RegroupNode: function (item, key, name) {
return function (context, callback) {
var list = context.get(item);
if (!list instanceof Array) { callback(false, ''); }
var dict = {};
var grouped = list
.map(function (x) { return x[key]; })
.filter(function (x) { var val = dict[x]; dict[x] = x; return !val; })
.map(function (grp) {
return { grouper: grp, list: list.filter(function (o) { return o[key] === grp }) };
});
context.set(name, grouped);
callback(false, '');
}
},
UrlNode: function (url_name, replacements, item_name) {
return function (context, callback) {
var match = process.djangode_urls[context.get(url_name)]
if (!match) { return callback('no matching urls for ' + url_name_val); }
var url = string_utils.regex_to_string(match, replacements.map(function (x) { return context.get(x); }));
url = '/' + url;
if (item_name) {
context.set( item_name, url);
callback(false, '');
} else {
callback(false, url);
}
}
}
};
var tags = exports.tags = {
@ -798,5 +828,25 @@ var tags = exports.tags = {
return nodes.SpacelessNode(node_list);
},
'widthratio': simple_tag(nodes.WithRatioNode, { argcount: 3 }),
'regroup': simple_tag(nodes.RegroupNode, { argcount: 5, mustbe: { 2: 'by', 4: 'as' }, exclude: [2, 4] }),
'url': function (parser, token) {
var parts = token.split_contents();
parts.shift();
var url_name = parts.shift();
if (parts[parts.length - 2] === 'as') {
var item_name = parts.pop();
parts.pop();
}
// TODO: handle qouted strings with commas in them correctly
var replacements = parts.join('').split(/\s*,\s*/)
return nodes.UrlNode(url_name, replacements, item_name);
}
};

Просмотреть файл

@ -243,19 +243,9 @@ testcase('include')
make_parse_and_execute_test('her er en hestgiraf.', '{% include name %}');
testcase('load')
exports.filters = { testfilter: function () { return 'hestgiraf'; } }
exports.tags = {
testtag: function () {
return function (context, callback) {
callback('', 'hestgiraf')
};
}
};
make_parse_and_execute_test('hestgiraf', '{% load ./template_defaults.tags.test %}{{ 100|testfilter }}');
make_parse_and_execute_test('hestgiraf', '{% load "./template_defaults.tags.test" %}{{ 100|testfilter }}');
make_parse_and_execute_test('hestgiraf', '{% load ./template_defaults.tags.test %}{% testtag %}');
make_parse_and_execute_test('hestgiraf', '{% load ./load_tag_test %}{{ 100|testfilter }}');
make_parse_and_execute_test('hestgiraf', '{% load "./load_tag_test" %}{{ 100|testfilter }}');
make_parse_and_execute_test('hestgiraf', '{% load ./load_tag_test %}{% testtag %}');
testcase('templatetag')
make_parse_and_execute_test('{%', '{% templatetag openblock %}');
@ -275,5 +265,51 @@ testcase('widthratio')
setup(function () { return {obj:{this_value: 175, max_value: 200 } }; });
make_parse_and_execute_test('88', '{% widthratio this_value max_value 100 %}');
testcase('regroup')
setup(function () {
return {
obj: {
people: [
{'first_name': 'George', 'last_name': 'Bush', 'gender': 'Male'},
{'first_name': 'Bill', 'last_name': 'Clinton', 'gender': 'Male'},
{'first_name': 'Margaret', 'last_name': 'Thatcher', 'gender': 'Female'},
{'first_name': 'Condoleezza', 'last_name': 'Rice', 'gender': 'Female'},
{'first_name': 'Pat', 'last_name': 'Smith', 'gender': 'Unknown'}
]
}
};
});
make_parse_and_execute_test('<ul>' +
'<li>Male:<ul><li>George Bush</li><li>Bill Clinton</li></ul></li>' +
'<li>Female:<ul><li>Margaret Thatcher</li><li>Condoleezza Rice</li></ul></li>' +
'<li>Unknown:<ul><li>Pat Smith</li></ul></li></ul>',
'{% regroup people by gender as gender_list %}' +
'<ul>{% for gender in gender_list %}<li>{{ gender.grouper }}:' +
'<ul>{% for item in gender.list %}<li>{{ item.first_name }} {{ item.last_name }}</li>{% endfor %}' +
'</ul></li>{% endfor %}</ul>');
testcase('url')
setup(function () {
process.djangode_urls = {
'news-views-special_case_2003': /^articles\/2003\/$/,
'news-views-year_archive': /^articles\/(\d{4})\/$/,
'news-views-month_archive': /^articles\/(\d{4})\/(\d{2})\/$/,
'news-views-article_detail': /^articles\/(\d{4})\/(\d{2})\/(\d+)\/$/
};
return { obj: { year: 1981, month: 12, date: 2, url_name: 'news-views-article_detail' } };
});
teardown( function () {
delete process.djangode_urls;
});
make_parse_and_execute_test("/articles/2003/", "{% url 'news-views-special_case_2003' %}");
make_parse_and_execute_test("/articles/1981/", "{% url 'news-views-year_archive' 1981 %}");
make_parse_and_execute_test("/articles/1981/12/", "{% url 'news-views-month_archive' 1981 , 12 %}");
make_parse_and_execute_test("/articles/1981/12/2/", "{% url url_name year, month, date %}");
make_parse_and_execute_test("/articles/2003/",
"{% url 'news-views-special_case_2003' as the_url %}{{ the_url }}");
make_parse_and_execute_test("/articles/1981/12/",
"{% url 'news-views-month_archive' 1981, 12 as the_url %}{{ the_url }}");
run();

Просмотреть файл

@ -59,4 +59,5 @@ var app = dj.makeApp([
]);
dj.serve(app, 8009);
process.djangode_urls = app.urls;

Просмотреть файл

@ -203,4 +203,57 @@ function wordwrap (str, int_width, str_break, cut) {
exports.wordwrap = wordwrap;
// replace groups in regex like string with replacer
function replace_groups(input, replacer) {
var i, out = '', cnt = 0;
for (i = 0; i < input.length; i += 1) {
if (input[i] === '\\') {
if (cnt === 0) {
out += input[i] + input[i + 1];
}
i += 1;
continue;
}
if (cnt === 0 && input[i] !== '(') {
out += input[i];
continue;
}
if (input[i] === '(') {
cnt += 1;
} else if (input[i] === ')') {
cnt -= 1;
if (cnt === 0) {
out += replacer;
}
}
}
return out;
}
exports.regex_to_string = function (re, group_replacements) {
var s = re.toString();
// remove leading and trailing slashes
s = s.substr(1, s.length - 2);
// replace groups with '(())'
s = replace_groups(s, '(())');
// remove special chars
s = s.replace(/\^|\$|\*|\+|\?|\.|\\cX|\\xhh|\\uhhhh|\\./g, function (m) {
if (m[0] === '\\') {
if (m.substr(1).match(/f|r|n|t|v|\d+|b|s|S|w|W|d|D|b|B/)) { return ''; }
if (m.substr(1).match(/c.|x..|u..../)) { return eval("'" + m + "'"); }
return m[1];
}
return '';
});
// replace groups with replacers
s = s.replace(/\(\(\)\)/g, function () { return (group_replacements || []).shift() || ''; });
return s;
}

Просмотреть файл

@ -1,4 +1,5 @@
var sys = require('sys');
process.mixin(GLOBAL, require('./test').dsl);
process.mixin(GLOBAL, require('./string'));
@ -29,5 +30,19 @@ testcase('wrap')
test('should wrap text', function () {
assertEquals('Joel \nis a \nslug', wordwrap('Joel is a slug', 5));
});
testcase('regex_to_string')
test('should work without groups', function () {
assertEquals('hest', regex_to_string(/hest/));
assertEquals('hest', regex_to_string(/^hest$/));
assertEquals('hestgiraf', regex_to_string(/hest\s*giraf\d+/));
assertEquals('hest*', regex_to_string(/hest\*/));
assertEquals('hestgiraf', regex_to_string(/hest(tobis)giraf/));
});
test('should replace groups with input', function () {
assertEquals('shows/hest/34/', regex_to_string(/^shows\/(\w+)\/(\d+)\/$/, ['hest', 34]));
assertEquals('shows/giraf/90/', regex_to_string(/^shows\/(hest(?:laks|makrel))\/(\d+)\/$/, ['giraf', 90]));
});
run();