-
Notifications
You must be signed in to change notification settings - Fork 46
/
controller.cr
159 lines (138 loc) · 4.51 KB
/
controller.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
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
module Amethyst
module Base
abstract class Controller
getter :actions
property :request
property :response
property :body
getter :params
include Support::ControllerHelpers
include Sugar::View
include Support::Sendable
class Formatter
getter :processed
def initialize(request : Http::Request, response : Http::Response)
@response = response
@request = request
@processed = false
end
# Do stuff in block if client accepts text/html
def html(&block)
if @request.accept == "text/html"
@response.status = 200
@response.header "Content-type", "text/html"
yield
@processed = true
end
end
def any(&block)
@response.status = 200
@response.header "Content-type", "text/html"
yield
@processed = true
end
end
def body
response.body
end
def session
session_id = request.cookies["sid"]
return Base::App.session.get_session(session_id)
end
def destroy_session
session_id = request.cookies["sid"]
return Base::App.session.destroy_session(session_id)
end
# This hack creates procs from controller actions, and adds it to the @actions
macro actions(*actions)
private def add_actions
{% for action in actions %}
@actions[{{action}}.to_s] = ->{{action.id}}
{% end %}
end
end
macro register_action_callbacks
{% method_names = @type.methods.map(&.name.stringify) %}
{% callbacks = method_names.select do |name|
name.starts_with?("_before_") || name.starts_with?("_after_")
end %}
def action_callbacks
{% for method in callbacks %}
{{method.id}}
{% end %}
end
end
macro before_action(callback, only = [] of Symbol)
{% if only.empty? %}
{% only = ["all"] %}
{% end %}
{% for action in only %}
def _before_{{action.id}}_{{callback.id}}
@before_callbacks["{{action.id}}"] = [] of (-> Array(String)) unless @before_callbacks["{{action.id}}"]?
@before_callbacks["{{action.id}}"] << ->{{callback.id}}
end
{% end %}
register_action_callbacks
end
macro after_action(callback, only = [] of Symbol)
{% if only.empty? %}
{% only = ["all"] %}
{% end %}
{% for action in only %}
def _after_{{action.id}}_{{callback.id}}
@after_callbacks["{{action.id}}"] = [] of (-> Array(String)) unless @after_callbacks["{{action.id}}"]?
@after_callbacks["{{action.id}}"] << ->{{callback.id}}
end
{% end %}
register_action_callbacks
end
# Creates a hash for controller actions
# Then, invokes actions method to add actions to the hash
def initialize
@request = Http::Request.new(HTTP::Request.new("", ""))
@response = Http::Response.new
@actions = {} of String => ->
add_actions
@before_callbacks = {} of String => Array(Proc(Array(String)))
@after_callbacks = {} of String => Array(Proc(Array(String)))
action_callbacks
end
def params
request.parameters
end
def set_env(@request, @response)
end
def respond_to(&block)
formatter = Formatter.new(@request, @response)
yield formatter
raise Exceptions::HttpBadRequest.new unless formatter.processed
end
# Works like Ruby's send(:method) to invoke controller action:
# NameController.call_action("show")
def call_action(action)
raise Exceptions::ControllerActionNotFound.new(action, self.class.name) unless @actions.has_key? action
if do_callbacks @before_callbacks, action
@actions[action].call
do_callbacks @after_callbacks, action
end
@response
end
def to_s(io : IO)
msg = "self.name\n"
@actions.each do |action|
msg += "#{action}\n"
end
io << msg
end
private def do_callbacks(callbacks, action)
[callbacks[action.to_s]?, callbacks["all"]?].compact.each do |callbacks|
callbacks.each do |callback|
return false unless callback.call
end
end
true
end
end
end
end
# TODO: Implement Http errors handling middleware