Created
February 22, 2014 07:56
-
-
Save rsky/9150200 to your computer and use it in GitHub Desktop.
Export Django's django.core.urlresolvers.reverse as JavaScript and CoffeeScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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