/
retour.cr
94 lines (89 loc) · 3.37 KB
/
retour.cr
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
module Retour
class Error < Exception
end
struct NotFound
end
macro routes(routes, default = ".+?", method = :call, decode_item = "", encode_item = "")
{% regex = [] of String %}\
{% funcs = [] of {name: String, args: Array(String), texts: Array(String)} %}\
{% for route, func, ri in routes %}\
{% brack = 0 %}\
{% escape = false %}\
{% text_start = 0 %}\
{% funcs << {name: func.id, args: args = [] of String, texts: texts = [] of String} %}\
{% if ri > 0 %}\
{% regex << "|" %}\
{% end %}\
{% regex << "(?:()" %}\
{% for c, ci in route.chars %}\
{% if escape %}\
{% escape = false %}\
{% elsif c == '\\' %}\
{% escape = true %}\
{% elsif c == '{' %}\
{% if brack == 0 %}\
{% texts << route[text_start...ci] %}\
{% regex << route[text_start...ci].gsub(/[$()*+.?[\\^{|]/, "\\\\\\0") %}\
{% regex_start = brack_start = ci + 1 %}\
{% param_end = nil %}\
{% end %}\
{% brack += 1 %}\
{% elsif c == ':' && brack > 0 && param_end == nil %}\
{% param_end = ci %}\
{% regex_start = ci + 1 %}\
{% elsif c == '}' %}\
{% brack -= 1 %}\
{% if brack < 0 %}\
{% raise "Too many closing curly braces in this route (at position #{ci}):\n#{route.id}" %}\
{% end %}\
{% if brack == 0 %}\
{% if param_end == nil %}\
{% param_end = ci %}\
{% re = default %}\
{% else %}\
{% re = route[regex_start...ci] %}\
{% end %}\
{% regex << "(" << re << ")" %}\
{% unless brack_start < param_end %}\
{% raise "Empty parameter name in this route (at position #{param_end}):\n#{route.id}" %}\
{% end %}\
{% args << route[brack_start...param_end].id %}\
{% text_start = ci + 1 %}\
{% end %}\
{% end %}\
{% end %}\
{% texts << route[text_start..-1] %}\
{% regex << route[text_start..-1].gsub(/[$()*+.?[\\^{|]/, "\\\\\\0") %}\
{% regex << ")" %}\
{% if brack > 0 %}\
{% raise "Too many opening curly braces in this route (at position #{brack_start}):\n#{route.id}" %}\
{% end %}\
{% end %}\
{% for func in funcs %}\
def self.gen_{{ func[:name] }}({% for arg, i in func[:args] %}{{ arg }} a{{ i + 1 }}, {% end %}) : String
String.interpolation({% for text, i in func[:texts] %}{% if i > 0 %}({{encode_item.id}} a{{ i }}), {% end %}{{ text }}, {% end %})
end
{% end %}\
{% gi = 0 %}
def {{ method.id }}(input : String, *args, **kwargs)
{% if regex.empty? %}\
{% regex = "@^" %} # Never matches
return Retour::NotFound.new
{% else %}
{% regex = "(?:" + regex.join("") + ")" %}
if !(m = %r(\A(?:{{ regex.id }})\Z).match(input))
return Retour::NotFound.new
{% for func in funcs %}\
elsif m[{{ gi += 1 }}]?
{{ func[:name] }}(*args, **kwargs{% for arg in func[:args] %}, {{ arg }}: ({{decode_item.id}} m[{{ gi += 1 }}]){% end %})
{% end %}\
else
raise Retour::Error.new("BUG: Retour regex matched but didn't find any group")
end
{% end %}\
end
def self.{{ method.id }}_regex : Regex
%r({{ regex.id }})
end
end
end