Skip to content

Instantly share code, notes, and snippets.

@rsky
Created February 22, 2014 07:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rsky/9150200 to your computer and use it in GitHub Desktop.
Save rsky/9150200 to your computer and use it in GitHub Desktop.
Export Django's django.core.urlresolvers.reverse as JavaScript and CoffeeScript
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import json
import os
import re
from optparse import make_option
from collections import OrderedDict
from django.core.urlresolvers import get_urlconf, get_resolver
from django.core.management.base import BaseCommand
from django.utils.encoding import force_text
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
make_option('--language', action='store', dest='language', default='json',
choices=('coffee', 'js', 'json', 'java', 'objc')),
)
def handle(self, *args, **options):
language = options.get('language')
urlconf = get_urlconf()
resolver = get_resolver(urlconf)
named_capture_pattern = re.compile(r'\(\?P<\w+>')
tmp = {}
for view, (possibility, pattern, defaults) in resolver.reverse_dict.iteritems():
if isinstance(view, basestring):
view_name = view
elif hasattr(view, '__name__'):
view_name = view.__name__
else:
view_name = force_text(view)
tmp[view_name] = [possibility, named_capture_pattern.sub('(', pattern)]
config = OrderedDict()
for k in sorted(tmp.keys()):
config[k] = tmp[k]
code = getattr(self, 'export_to_' + language)(config)
print(code)
def export_to_coffee(self, config):
config_json = self.export_to_json(config, indent=None)
return self.read_template('reverse.coffee').replace('__CONFIG__', config_json)
def export_to_js(self, config):
config_json = self.export_to_json(config, indent=None)
return self.read_template('reverse.js').replace('__CONFIG__', config_json)
def export_to_json(self, config, indent=2):
return json.dumps(config, indent=indent, sort_keys=True)
def export_to_java(self, config):
raise NotImplementedError()
def export_to_objc(self, config):
raise NotImplementedError()
def read_template(self, filename):
template = os.path.join(os.path.dirname(__file__), 'export_reverse', filename)
return open(template, 'r').read()
config = __CONFIG__
typeIsArray = (value) ->
value and
typeof value is 'object' and
value instanceof Array and
typeof value.length is 'number' and
typeof value.splice is 'function' and
not (value.propertyIsEnumerable 'length')
paramsFromArray = (args, candidate_params) ->
len = args.length
if len != candidate_params.length
return null
params = {}
for key, idx in candidate_params
params[key] = args[idx]
return params
paramsFromObject = (args, candidate_params) ->
len = Object.keys(args).length
if len != candidate_params.length
return null
params = {}
for key in candidate_params
if key of args
params[key] = args[key]
else
return null
return params
reverse = (name, args) ->
if name not of config
return null
possibility = config[name][0]
pattern = new RegExp '^' + config[name][1]
for candidate in possibility
candidate_result = candidate[0]
candidate_params = candidate[1]
if candidate_params.length == 0
if not args
return candidate_result
else
if typeIsArray args
params = paramsFromArray(args, candidate_params)
else
params = paramsFromObject(args, candidate_params)
if not params
continue
replacer = (all, percents, key) ->
percents_count = percents.length
if percents_count % 2 == 0
return all
if percents_count > 2
prefix = Array((percents_count - 1) / 2).join '%'
else
prefix = ''
return encodeURIComponent prefix + params[key]
result = candidate_result.replace(/(%+)\((\w+)\)s/g, replacer)
if pattern.test result
return result
return null
module.exports = reverse
var reverse = (function() {
var config, paramsFromArray, paramsFromObject, reverse, typeIsArray;
config = __CONFIG__;
typeIsArray = function(value) {
return value && typeof value === 'object' && value instanceof Array && typeof value.length === 'number' && typeof value.splice === 'function' && !(value.propertyIsEnumerable('length'));
};
paramsFromArray = function(args, candidate_params) {
var idx, key, len, params, _i, _len;
len = args.length;
if (len !== candidate_params.length) {
return null;
}
params = {};
for (idx = _i = 0, _len = candidate_params.length; _i < _len; idx = ++_i) {
key = candidate_params[idx];
params[key] = args[idx];
}
return params;
};
paramsFromObject = function(args, candidate_params) {
var key, len, params, _i, _len;
len = Object.keys(args).length;
if (len !== candidate_params.length) {
return null;
}
params = {};
for (_i = 0, _len = candidate_params.length; _i < _len; _i++) {
key = candidate_params[_i];
if (key in args) {
params[key] = args[key];
} else {
return null;
}
}
return params;
};
reverse = function(name, args) {
var candidate, candidate_params, candidate_result, params, pattern, possibility, replacer, result, _i, _len;
if (!(name in config)) {
return null;
}
possibility = config[name][0];
pattern = new RegExp('^' + config[name][1]);
for (_i = 0, _len = possibility.length; _i < _len; _i++) {
candidate = possibility[_i];
candidate_result = candidate[0];
candidate_params = candidate[1];
if (candidate_params.length === 0) {
if (!args) {
return candidate_result;
}
} else {
if (typeIsArray(args)) {
params = paramsFromArray(args, candidate_params);
} else {
params = paramsFromObject(args, candidate_params);
}
if (!params) {
continue;
}
replacer = function(all, percents, key) {
var percents_count, prefix;
percents_count = percents.length;
if (percents_count % 2 === 0) {
return all;
}
if (percents_count > 2) {
prefix = Array((percents_count - 1) / 2).join('%');
} else {
prefix = '';
}
return encodeURIComponent(prefix + params[key]);
};
result = candidate_result.replace(/(%+)\((\w+)\)s/g, replacer);
if (pattern.test(result)) {
return result;
}
}
}
return null;
};
return reverse;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment