diff options
Diffstat (limited to 'third_party/python/json-e/jsone/builtins.py')
-rw-r--r-- | third_party/python/json-e/jsone/builtins.py | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/third_party/python/json-e/jsone/builtins.py b/third_party/python/json-e/jsone/builtins.py new file mode 100644 index 0000000000..751ee2dc04 --- /dev/null +++ b/third_party/python/json-e/jsone/builtins.py @@ -0,0 +1,121 @@ +from __future__ import absolute_import, print_function, unicode_literals + +import math +from .shared import string, to_str, fromNow, JSONTemplateError + + +class BuiltinError(JSONTemplateError): + pass + + +def build(context): + builtins = {} + + def builtin(name, variadic=None, argument_tests=None, minArgs=None): + def wrap(fn): + def bad(reason=None): + raise BuiltinError( + (reason or 'invalid arguments to builtin: {}').format(name)) + if variadic: + def invoke(*args): + if minArgs: + if len(args) < minArgs: + bad("too few arguments to {}") + for arg in args: + if not variadic(arg): + bad() + return fn(*args) + + elif argument_tests: + def invoke(*args): + if len(args) != len(argument_tests): + bad() + for t, arg in zip(argument_tests, args): + if not t(arg): + bad() + return fn(*args) + + else: + def invoke(*args): + return fn(*args) + + builtins[name] = invoke + return fn + return wrap + + def is_number(v): + return isinstance(v, (int, float)) and not isinstance(v, bool) + + def is_string(v): + return isinstance(v, string) + + def is_string_or_array(v): + return isinstance(v, (string, list)) + + def anything_except_array(v): + return isinstance(v, (string, int, float, bool)) or v is None + + def anything(v): + return isinstance(v, (string, int, float, list, dict)) or v is None or callable(v) + + # --- + + builtin('min', variadic=is_number, minArgs=1)(min) + builtin('max', variadic=is_number, minArgs=1)(max) + builtin('sqrt', argument_tests=[is_number])(math.sqrt) + builtin('abs', argument_tests=[is_number])(abs) + + @builtin('ceil', argument_tests=[is_number]) + def ceil(v): + return int(math.ceil(v)) + + @builtin('floor', argument_tests=[is_number]) + def floor(v): + return int(math.floor(v)) + + @builtin('lowercase', argument_tests=[is_string]) + def lowercase(v): + return v.lower() + + @builtin('uppercase', argument_tests=[is_string]) + def lowercase(v): + return v.upper() + + builtin('len', argument_tests=[is_string_or_array])(len) + builtin('str', argument_tests=[anything_except_array])(to_str) + builtin('number', variadic=is_string, minArgs=1)(float) + + @builtin('strip', argument_tests=[is_string]) + def strip(s): + return s.strip() + + @builtin('rstrip', argument_tests=[is_string]) + def rstrip(s): + return s.rstrip() + + @builtin('lstrip', argument_tests=[is_string]) + def lstrip(s): + return s.lstrip() + + @builtin('fromNow', variadic=is_string, minArgs=1) + def fromNow_builtin(offset, reference=None): + return fromNow(offset, reference or context.get('now')) + + @builtin('typeof', argument_tests=[anything]) + def typeof(v): + if isinstance(v, bool): + return 'boolean' + elif isinstance(v, string): + return 'string' + elif isinstance(v, (int, float)): + return 'number' + elif isinstance(v, list): + return 'array' + elif isinstance(v, dict): + return 'object' + elif v is None: + return None + elif callable(v): + return 'function' + + return builtins |