1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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
|