line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Pinwheel::Controller; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
598
|
use strict; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
150
|
|
4
|
4
|
|
|
4
|
|
28
|
use warnings; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
97
|
|
5
|
|
|
|
|
|
|
|
6
|
4
|
|
|
4
|
|
23
|
use Carp; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
421
|
|
7
|
4
|
|
|
4
|
|
23
|
use Exporter; |
|
4
|
|
|
|
|
36
|
|
|
4
|
|
|
|
|
205
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
require File::Find; |
10
|
4
|
|
|
4
|
|
4340
|
use File::Slurp; |
|
4
|
|
|
|
|
81917
|
|
|
4
|
|
|
|
|
391
|
|
11
|
4
|
|
|
4
|
|
46
|
use Scalar::Util qw(blessed); |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
449
|
|
12
|
|
|
|
|
|
|
|
13
|
4
|
|
|
4
|
|
1905
|
use Pinwheel::Context; |
|
4
|
|
|
|
|
22
|
|
|
4
|
|
|
|
|
102
|
|
14
|
4
|
|
|
4
|
|
2309
|
use Pinwheel::Database; |
|
4
|
|
|
|
|
12
|
|
|
4
|
|
|
|
|
171
|
|
15
|
4
|
|
|
4
|
|
2172
|
use Pinwheel::Helpers; |
|
4
|
|
|
|
|
14
|
|
|
4
|
|
|
|
|
181
|
|
16
|
4
|
|
|
4
|
|
2245
|
use Pinwheel::Mapper; |
|
4
|
|
|
|
|
14
|
|
|
4
|
|
|
|
|
145
|
|
17
|
4
|
|
|
4
|
|
32
|
use Pinwheel::Model::Time; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
91
|
|
18
|
4
|
|
|
4
|
|
2569
|
use Pinwheel::View::Data; |
|
4
|
|
|
|
|
16
|
|
|
4
|
|
|
|
|
187
|
|
19
|
4
|
|
|
4
|
|
2807
|
use Pinwheel::View::ERB; |
|
4
|
|
|
|
|
17
|
|
|
4
|
|
|
|
|
23547
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
22
|
|
|
|
|
|
|
our @EXPORT = qw( |
23
|
|
|
|
|
|
|
url_for |
24
|
|
|
|
|
|
|
redirect_to |
25
|
|
|
|
|
|
|
render |
26
|
|
|
|
|
|
|
render_to_string |
27
|
|
|
|
|
|
|
render_404 |
28
|
|
|
|
|
|
|
render_500 |
29
|
|
|
|
|
|
|
set_header |
30
|
|
|
|
|
|
|
expires_in |
31
|
|
|
|
|
|
|
expires_at |
32
|
|
|
|
|
|
|
expires_now |
33
|
|
|
|
|
|
|
accepts |
34
|
|
|
|
|
|
|
respond_to |
35
|
|
|
|
|
|
|
params |
36
|
|
|
|
|
|
|
query_params |
37
|
|
|
|
|
|
|
); |
38
|
|
|
|
|
|
|
our @EXPORT_OK = qw( |
39
|
|
|
|
|
|
|
connect |
40
|
|
|
|
|
|
|
dispatch |
41
|
|
|
|
|
|
|
format |
42
|
|
|
|
|
|
|
set_base_format |
43
|
|
|
|
|
|
|
set_format_param |
44
|
|
|
|
|
|
|
expand_static_path |
45
|
|
|
|
|
|
|
set_static_root |
46
|
|
|
|
|
|
|
set_templates_root |
47
|
|
|
|
|
|
|
request_time |
48
|
|
|
|
|
|
|
request_time_model |
49
|
|
|
|
|
|
|
); |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
our $map = new Pinwheel::Mapper; |
53
|
|
|
|
|
|
|
our $static_root = '.'; |
54
|
|
|
|
|
|
|
our $templates_root = '.'; |
55
|
|
|
|
|
|
|
our %template_types = ( |
56
|
|
|
|
|
|
|
'tmpl' => \&Pinwheel::View::ERB::parse_template, |
57
|
|
|
|
|
|
|
'erb' => \&Pinwheel::View::ERB::parse_template, |
58
|
|
|
|
|
|
|
'data' => \&Pinwheel::View::Data::parse_template, |
59
|
|
|
|
|
|
|
); |
60
|
|
|
|
|
|
|
our $format_param = 'format'; |
61
|
|
|
|
|
|
|
our %format_defaults = ( |
62
|
|
|
|
|
|
|
'atom' => { content_type => 'application/atom+xml', layout => 0 }, |
63
|
|
|
|
|
|
|
'css' => { content_type => 'text/css', layout => 0 }, |
64
|
|
|
|
|
|
|
'gif' => { content_type => 'image/gif', layout => 0 }, |
65
|
|
|
|
|
|
|
'html' => { content_type => 'text/html' }, |
66
|
|
|
|
|
|
|
'ics' => { content_type => 'text/calendar', layout => 0 }, |
67
|
|
|
|
|
|
|
'json' => { content_type => 'application/json', layout => 0 }, |
68
|
|
|
|
|
|
|
'mp' => { content_type => 'text/html' }, |
69
|
|
|
|
|
|
|
'ram' => { content_type => 'audio/x-pn-realaudio', layout => 0 }, |
70
|
|
|
|
|
|
|
'rdf' => { content_type => 'application/rdf+xml' }, |
71
|
|
|
|
|
|
|
'rss' => { content_type => 'application/rss+xml', layout => 0 }, |
72
|
|
|
|
|
|
|
'ssi' => { content_type => 'text/plain', layout => 0 }, |
73
|
|
|
|
|
|
|
'sssi' => { content_type => 'text/html', layout => 0 }, |
74
|
|
|
|
|
|
|
'txt' => { content_type => 'text/plain', layout => 0 }, |
75
|
|
|
|
|
|
|
'wml' => { content_type => 'text/vnd.wap.wml' }, |
76
|
|
|
|
|
|
|
'xml' => { content_type => 'application/xml', layout => 0 }, |
77
|
|
|
|
|
|
|
'yaml' => { content_type => 'application/x-yaml', layout => 0 }, |
78
|
|
|
|
|
|
|
); |
79
|
|
|
|
|
|
|
our $error_logger = \&default_error_logger; |
80
|
|
|
|
|
|
|
our (%template_cache, %controllers, $layout_helpers); |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub initialise |
84
|
|
|
|
|
|
|
{ |
85
|
1
|
|
|
1
|
0
|
947
|
my ($hooks); |
86
|
|
|
|
|
|
|
|
87
|
1
|
|
|
|
|
4
|
$hooks = \%Config::Hooks::; |
88
|
1
|
50
|
|
|
|
10
|
$hooks->{initialise}() if (exists($hooks->{initialise})); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub connect |
92
|
|
|
|
|
|
|
{ |
93
|
24
|
|
|
24
|
1
|
225
|
return $map->connect(@_); |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub dispatch |
97
|
|
|
|
|
|
|
{ |
98
|
21
|
|
|
21
|
1
|
23771
|
my ($request, %args) = @_; |
99
|
21
|
|
|
|
|
262
|
my ($ctx, $hooks); |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# Odd idiom, just to keep coverage happy |
102
|
|
|
|
|
|
|
# Usually: $request->{time} ||= time(); |
103
|
21
|
100
|
|
|
|
330
|
$request->{time} = time() if not $request->{time}; |
104
|
|
|
|
|
|
|
|
105
|
21
|
|
|
|
|
96
|
Pinwheel::Context::reset(); |
106
|
|
|
|
|
|
|
|
107
|
21
|
|
|
|
|
68
|
$ctx = Pinwheel::Context::get(); |
108
|
21
|
|
|
|
|
69
|
$ctx->{request} = $request; |
109
|
21
|
|
|
|
|
79
|
$ctx->{response} = {headers => {}}; |
110
|
21
|
|
|
|
|
45
|
$ctx->{rendering} = 0; |
111
|
|
|
|
|
|
|
|
112
|
21
|
|
|
|
|
85
|
Pinwheel::Context::get('render')->{format} = ['html']; |
113
|
|
|
|
|
|
|
|
114
|
21
|
|
|
|
|
57
|
$hooks = \%Config::Hooks::; |
115
|
21
|
100
|
|
|
|
158
|
if (exists($hooks->{before_dispatch})) { |
116
|
1
|
|
|
|
|
8
|
$hooks->{before_dispatch}($request); |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
21
|
|
|
|
|
50
|
eval { |
120
|
|
|
|
|
|
|
local $SIG{__DIE__} = sub { |
121
|
5
|
|
|
5
|
|
104
|
local $Carp::CarpLevel = $Carp::CarpLevel + 2; |
122
|
5
|
|
|
|
|
8903
|
Carp::confess($_[0]); |
123
|
21
|
|
|
|
|
186
|
}; |
124
|
21
|
|
|
|
|
83
|
_process_request(\%args, $ctx); |
125
|
17
|
100
|
|
|
|
136
|
render() unless $ctx->{headers}; |
126
|
16
|
100
|
|
|
|
178
|
if ($hooks->{after_dispatch}) |
127
|
|
|
|
|
|
|
{ |
128
|
1
|
|
|
|
|
7
|
$hooks->{after_dispatch}($ctx->{headers}, \$ctx->{content}); |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
}; |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# Defensive: pass a copy of $@, not $@ itself |
133
|
21
|
100
|
|
|
|
1625
|
render_500("$@") if ($@); |
134
|
|
|
|
|
|
|
|
135
|
21
|
|
|
|
|
98
|
Pinwheel::Database::finish_all(); |
136
|
|
|
|
|
|
|
|
137
|
21
|
|
|
|
|
107
|
return ($ctx->{headers}, $ctx->{content}); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub _process_request |
141
|
|
|
|
|
|
|
{ |
142
|
28
|
|
|
28
|
|
5213
|
my ($args, $ctx) = @_; |
143
|
28
|
|
|
|
|
46
|
my ($hooks, $route, $controller, $fn); |
144
|
|
|
|
|
|
|
|
145
|
28
|
|
|
|
|
239
|
$route = $map->match($ctx->{request}{path}, $ctx->{request}{method}); |
146
|
28
|
100
|
|
|
|
122
|
$route = undef if (!_check_route_params($route)); |
147
|
28
|
100
|
|
|
|
87
|
return render_404('No matching route') unless $route; |
148
|
|
|
|
|
|
|
# $route->{controller} and $route->{action} are now guaranteed to be |
149
|
|
|
|
|
|
|
# strings matching /^[a-z][a-z0-9_]*$/ |
150
|
|
|
|
|
|
|
|
151
|
23
|
|
|
|
|
88
|
$controller = _get_controller($route->{controller}); |
152
|
23
|
100
|
|
|
|
72
|
return render_404('Controller not found') unless $controller; |
153
|
22
|
|
|
|
|
95
|
$fn = $controller->{actions}{$route->{action}}; |
154
|
22
|
100
|
|
|
|
72
|
return render_404('Action is missing or not in @ACTIONS') unless $fn; |
155
|
|
|
|
|
|
|
|
156
|
21
|
|
|
|
|
55
|
$ctx->{route} = $route; |
157
|
21
|
|
|
|
|
114
|
$ctx->{controller} = $controller; |
158
|
21
|
|
|
|
|
73
|
&$fn(); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub url_for |
162
|
|
|
|
|
|
|
{ |
163
|
26
|
100
|
|
26
|
1
|
3902
|
my $name = (scalar(@_) & 1) ? shift : undef; |
164
|
26
|
|
|
|
|
83
|
my %params = @_; |
165
|
26
|
|
|
|
|
38
|
my ($ctx, $only_path, $path, $base); |
166
|
|
|
|
|
|
|
|
167
|
26
|
|
|
|
|
84
|
$ctx = Pinwheel::Context::get(); |
168
|
|
|
|
|
|
|
|
169
|
26
|
|
|
|
|
55
|
$only_path = delete $params{only_path}; |
170
|
26
|
100
|
|
|
|
87
|
$only_path = 1 unless defined($only_path); |
171
|
26
|
|
|
|
|
161
|
$path = $map->generate($name, %params, _base => $ctx->{route}); |
172
|
26
|
100
|
|
|
|
106
|
return undef unless $path; |
173
|
|
|
|
|
|
|
|
174
|
25
|
100
|
100
|
|
|
133
|
if ($ctx->{request} && $path !~ /^\w+:\/\//) { |
175
|
12
|
|
|
|
|
34
|
$path = $ctx->{request}{base} . $path; |
176
|
12
|
100
|
|
|
|
44
|
$path = "http://$ctx->{request}{host}$path" unless $only_path; |
177
|
|
|
|
|
|
|
} |
178
|
25
|
|
|
|
|
105
|
return $path; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub redirect_to |
182
|
|
|
|
|
|
|
{ |
183
|
9
|
|
|
9
|
1
|
22
|
my ($ctx, $status); |
184
|
9
|
|
|
|
|
14
|
my $url = shift; |
185
|
9
|
|
|
|
|
20
|
my %options = (); |
186
|
|
|
|
|
|
|
|
187
|
9
|
100
|
|
|
|
34
|
%options = @_ if (scalar(@_)>1); |
188
|
9
|
|
100
|
|
|
40
|
$status = delete $options{status} || 302; |
189
|
|
|
|
|
|
|
|
190
|
9
|
|
|
|
|
23
|
$ctx = Pinwheel::Context::get(); |
191
|
9
|
100
|
100
|
|
|
50
|
if (defined $url && $url =~ /\//) { |
192
|
5
|
100
|
|
|
|
29
|
$url = "http://$ctx->{request}{host}$url" if ($url !~ /^\w+:\/\//); |
193
|
|
|
|
|
|
|
} else { |
194
|
4
|
|
|
|
|
16
|
$url = url_for($url, %options, only_path => 0); |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# XXX $url might be undef, which should trigger a 500-ish error |
198
|
9
|
|
|
|
|
39
|
render(text => "Please see $url\n", status => $status, location => $url); |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub render |
202
|
|
|
|
|
|
|
{ |
203
|
54
|
|
|
54
|
|
1684
|
my %options = @_; |
204
|
54
|
|
|
|
|
97
|
my ($ctx, $content, $format); |
205
|
|
|
|
|
|
|
|
206
|
54
|
|
|
|
|
183
|
$ctx = Pinwheel::Context::get(); |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# XXX an error has occurred (double render) if this happens: don't silently |
209
|
|
|
|
|
|
|
# ignore it! |
210
|
54
|
100
|
|
|
|
1242
|
return if ($ctx->{headers}); |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# Set the top-level output format |
213
|
53
|
100
|
100
|
|
|
393
|
if (!$ctx->{rendering} && $options{format}) { |
214
|
1
|
|
|
|
|
6
|
Pinwheel::Context::get('render')->{format} = [$options{format}]; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
53
|
|
|
|
|
100
|
$ctx->{rendering}++; |
218
|
53
|
|
|
|
|
396
|
($content, $format) = _render_content(\%options); |
219
|
50
|
|
|
|
|
110
|
$ctx->{rendering}--; |
220
|
|
|
|
|
|
|
|
221
|
50
|
100
|
|
|
|
223
|
if ($ctx->{rendering} == 0) { |
222
|
48
|
100
|
|
|
|
217
|
$content = $content->to_string($format) if ref($content); |
223
|
48
|
|
|
|
|
223
|
set_header('Content-Length', length($content)); |
224
|
48
|
|
|
|
|
166
|
$ctx->{headers} = _render_headers(\%options, $format); |
225
|
48
|
|
|
|
|
123
|
$ctx->{content} = $content; |
226
|
|
|
|
|
|
|
} |
227
|
50
|
|
|
|
|
175
|
return $content; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub render_to_string |
231
|
|
|
|
|
|
|
{ |
232
|
3
|
|
|
3
|
1
|
1966
|
my %options = @_; |
233
|
3
|
|
|
|
|
5
|
my ($ctx, $content); |
234
|
|
|
|
|
|
|
|
235
|
3
|
|
|
|
|
62
|
$ctx = Pinwheel::Context::get(); |
236
|
3
|
|
|
|
|
8
|
$ctx->{rendering}++; |
237
|
3
|
|
|
|
|
9
|
($content) = _render_content(\%options); |
238
|
3
|
|
|
|
|
6
|
$ctx->{rendering}--; |
239
|
3
|
|
|
|
|
12
|
return $content; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub default_error_logger |
243
|
|
|
|
|
|
|
{ |
244
|
2
|
|
|
2
|
0
|
6
|
my ($status, $msg, $depth) = @_; |
245
|
2
|
100
|
|
|
|
13
|
Carp::cluck("render_error [$depth]: $status $msg") |
246
|
|
|
|
|
|
|
if $status == 500; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub render_error |
250
|
|
|
|
|
|
|
{ |
251
|
22
|
|
|
22
|
|
2972
|
my ($status, $msg) = @_; |
252
|
22
|
|
|
|
|
41
|
my ($ctx, $format, $template); |
253
|
|
|
|
|
|
|
|
254
|
22
|
|
|
|
|
86
|
$ctx = Pinwheel::Context::get(); |
255
|
22
|
|
|
|
|
56
|
$ctx->{headers} = undef; |
256
|
22
|
|
|
|
|
42
|
$ctx->{rendering} = 0; |
257
|
22
|
100
|
|
|
|
81
|
$ctx->{error}++ if ($status == 500); |
258
|
|
|
|
|
|
|
|
259
|
22
|
|
100
|
|
|
148
|
&$error_logger($status, $msg, $ctx->{error}||0); |
260
|
|
|
|
|
|
|
|
261
|
22
|
100
|
100
|
|
|
144
|
if (($ctx->{error} || 0) < 2) { |
262
|
21
|
|
|
|
|
62
|
$format = Pinwheel::Context::get('render')->{format}[0]; |
263
|
21
|
|
|
|
|
109
|
$template = _get_template("shared/error$status.$format"); |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
22
|
100
|
|
|
|
73
|
if (!$template) { |
267
|
3
|
|
|
|
|
8
|
render(text => $msg, status => $status); |
268
|
|
|
|
|
|
|
} else { |
269
|
19
|
|
|
|
|
35
|
eval { |
270
|
19
|
|
|
|
|
129
|
render( |
271
|
|
|
|
|
|
|
template => "shared/error$status", |
272
|
|
|
|
|
|
|
status => $status, |
273
|
|
|
|
|
|
|
locals => { msg => $msg } |
274
|
|
|
|
|
|
|
); |
275
|
|
|
|
|
|
|
}; |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# Defensive: pass a copy of $@, not $@ itself |
278
|
19
|
100
|
|
|
|
83
|
render_500("$@") if $@; |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
22
|
100
|
|
|
|
97
|
$ctx->{error}-- if ($status == 500); |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
sub render_404 |
285
|
|
|
|
|
|
|
{ |
286
|
9
|
|
|
9
|
1
|
1838
|
render_error(404, @_); |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub render_500 |
290
|
|
|
|
|
|
|
{ |
291
|
10
|
|
|
10
|
1
|
4628
|
render_error(500, @_); |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub set_header |
295
|
|
|
|
|
|
|
{ |
296
|
68
|
|
|
68
|
1
|
1400
|
my ($key, $value) = @_; |
297
|
68
|
|
|
|
|
267
|
my ($ctx); |
298
|
|
|
|
|
|
|
|
299
|
68
|
|
|
|
|
195
|
$ctx = Pinwheel::Context::get(); |
300
|
68
|
|
|
|
|
635
|
$ctx->{response}{headers}{lc($key)} = [$key, $value]; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
sub request_time |
304
|
|
|
|
|
|
|
{ |
305
|
5
|
|
|
5
|
1
|
5013924
|
my $ctx = Pinwheel::Context::get(); |
306
|
5
|
|
|
|
|
52
|
return $ctx->{request}{time}; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
sub request_time_model |
310
|
|
|
|
|
|
|
{ |
311
|
5
|
|
|
5
|
1
|
84
|
my $ctx = Pinwheel::Context::get(); |
312
|
5
|
|
|
|
|
72
|
return Pinwheel::Model::Time->new($ctx->{request}{time}); |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
sub expires_in |
316
|
|
|
|
|
|
|
{ |
317
|
2
|
|
|
2
|
1
|
2284
|
my ($seconds) = @_; |
318
|
2
|
|
|
|
|
4
|
my ($ctx, $now); |
319
|
|
|
|
|
|
|
|
320
|
2
|
|
|
|
|
9
|
$ctx = Pinwheel::Context::get(); |
321
|
2
|
|
|
|
|
11
|
$now = Pinwheel::Model::Time->new($ctx->{request}{time}); |
322
|
2
|
|
|
|
|
12
|
set_header('Date', $now->rfc822); |
323
|
2
|
|
|
|
|
11
|
set_header('Expires', $now->add($seconds)->rfc822); |
324
|
2
|
|
|
|
|
11
|
set_header('Cache-Control', 'max-age=' . $seconds); |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
sub expires_at |
328
|
|
|
|
|
|
|
{ |
329
|
1
|
|
|
1
|
1
|
4
|
my ($expires) = @_; |
330
|
1
|
|
|
|
|
2
|
my ($ctx, $now, $seconds); |
331
|
|
|
|
|
|
|
|
332
|
1
|
|
|
|
|
6
|
$ctx = Pinwheel::Context::get(); |
333
|
1
|
|
|
|
|
8
|
$now = Pinwheel::Model::Time->new($ctx->{request}{time}); |
334
|
1
|
|
|
|
|
5
|
$seconds = $expires->timestamp - $now->timestamp; |
335
|
1
|
|
|
|
|
6
|
set_header('Date', $now->rfc822); |
336
|
1
|
|
|
|
|
7
|
set_header('Expires', $expires->rfc822); |
337
|
1
|
|
|
|
|
6
|
set_header('Cache-Control', 'max-age=' . $seconds); |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub expires_now |
341
|
|
|
|
|
|
|
{ |
342
|
1
|
|
|
1
|
1
|
4274
|
set_header('Cache-Control', 'no-cache'); |
343
|
1
|
|
|
|
|
4
|
set_header('Pragma', 'no-cache'); |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
sub accepts |
347
|
|
|
|
|
|
|
{ |
348
|
8
|
|
|
8
|
1
|
23
|
my ($ctx, $format); |
349
|
|
|
|
|
|
|
|
350
|
8
|
|
|
|
|
22
|
$ctx = Pinwheel::Context::get('render'); |
351
|
8
|
|
|
|
|
23
|
$format = Pinwheel::Context::get()->{route}{$format_param}; |
352
|
8
|
100
|
|
|
|
25
|
$format = $ctx->{format}[0] if (!$format); |
353
|
|
|
|
|
|
|
|
354
|
8
|
|
|
|
|
22
|
foreach (@_) { |
355
|
11
|
100
|
|
|
|
32
|
if ($format eq $_) { |
356
|
5
|
|
|
|
|
11
|
$ctx->{format}[0] = $format; |
357
|
5
|
|
|
|
|
27
|
return 1; |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
} |
360
|
3
|
|
|
|
|
12
|
render_error(404, 'Format not supported'); |
361
|
3
|
|
|
|
|
21
|
return 0; |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
sub respond_to |
365
|
|
|
|
|
|
|
{ |
366
|
6
|
|
|
6
|
1
|
10
|
my ($ctx, $format, $old_format, $fn); |
367
|
|
|
|
|
|
|
|
368
|
6
|
|
|
|
|
16
|
$ctx = Pinwheel::Context::get('render'); |
369
|
6
|
|
|
|
|
12
|
$old_format = pop @{$ctx->{format}}; |
|
6
|
|
|
|
|
19
|
|
370
|
6
|
|
|
|
|
17
|
$format = Pinwheel::Context::get()->{route}{$format_param}; |
371
|
6
|
100
|
|
|
|
19
|
$format = $old_format if (!$format); |
372
|
6
|
|
|
|
|
8
|
push @{$ctx->{format}}, $format; |
|
6
|
|
|
|
|
19
|
|
373
|
|
|
|
|
|
|
|
374
|
6
|
|
|
|
|
10
|
my %handlers; |
375
|
6
|
|
|
|
|
16
|
while (@_) |
376
|
|
|
|
|
|
|
{ |
377
|
16
|
|
|
|
|
22
|
my $key = shift; |
378
|
16
|
100
|
|
|
|
39
|
my $handler = ((ref($_[0]) eq "CODE") ? shift : undef); |
379
|
16
|
|
|
|
|
44
|
$handlers{$key} = $handler; |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
|
382
|
6
|
100
|
|
|
|
17
|
if (!exists($handlers{$format})) { |
383
|
1
|
|
|
|
|
5
|
render_error(404, 'Format not supported'); |
384
|
|
|
|
|
|
|
} else { |
385
|
5
|
|
|
|
|
11
|
$fn = $handlers{$format}; |
386
|
5
|
100
|
|
|
|
30
|
if (defined($fn)) { |
387
|
1
|
|
|
|
|
13
|
&$fn(); |
388
|
|
|
|
|
|
|
} else { |
389
|
4
|
|
|
|
|
14
|
render(format => $format); |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
6
|
|
|
|
|
46
|
$ctx->{format}[-1] = $old_format; |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
sub params |
397
|
|
|
|
|
|
|
{ |
398
|
5
|
|
|
5
|
1
|
29
|
my $route = Pinwheel::Context::get()->{route}; |
399
|
|
|
|
|
|
|
|
400
|
5
|
100
|
|
|
|
21
|
return $route->{$_[0]} if scalar(@_) == 1; |
401
|
4
|
|
|
|
|
10
|
return [map { $route->{$_} } @_]; |
|
10
|
|
|
|
|
46
|
|
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
sub query_params |
405
|
|
|
|
|
|
|
{ |
406
|
10
|
|
|
10
|
1
|
25
|
my ($ctx, $q); |
407
|
|
|
|
|
|
|
|
408
|
10
|
|
|
|
|
29
|
$ctx = Pinwheel::Context::get(); |
409
|
10
|
100
|
|
|
|
36
|
unless ($q = $ctx->{query}) { |
410
|
7
|
|
|
|
|
17
|
my $t = $ctx->{request}{query}; |
411
|
7
|
100
|
|
|
|
18
|
$t = '' if not defined $t; |
412
|
12
|
100
|
|
|
|
34
|
$q = $ctx->{query} = { |
413
|
7
|
|
|
|
|
37
|
map { ($_ eq "") ? () : _query_key_value($_) } split(/&+/, $t) |
414
|
|
|
|
|
|
|
}; |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
|
417
|
10
|
100
|
|
|
|
61
|
return $q->{$_[0]} if scalar(@_) == 1; |
418
|
4
|
|
|
|
|
9
|
return [map { $q->{$_} } @_]; |
|
10
|
|
|
|
|
46
|
|
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
sub _query_key_value |
422
|
|
|
|
|
|
|
{ |
423
|
11
|
|
|
11
|
|
16
|
my ($s) = @_; |
424
|
11
|
|
|
|
|
15
|
my ($key, $value); |
425
|
|
|
|
|
|
|
|
426
|
11
|
|
|
|
|
16
|
$s =~ tr/+/ /; |
427
|
|
|
|
|
|
|
|
428
|
11
|
|
|
|
|
27
|
($key, $value) = split('=', $s, 2); |
429
|
11
|
|
|
|
|
22
|
$key =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/ge; |
|
1
|
|
|
|
|
6
|
|
430
|
11
|
100
|
|
|
|
32
|
$value =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/ge if $value; |
|
2
|
|
|
|
|
10
|
|
431
|
|
|
|
|
|
|
|
432
|
11
|
|
100
|
|
|
70
|
return ($key, $value || ''); |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub format |
436
|
|
|
|
|
|
|
{ |
437
|
6
|
|
|
6
|
1
|
29
|
return Pinwheel::Context::get('render')->{format}[-1]; |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
sub set_base_format |
441
|
|
|
|
|
|
|
{ |
442
|
2
|
|
|
2
|
1
|
8
|
Pinwheel::Context::get('render')->{format}[0] = $_[0]; |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
sub set_format_param |
446
|
|
|
|
|
|
|
{ |
447
|
5
|
|
|
5
|
1
|
17
|
$format_param = $_[0]; |
448
|
|
|
|
|
|
|
} |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
sub expand_static_path |
451
|
|
|
|
|
|
|
{ |
452
|
13
|
|
|
13
|
1
|
37
|
my ($path) = @_; |
453
|
13
|
|
|
|
|
80
|
my ($ctx, $base); |
454
|
|
|
|
|
|
|
|
455
|
13
|
100
|
|
|
|
68
|
$path = '/' . $path unless $path =~ /^\//; |
456
|
|
|
|
|
|
|
|
457
|
13
|
|
|
|
|
39
|
$ctx = Pinwheel::Context::get(); |
458
|
13
|
100
|
|
|
|
40
|
if ($ctx->{request}) { |
459
|
3
|
|
|
|
|
6
|
$base = $ctx->{request}{base}; |
460
|
3
|
|
|
|
|
38
|
$path =~ s/^$base//; |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
|
463
|
13
|
100
|
|
|
|
694
|
return if ($path =~ /\/\./); |
464
|
|
|
|
|
|
|
|
465
|
8
|
|
|
|
|
29
|
$path =~ s/\/{2,}/\//g; |
466
|
8
|
|
|
|
|
69
|
return $static_root . $path; |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
sub set_static_root |
470
|
|
|
|
|
|
|
{ |
471
|
1
|
|
|
1
|
1
|
7
|
$static_root = shift; |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
sub set_templates_root |
475
|
|
|
|
|
|
|
{ |
476
|
2
|
|
|
2
|
1
|
300
|
$templates_root = shift; |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
# ============================================================================== |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
sub _render_headers |
484
|
|
|
|
|
|
|
{ |
485
|
67
|
|
|
67
|
|
554
|
my ($opts, $format) = @_; |
486
|
67
|
|
|
|
|
101
|
my ($h, $type); |
487
|
|
|
|
|
|
|
|
488
|
67
|
|
|
|
|
184
|
$h = Pinwheel::Context::get()->{response}{headers}; |
489
|
|
|
|
|
|
|
|
490
|
67
|
100
|
|
|
|
258
|
$h->{'status'} = ['Status', $opts->{status}] if $opts->{status}; |
491
|
67
|
100
|
|
|
|
288
|
$h->{'status'} = ['Status', 200] unless $h->{'status'}; |
492
|
|
|
|
|
|
|
|
493
|
67
|
100
|
|
|
|
279
|
$type = $format_defaults{$format}{content_type} if $format; |
494
|
67
|
100
|
|
|
|
149
|
$type = 'text/html' unless $type; |
495
|
67
|
100
|
|
|
|
199
|
$type = $h->{'content-type'}[1] if $h->{'content-type'}; |
496
|
67
|
100
|
|
|
|
171
|
$type = $opts->{content_type} if $opts->{content_type}; |
497
|
67
|
|
|
|
|
561
|
$h->{'content-type'} = ['Content-Type', $type]; |
498
|
|
|
|
|
|
|
|
499
|
67
|
100
|
|
|
|
410
|
$h->{'location'} = ['Location', $opts->{location}] if $opts->{location}; |
500
|
|
|
|
|
|
|
|
501
|
67
|
|
|
|
|
233
|
return $h; |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
sub _render_content |
505
|
|
|
|
|
|
|
{ |
506
|
66
|
|
|
66
|
|
16977
|
my $options = shift; |
507
|
66
|
|
|
|
|
125
|
my ($ctx, $renderctx, $name, $format, $srcformat); |
508
|
0
|
|
|
|
|
0
|
my ($content, $template, $layout); |
509
|
|
|
|
|
|
|
|
510
|
66
|
100
|
|
|
|
331
|
if (exists($options->{text})) { |
511
|
|
|
|
|
|
|
# Render a static piece of text |
512
|
19
|
|
|
|
|
40
|
$content = $options->{text}; |
513
|
19
|
|
|
|
|
45
|
$format = 'txt'; |
514
|
|
|
|
|
|
|
} else { |
515
|
47
|
|
|
|
|
145
|
$ctx = Pinwheel::Context::get(); |
516
|
47
|
|
|
|
|
143
|
$renderctx = Pinwheel::Context::get('render'); |
517
|
|
|
|
|
|
|
|
518
|
47
|
|
|
|
|
168
|
$name = _make_template_name($options, $ctx->{route}); |
519
|
47
|
100
|
|
|
|
339
|
croak "Invalid template name" unless $name; |
520
|
46
|
|
|
|
|
88
|
$format = $options->{format}; |
521
|
46
|
100
|
|
|
|
164
|
$format = $renderctx->{format}[-1] if !$format; |
522
|
46
|
|
|
|
|
70
|
$srcformat = $options->{via}; |
523
|
46
|
100
|
|
|
|
110
|
$srcformat = $format if !$srcformat; |
524
|
46
|
|
|
|
|
161
|
$template = _get_template("$name.$srcformat"); |
525
|
46
|
100
|
|
|
|
798
|
croak "Unable to find template $name" unless $template; |
526
|
44
|
|
|
|
|
160
|
$layout = _get_layout($srcformat, $options); |
527
|
|
|
|
|
|
|
|
528
|
44
|
|
|
|
|
74
|
push @{$renderctx->{format}}, $srcformat; |
|
44
|
|
|
|
|
155
|
|
529
|
44
|
|
|
|
|
205
|
$content = _render_template($template, $layout, $options->{locals}); |
530
|
42
|
|
|
|
|
88
|
pop @{$renderctx->{format}}; |
|
42
|
|
|
|
|
301
|
|
531
|
|
|
|
|
|
|
} |
532
|
|
|
|
|
|
|
|
533
|
61
|
|
|
|
|
229
|
return ($content, $format); |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
sub _render_template |
537
|
|
|
|
|
|
|
{ |
538
|
52
|
|
|
52
|
|
241
|
my ($template, $layout, $locals) = @_; |
539
|
52
|
|
|
|
|
325
|
my ($ctx, $globals, $helpers, $content); |
540
|
|
|
|
|
|
|
|
541
|
52
|
|
|
|
|
331
|
$ctx = Pinwheel::Context::get(); |
542
|
|
|
|
|
|
|
|
543
|
52
|
100
|
|
|
|
181
|
$locals = {} if (!$locals); |
544
|
52
|
|
|
|
|
149
|
$globals = Pinwheel::Context::get('template'); |
545
|
52
|
|
|
|
|
132
|
$helpers = $ctx->{controller}{helpers}; |
546
|
52
|
100
|
|
|
|
181
|
$helpers = _get_helpers(['Pinwheel::Helpers', 'Application']) if (!$helpers); |
547
|
|
|
|
|
|
|
# Any supplied locals are sent to the layout too, so don't pass a reference |
548
|
|
|
|
|
|
|
# to the original here or it might be changed |
549
|
52
|
|
|
|
|
2396
|
$content = $template->({%$locals}, $globals, $helpers); |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
# The layout (if any) is added afterwards so that it has access to any |
552
|
|
|
|
|
|
|
# state built up by the content template, eg a list of Javascript or CSS |
553
|
|
|
|
|
|
|
# files to include |
554
|
50
|
100
|
|
|
|
298
|
if ($layout) { |
555
|
34
|
|
|
|
|
117
|
Pinwheel::Context::get('render')->{content}{'layout'} = $content; |
556
|
34
|
|
|
|
|
160
|
$content = $layout->($locals, $globals, _get_layout_helpers()); |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
|
559
|
50
|
|
|
|
|
176
|
return $content; |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
sub preload_templates |
563
|
|
|
|
|
|
|
{ |
564
|
2
|
|
|
2
|
1
|
7
|
my ($types, $w); |
565
|
|
|
|
|
|
|
|
566
|
2
|
|
|
|
|
13
|
$types = join('|', keys %template_types); |
567
|
|
|
|
|
|
|
$w = sub { |
568
|
36
|
100
|
|
36
|
|
1195
|
if (/^\Q${templates_root}\E\/(.+)\.(${types})$/) { |
569
|
|
|
|
|
|
|
# Ignore errors. Could mean there are files in the templates |
570
|
|
|
|
|
|
|
# directory that aren't named like valid templates. |
571
|
27
|
100
|
|
|
|
1292
|
_get_template($1) if -f $_; |
572
|
|
|
|
|
|
|
} |
573
|
2
|
|
|
|
|
14
|
}; |
574
|
|
|
|
|
|
|
|
575
|
2
|
|
|
|
|
138
|
File::Find::find({ no_chdir => 1, wanted => $w }, $templates_root); |
576
|
|
|
|
|
|
|
} |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
sub _get_template |
579
|
|
|
|
|
|
|
{ |
580
|
186
|
|
|
186
|
|
4620
|
my ($name) = @_; |
581
|
186
|
|
|
|
|
244
|
my ($ext, $filename, $template); |
582
|
|
|
|
|
|
|
|
583
|
186
|
100
|
|
|
|
724
|
return $template_cache{$name} if exists($template_cache{$name}); |
584
|
68
|
100
|
|
|
|
395
|
return if $name !~ m{^\w+/\w+\.\w+$}; |
585
|
|
|
|
|
|
|
|
586
|
59
|
|
|
|
|
211
|
foreach $ext (keys %template_types) { |
587
|
133
|
100
|
|
|
|
9604
|
next unless -f ($filename = "$templates_root/$name.$ext"); |
588
|
44
|
|
|
|
|
221
|
$template = read_file($filename, binmode => ':raw'); |
589
|
44
|
|
|
|
|
14416
|
$template = $template_types{$ext}->($template, $name); |
590
|
44
|
|
|
|
|
205
|
$template_cache{$name} = $template; |
591
|
44
|
|
|
|
|
687
|
return $template; |
592
|
|
|
|
|
|
|
} |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
# Cache failed lookups to avoid hitting the filesystem repeatedly for |
595
|
|
|
|
|
|
|
# non-existent layout files etc. |
596
|
15
|
|
|
|
|
85
|
$template_cache{$name} = undef; |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
sub _get_layout |
600
|
|
|
|
|
|
|
{ |
601
|
53
|
|
|
53
|
|
1341
|
my ($format, $options) = @_; |
602
|
53
|
|
|
|
|
152
|
my ($ctx, $controller, $base, $name, $layout); |
603
|
|
|
|
|
|
|
|
604
|
53
|
|
|
|
|
263
|
$ctx = Pinwheel::Context::get(); |
605
|
53
|
|
|
|
|
161
|
$controller = $ctx->{route}{controller}; |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
# When rendering a partial the layout comes from the same directory, |
608
|
|
|
|
|
|
|
# otherwise it comes from 'layouts'. |
609
|
53
|
100
|
|
|
|
233
|
if ($options->{partial}) { |
610
|
7
|
100
|
|
|
|
49
|
$base = $1 if $options->{partial} =~ /^(\w+)\//; |
611
|
7
|
100
|
|
|
|
24
|
$base = $controller if !$base; |
612
|
7
|
|
|
|
|
16
|
$base = $base . '/_'; |
613
|
|
|
|
|
|
|
} else { |
614
|
46
|
|
|
|
|
99
|
$base = 'layouts/'; |
615
|
|
|
|
|
|
|
} |
616
|
|
|
|
|
|
|
|
617
|
53
|
100
|
|
|
|
391
|
if (defined($options->{layout})) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
618
|
10
|
|
|
|
|
22
|
$name = $options->{layout}; |
619
|
|
|
|
|
|
|
} elsif ($options->{partial}) { |
620
|
1
|
|
|
|
|
2
|
$name = 0; |
621
|
|
|
|
|
|
|
} elsif (defined($ctx->{controller}{layout})) { |
622
|
1
|
|
|
|
|
4
|
$name = $ctx->{controller}{layout}; |
623
|
|
|
|
|
|
|
} else { |
624
|
41
|
|
|
|
|
131
|
$name = $format_defaults{$format}{layout}; |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
|
627
|
53
|
100
|
|
|
|
187
|
if (!defined($name)) { |
|
|
100
|
|
|
|
|
|
628
|
|
|
|
|
|
|
# Automatic layout (eg, no layout option or layout => undef) |
629
|
33
|
100
|
|
|
|
164
|
$layout = _get_template("${base}$controller.$format") if $controller; |
630
|
33
|
100
|
|
|
|
166
|
$layout = _get_template("${base}application.$format") if !$layout; |
631
|
|
|
|
|
|
|
} elsif ($name) { |
632
|
|
|
|
|
|
|
# Specified layout (eg, layout => 'foo') |
633
|
10
|
|
|
|
|
47
|
$layout = _get_template("${base}$name.$format"); |
634
|
10
|
100
|
|
|
|
307
|
croak "Unable to find ${base}$name" unless $layout; |
635
|
|
|
|
|
|
|
} else { |
636
|
|
|
|
|
|
|
# Layout disabled (eg, layout => 0) |
637
|
|
|
|
|
|
|
} |
638
|
52
|
|
|
|
|
159
|
return $layout; |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
sub _get_controller |
643
|
|
|
|
|
|
|
{ |
644
|
31
|
|
|
31
|
|
11388
|
my $name = shift; |
645
|
31
|
|
|
|
|
54
|
my ($info, $pkgname, $pkg, $layout, $helpers); |
646
|
|
|
|
|
|
|
|
647
|
31
|
100
|
|
|
|
324
|
return $info if ($info = $controllers{$name}); |
648
|
|
|
|
|
|
|
|
649
|
6
|
|
|
|
|
22
|
$pkgname = _make_mixed_case($name); |
650
|
6
|
|
|
|
|
27
|
$pkg = _get_package('Controllers::' . $pkgname); |
651
|
6
|
100
|
|
|
|
32
|
return unless $pkg->{'ACTIONS'}; |
652
|
|
|
|
|
|
|
|
653
|
4
|
|
|
|
|
10
|
$layout = $pkg->{'LAYOUT'}; |
654
|
4
|
100
|
|
|
|
14
|
$layout = $$layout if $layout; |
655
|
4
|
|
100
|
|
|
25
|
$helpers = $pkg->{'HELPERS'} || []; |
656
|
4
|
|
|
|
|
18
|
$helpers = ['Pinwheel::Helpers', 'Application', @$helpers, $pkgname]; |
657
|
4
|
|
|
|
|
15
|
return $controllers{$name} = { |
658
|
|
|
|
|
|
|
layout => $layout, |
659
|
|
|
|
|
|
|
helpers => _get_helpers($helpers), |
660
|
|
|
|
|
|
|
actions => _get_actions($pkg) |
661
|
|
|
|
|
|
|
}; |
662
|
|
|
|
|
|
|
} |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
sub _get_layout_helpers |
665
|
|
|
|
|
|
|
{ |
666
|
36
|
100
|
|
36
|
|
3298
|
if (!$layout_helpers) { |
667
|
1
|
|
|
|
|
5
|
$layout_helpers = _get_helpers(['Pinwheel::Helpers', 'Application']); |
668
|
|
|
|
|
|
|
} |
669
|
36
|
|
|
|
|
1257
|
return $layout_helpers; |
670
|
|
|
|
|
|
|
} |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
sub _get_helpers |
673
|
|
|
|
|
|
|
{ |
674
|
21
|
|
|
21
|
|
1154
|
my $helpers = shift; |
675
|
21
|
|
|
|
|
34
|
my ($name, $fns, $pkg, $exports); |
676
|
|
|
|
|
|
|
|
677
|
21
|
|
|
|
|
46
|
$fns = {}; |
678
|
21
|
|
|
|
|
50
|
foreach $name (@$helpers) { |
679
|
44
|
100
|
|
|
|
175
|
$name = "Helpers::$name" unless $name =~ /::/; |
680
|
44
|
|
|
|
|
110
|
$pkg = _get_package($name); |
681
|
44
|
100
|
|
|
|
212
|
next unless $exports = $pkg->{'EXPORT_OK'}; |
682
|
42
|
|
|
|
|
89
|
foreach (@$exports) { |
683
|
62
|
100
|
|
|
|
176
|
next unless $pkg->{$_}; |
684
|
61
|
|
|
|
|
75
|
$fns->{$_} = \&{$pkg->{$_}}; |
|
61
|
|
|
|
|
333
|
|
685
|
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
} |
687
|
21
|
|
|
|
|
70
|
return $fns; |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
sub _get_actions |
691
|
|
|
|
|
|
|
{ |
692
|
4
|
|
|
4
|
|
10
|
my $pkg = shift; |
693
|
4
|
|
|
|
|
6
|
my ($actions, $fns); |
694
|
|
|
|
|
|
|
|
695
|
4
|
|
|
|
|
10
|
$actions = $pkg->{'ACTIONS'}; |
696
|
4
|
|
|
|
|
11
|
foreach (@$actions) { |
697
|
7
|
100
|
|
|
|
23
|
next unless $pkg->{$_}; |
698
|
6
|
|
|
|
|
10
|
$fns->{$_} = \&{$pkg->{$_}}; |
|
6
|
|
|
|
|
28
|
|
699
|
|
|
|
|
|
|
} |
700
|
|
|
|
|
|
|
|
701
|
4
|
|
|
|
|
34
|
return $fns; |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
sub _check_route_params |
706
|
|
|
|
|
|
|
{ |
707
|
39
|
|
|
39
|
|
465
|
my ($params) = @_; |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
return ( |
710
|
39
|
|
100
|
|
|
587
|
$params |
711
|
|
|
|
|
|
|
&& $params->{controller} =~ /^[a-z][a-z0-9_]*$/ |
712
|
|
|
|
|
|
|
&& $params->{action} =~ /^[a-z][a-z0-9_]*$/ |
713
|
|
|
|
|
|
|
); |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
sub _make_template_name |
718
|
|
|
|
|
|
|
{ |
719
|
67
|
|
|
67
|
|
499
|
my ($options, $route) = @_; |
720
|
67
|
|
|
|
|
96
|
my ($name, $format); |
721
|
|
|
|
|
|
|
|
722
|
67
|
100
|
|
|
|
285
|
if ($options->{action}) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
723
|
8
|
|
|
|
|
23
|
$name = "$route->{controller}/$options->{action}"; |
724
|
|
|
|
|
|
|
} elsif ($options->{template}) { |
725
|
32
|
|
|
|
|
58
|
$name = $options->{template}; |
726
|
|
|
|
|
|
|
} elsif ($options->{partial}) { |
727
|
11
|
|
|
|
|
24
|
$name = $options->{partial}; |
728
|
11
|
100
|
|
|
|
59
|
$name = "$route->{controller}/$name" unless $name =~ /\//; |
729
|
11
|
|
|
|
|
60
|
$name =~ s!/!/_!; |
730
|
|
|
|
|
|
|
} else { |
731
|
16
|
|
|
|
|
68
|
$name = "$route->{controller}/$route->{action}"; |
732
|
|
|
|
|
|
|
} |
733
|
|
|
|
|
|
|
|
734
|
67
|
100
|
|
|
|
800
|
return unless $name =~ m{^(\w+/\w+)$}; |
735
|
54
|
|
|
|
|
169
|
return $name; |
736
|
|
|
|
|
|
|
} |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
sub _make_mixed_case |
740
|
|
|
|
|
|
|
{ |
741
|
12
|
|
|
12
|
|
348
|
my $name = shift; |
742
|
|
|
|
|
|
|
# Convert some_name to SomeName |
743
|
12
|
|
|
|
|
47
|
$name =~ s/_+/ /g; |
744
|
12
|
|
|
|
|
116
|
$name =~ s/\b(\w)/\U$1/g; |
745
|
12
|
|
|
|
|
36
|
$name =~ s/ +//g; |
746
|
12
|
|
|
|
|
51
|
return $name; |
747
|
|
|
|
|
|
|
} |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
sub _get_package |
750
|
|
|
|
|
|
|
{ |
751
|
50
|
|
|
50
|
|
160
|
my $name = shift; |
752
|
50
|
|
|
|
|
85
|
my $pkg = \%::; |
753
|
50
|
|
|
|
|
576
|
$pkg = $pkg->{"$_\::"} foreach split(/::/, $name); |
754
|
50
|
|
|
|
|
169
|
return $pkg; |
755
|
|
|
|
|
|
|
} |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
1; |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
__DATA__ |