roda-cj 0.9.6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +16 -0
- data/README.rdoc +211 -103
- data/Rakefile +1 -1
- data/doc/release_notes/1.0.0.txt +329 -0
- data/lib/roda.rb +295 -42
- data/lib/roda/plugins/all_verbs.rb +1 -1
- data/lib/roda/plugins/assets.rb +277 -0
- data/lib/roda/plugins/backtracking_array.rb +1 -1
- data/lib/roda/plugins/error_email.rb +110 -0
- data/lib/roda/plugins/multi_route.rb +14 -3
- data/lib/roda/plugins/not_allowed.rb +10 -3
- data/lib/roda/plugins/path.rb +38 -0
- data/lib/roda/plugins/symbol_matchers.rb +1 -1
- data/lib/roda/plugins/view_subdirs.rb +7 -1
- data/lib/roda/version.rb +1 -1
- data/spec/integration_spec.rb +95 -3
- data/spec/plugin/_erubis_escaping_spec.rb +1 -0
- data/spec/plugin/assets_spec.rb +86 -0
- data/spec/plugin/error_email_spec.rb +68 -0
- data/spec/plugin/multi_route_spec.rb +22 -0
- data/spec/plugin/not_allowed_spec.rb +13 -0
- data/spec/plugin/path_spec.rb +29 -0
- metadata +104 -66
- checksums.yaml +0 -7
data/CHANGELOG
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
= HEAD
|
2
2
|
|
3
|
+
* Support adding middleware after the route block has been added (jeremyevans)
|
4
|
+
|
5
|
+
* Allow Roda subclasses to use route block from superclass (jeremyevans)
|
6
|
+
|
7
|
+
* Have r.multi_route ignore non-String named routes (jeremyevans)
|
8
|
+
|
9
|
+
* Pick up newly added named routes while running in the multi_route plugin, useful for development (jeremyevans)
|
10
|
+
|
11
|
+
* Add path plugin, for named path support (jeremyevans) (#4)
|
12
|
+
|
13
|
+
* Add error_email plugin, for easily emailing an error notification for an exception (jeremyevans)
|
14
|
+
|
15
|
+
= 1.0.0 (2014-08-19)
|
16
|
+
|
17
|
+
* Don't have :extension hash matcher force a terminal match (jeremyevans)
|
18
|
+
|
3
19
|
* Add :content option to view method in render plugin to use given content instead of rendering a template (jeremyevans)
|
4
20
|
|
5
21
|
* Add :escape option to render plugin for using erb templates where <%= %> escapes and <%== %> does not (jeremyevans)
|
data/README.rdoc
CHANGED
@@ -35,25 +35,30 @@ Here's a simple application, showing how the routing tree works:
|
|
35
35
|
use Rack::Session::Cookie, :secret => ENV['SECRET']
|
36
36
|
|
37
37
|
route do |r|
|
38
|
-
#
|
39
|
-
r.
|
38
|
+
# GET / request
|
39
|
+
r.root do
|
40
|
+
r.redirect "/hello"
|
41
|
+
end
|
40
42
|
|
41
|
-
|
42
|
-
|
43
|
-
r.redirect "/hello"
|
44
|
-
end
|
43
|
+
# /hello branch
|
44
|
+
r.on "hello" do
|
45
45
|
|
46
|
-
#
|
47
|
-
r.
|
46
|
+
# GET /hello/world request
|
47
|
+
r.get "world" do
|
48
|
+
"Hello world!"
|
49
|
+
end
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
|
51
|
+
# /hello request
|
52
|
+
r.is do
|
53
|
+
# GET /hello request
|
54
|
+
r.get do
|
55
|
+
"Hello!"
|
52
56
|
end
|
53
57
|
|
54
|
-
#
|
55
|
-
r.
|
56
|
-
"
|
58
|
+
# POST /hello request
|
59
|
+
r.post do
|
60
|
+
puts "Someone said hello!"
|
61
|
+
r.redirect
|
57
62
|
end
|
58
63
|
end
|
59
64
|
end
|
@@ -62,8 +67,6 @@ Here's a simple application, showing how the routing tree works:
|
|
62
67
|
|
63
68
|
run App.app
|
64
69
|
|
65
|
-
You can now run +rackup+ and enjoy what you have just created.
|
66
|
-
|
67
70
|
Here's a breakdown of what is going on in the above block:
|
68
71
|
|
69
72
|
After requiring the library and subclassing Roda, the +use+ method
|
@@ -76,34 +79,120 @@ with some additional methods for matching routes. By
|
|
76
79
|
convention, this argument should be named +r+.
|
77
80
|
|
78
81
|
The primary way routes are matched in Roda is by calling
|
79
|
-
+r.on+,
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
82
|
+
+r.on+, +r.is+, +r.root+, +r.get+, or +r.post+. These methods are
|
83
|
+
calling the routing methods, and each of them takes a block. The
|
84
|
+
block is referred to as a match block.
|
85
|
+
|
86
|
+
Each routing method takes each of the arguments (called matchers)
|
87
|
+
given and tries to match them to the current request. If it is
|
88
|
+
able to match all of the arguments, it yields to the match block,
|
89
|
+
otherwise the block is skipped and execution continues.
|
90
|
+
|
91
|
+
+r.on+ matches if all of the arguments match.
|
92
|
+
+r.is+ matches if all of the arguments match, and there are no
|
93
|
+
further entries in the path after matching.
|
94
|
+
+r.get+ when called without arguments matches any +GET+ request.
|
95
|
+
+r.get+ when called with any arguments matches only if the
|
96
|
+
current request is a +GET+ request and there are no further entries
|
97
|
+
in the path after matching.
|
98
|
+
+r.root+ only matches a +GET+ request where the current path is +/+.
|
99
|
+
|
100
|
+
If a routing method matches and control is yielded to the match
|
101
|
+
block, whenever the match block returns, Roda will return the
|
102
|
+
rack response array of status, headers, and body, to the caller.
|
103
|
+
|
104
|
+
If the match block returns a string and the response body hasn't
|
105
|
+
already been written to, the block return value will interpreted
|
106
|
+
as the body for the response. If none of the routing methods match
|
107
|
+
and the route block returns a string, it will be interpreted as the
|
108
|
+
body for the response.
|
96
109
|
|
97
110
|
+r.redirect+ immediately returns the response, allowing for
|
98
|
-
code such as <tt>r.redirect(path) if some_condition</tt>.
|
111
|
+
code such as <tt>r.redirect(path) if some_condition</tt>. If
|
112
|
+
called without arguments, it redirects to the current path if
|
113
|
+
the current request method is not +GET+.
|
99
114
|
|
100
115
|
The +.app+ at the end is an optimization, which you can leave
|
101
116
|
off, but which saves a few methods call for every response.
|
102
117
|
|
118
|
+
== The Routing Tree
|
119
|
+
|
120
|
+
Roda is called a routing tree web framework because the way most
|
121
|
+
sites are structured, routing takes the form of a tree based on the
|
122
|
+
URL structure of the site. In general, +r.on+ is used to split the
|
123
|
+
tree into different branches, and +r.is+ is finalizes the routing,
|
124
|
+
where the request is actually handled.
|
125
|
+
|
126
|
+
So a simple routing tree may look something like this:
|
127
|
+
|
128
|
+
r.on "a" do # /a branch
|
129
|
+
r.on "b" do # /a/b branch
|
130
|
+
r.is "c" do # /a/b/c request
|
131
|
+
r.get do end # GET /a/b/c request
|
132
|
+
r.post do end # POST /a/b/c request
|
133
|
+
end
|
134
|
+
r.get "d" do end # GET /a/b/d request
|
135
|
+
r.post "e" do end # POST /a/b/e request
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
It's also possible to handle the same requests, but structure the
|
140
|
+
routing tree by first branching on the request method:
|
141
|
+
|
142
|
+
r.get do # GET
|
143
|
+
r.on "a" do # GET /a branch
|
144
|
+
r.on "b" do # GET /a/b branch
|
145
|
+
r.is "c" do end # GET /a/b/c request
|
146
|
+
r.is "d" do end # GET /a/b/d request
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
r.post do # POST
|
152
|
+
r.on "a" do # POST /a branch
|
153
|
+
r.on "b" do # POST /a/b branch
|
154
|
+
r.is "c" do end # POST /a/b/c request
|
155
|
+
r.is "e" do end # POST /a/b/e request
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
This allows you to easily separate your +GET+ request handling from
|
161
|
+
your +POST+ request handling. If you only have a small number of
|
162
|
+
+POST+ request URLs and a large number of +GET+ request URLs, this
|
163
|
+
may make things easier.
|
164
|
+
|
165
|
+
However, in general routing first by the path and last by the
|
166
|
+
request method is likely to lead to simpler and DRYer code. This
|
167
|
+
is because at any point during the routing, you can act on the
|
168
|
+
request. For example, if all requests in the +/a+ branch need
|
169
|
+
need access permission +A+ and all requests in the +/a/b+ branch
|
170
|
+
need access permission +B+, you can easily handle this in the
|
171
|
+
routing tree:
|
172
|
+
|
173
|
+
r.on "a" do # /a branch
|
174
|
+
check_perm(:A)
|
175
|
+
r.on "b" do # /a/b branch
|
176
|
+
check_perm(:B)
|
177
|
+
r.is "c" do # /a/b/c request
|
178
|
+
r.get do end # GET /a/b/c request
|
179
|
+
r.post do end # POST /a/b/c request
|
180
|
+
end
|
181
|
+
r.get "d" do end # GET /a/b/d request
|
182
|
+
r.post "e" do end # POST /a/b/e request
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
Being able to operate on the request at any point during the
|
187
|
+
the routing is one of the major advantages of Roda compared
|
188
|
+
to other web frameworks that do not use a routing tree.
|
189
|
+
|
103
190
|
== Matchers
|
104
191
|
|
105
|
-
|
106
|
-
|
192
|
+
Other than +r.root+, the routing methods all take arguments called
|
193
|
+
matchers. If all of the matchers match, the routing method yields to
|
194
|
+
the match block. Here's an example showcasing how different
|
195
|
+
matchers work:
|
107
196
|
|
108
197
|
class App < Roda
|
109
198
|
route do |r|
|
@@ -136,7 +225,6 @@ are arguments passed to +r.on+.
|
|
136
225
|
|
137
226
|
# /username/foobar/posts
|
138
227
|
r.is "posts" do
|
139
|
-
|
140
228
|
# You can access user here, because the blocks are closures.
|
141
229
|
"Total Posts: #{user.posts.size}" #=> "Total Posts: 6"
|
142
230
|
end
|
@@ -158,7 +246,7 @@ are arguments passed to +r.on+.
|
|
158
246
|
r.is "login" do
|
159
247
|
|
160
248
|
# POST /login, user: foo, pass: baz
|
161
|
-
r.on
|
249
|
+
r.on({:param=>"user"}, {:param=>"pass"}) do |user, pass|
|
162
250
|
"#{user}:#{pass}" #=> "foo:baz"
|
163
251
|
end
|
164
252
|
|
@@ -180,75 +268,75 @@ The +/+ here is considered the empty segment.
|
|
180
268
|
If it does not contain a colon or slash, it matches single segment
|
181
269
|
with the text of the string, preceeded by a slash.
|
182
270
|
|
183
|
-
"" matches "/"
|
184
|
-
"foo" matches "/foo"
|
185
|
-
"foo" does not match "/food"
|
271
|
+
"" # matches "/"
|
272
|
+
"foo" # matches "/foo"
|
273
|
+
"foo" # does not match "/food"
|
186
274
|
|
187
275
|
If it contains any slashes, it matches one additional segment for
|
188
276
|
each slash:
|
189
277
|
|
190
|
-
"foo/bar" matches "/foo/bar"
|
191
|
-
"foo/bar" does not match "/foo/bard"
|
278
|
+
"foo/bar" # matches "/foo/bar"
|
279
|
+
"foo/bar" # does not match "/foo/bard"
|
192
280
|
|
193
281
|
If it contains a colon followed by any <tt>\\w</tt> characters, the colon and
|
194
282
|
remaing <tt>\\w</tt> characters matches any nonempty segment that contains at
|
195
283
|
least one character:
|
196
284
|
|
197
|
-
"foo/:id" matches "/foo/bar", "/foo/baz", etc.
|
198
|
-
"foo/:id" does not match "/fo/bar"
|
285
|
+
"foo/:id" # matches "/foo/bar", "/foo/baz", etc.
|
286
|
+
"foo/:id" # does not match "/fo/bar"
|
199
287
|
|
200
288
|
You can use multiple colons in a string:
|
201
289
|
|
202
|
-
":x/:y" matches "/foo/bar", "/bar/foo" etc.
|
203
|
-
":x/:y" does not match "/foo", "/bar/"
|
290
|
+
":x/:y" # matches "/foo/bar", "/bar/foo" etc.
|
291
|
+
":x/:y" # does not match "/foo", "/bar/"
|
204
292
|
|
205
293
|
You can prefix colons:
|
206
294
|
|
207
|
-
"foo:x/bar:y" matches "/food/bard", "/fool/bart", etc.
|
208
|
-
"foo:x/bar:y" does not match "/foo/bart", "/fool/bar", etc.
|
295
|
+
"foo:x/bar:y" # matches "/food/bard", "/fool/bart", etc.
|
296
|
+
"foo:x/bar:y" # does not match "/foo/bart", "/fool/bar", etc.
|
209
297
|
|
210
298
|
If any colons are used, the block will yield one argument for
|
211
299
|
each segment matched containing the matched text. So:
|
212
300
|
|
213
|
-
"foo:x/:y" matching "/fool/bar" yields "l", "bar"
|
301
|
+
"foo:x/:y" # matching "/fool/bar" yields "l", "bar"
|
214
302
|
|
215
303
|
Colons that are not followed by a <tt>\\w</tt> character are matched literally:
|
216
304
|
|
217
|
-
":/a" matches "/:/a"
|
305
|
+
":/a" # matches "/:/a"
|
218
306
|
|
219
307
|
Note that strings are regexp escaped before being used in a regular
|
220
308
|
expression, so:
|
221
309
|
|
222
|
-
"\\d+(/\\w+)?" matches "
|
223
|
-
"\\d
|
310
|
+
"\\d+(/\\w+)?" # matches "/\d+(/\w+)?"
|
311
|
+
"\\d+(/\\w+)?" # does not match "/123/abc"
|
224
312
|
|
225
313
|
=== Regexp
|
226
314
|
|
227
315
|
Regexps match one or more segments by looking for the pattern preceeded by a
|
228
316
|
slash:
|
229
317
|
|
230
|
-
/foo\w+/ matches "/foobar"
|
231
|
-
/foo\w+/ does not match "/foo/bar"
|
318
|
+
/foo\w+/ # matches "/foobar"
|
319
|
+
/foo\w+/ # does not match "/foo/bar"
|
232
320
|
|
233
321
|
If any patterns are captured by the regexp, they are yielded:
|
234
322
|
|
235
|
-
/foo\w+/ matches "/foobar", yields nothing
|
236
|
-
/foo(\w+)/ matches "/foobar", yields "bar"
|
323
|
+
/foo\w+/ # matches "/foobar", yields nothing
|
324
|
+
/foo(\w+)/ # matches "/foobar", yields "bar"
|
237
325
|
|
238
326
|
=== Symbol
|
239
327
|
|
240
328
|
Symbols match any nonempty segment, yielding the segment except for the
|
241
329
|
preceeding slash:
|
242
330
|
|
243
|
-
:id matches "/foo" yields "foo"
|
244
|
-
:id does not match "/"
|
331
|
+
:id # matches "/foo" yields "foo"
|
332
|
+
:id # does not match "/"
|
245
333
|
|
246
334
|
=== Proc
|
247
335
|
|
248
336
|
Procs match unless they return false or nil:
|
249
337
|
|
250
|
-
proc{true} matches anything
|
251
|
-
proc{false} does not match anything
|
338
|
+
proc{true} # matches anything
|
339
|
+
proc{false} # does not match anything
|
252
340
|
|
253
341
|
Procs don't capture anything by default, but they can if you add
|
254
342
|
the captured text to +r.captures+.
|
@@ -263,8 +351,8 @@ condition). Evaluation stops at the first matcher that matches.
|
|
263
351
|
Additionally, if the matched object is a String, the string is yielded.
|
264
352
|
This makes it easy to handle multiple strings without a Regexp:
|
265
353
|
|
266
|
-
|
267
|
-
[] does not match anything
|
354
|
+
['page1', 'page2'] # matches "/page1", "/page2"
|
355
|
+
[] # does not match anything
|
268
356
|
|
269
357
|
=== Hash
|
270
358
|
|
@@ -276,12 +364,12 @@ block will be called with the value of the hash.
|
|
276
364
|
|
277
365
|
class App < Roda
|
278
366
|
hash_matcher(:foo) do |v|
|
279
|
-
...
|
367
|
+
# ...
|
280
368
|
end
|
281
369
|
|
282
370
|
route do |r|
|
283
371
|
r.on :foo=>'bar' do
|
284
|
-
...
|
372
|
+
# ...
|
285
373
|
end
|
286
374
|
end
|
287
375
|
end
|
@@ -291,13 +379,13 @@ block will be called with the value of the hash.
|
|
291
379
|
The :all matcher matches if all of the entries in the given array matches. So
|
292
380
|
|
293
381
|
r.on :all=>[:a, :b] do
|
294
|
-
...
|
382
|
+
# ...
|
295
383
|
end
|
296
384
|
|
297
385
|
is the same as:
|
298
386
|
|
299
387
|
r.on :a, :b do
|
300
|
-
...
|
388
|
+
# ...
|
301
389
|
end
|
302
390
|
|
303
391
|
The reason it also exists as a separate hash matcher is so you can use it inside
|
@@ -312,34 +400,32 @@ Would match +/foo+ and +/foos/10+, but not +/foos+.
|
|
312
400
|
|
313
401
|
The :extension matcher matches any nonempty path ending with the given extension:
|
314
402
|
|
315
|
-
:extension => "css" matches "/foo.css", "/bar.css"
|
316
|
-
:extension => "css" does not match "/foo.css/x", "/foo.bar", "/.css"
|
403
|
+
{:extension => "css"} # matches "/foo.css", "/bar.css"
|
404
|
+
{:extension => "css"} # does not match "/foo.css/x", "/foo.bar", "/.css"
|
317
405
|
|
318
|
-
This matcher yields the part before the extension.
|
319
|
-
matchers, this matcher assumes terminal behavior, it doesn't match if there
|
320
|
-
are additional segments.
|
406
|
+
This matcher yields the part before the extension.
|
321
407
|
|
322
408
|
==== :method
|
323
409
|
|
324
410
|
This matches the method of the request. You can provide an array to specify multiple
|
325
411
|
request methods and match on any of them:
|
326
412
|
|
327
|
-
:method => :post matches POST
|
328
|
-
:method =>
|
413
|
+
{:method => :post} # matches POST
|
414
|
+
{:method => ['post', 'patch']} # matches POST and PATCH
|
329
415
|
|
330
416
|
==== :param
|
331
417
|
|
332
418
|
The :param matcher matches if the given parameter is present, even if empty.
|
333
419
|
|
334
|
-
:param => "user" matches "/foo?user=bar", "/foo?user="
|
335
|
-
:param => "user" does not matches "/foo"
|
420
|
+
{:param => "user"} # matches "/foo?user=bar", "/foo?user="
|
421
|
+
{:param => "user"} # does not matches "/foo"
|
336
422
|
|
337
423
|
==== :param!
|
338
424
|
|
339
425
|
The :param! matcher matches if the given parameter is present and not empty.
|
340
426
|
|
341
|
-
:param! => "user" matches "/foo?user=bar"
|
342
|
-
:param! => "user" does not matches "/foo", "/foo?user="
|
427
|
+
{:param! => "user"} # matches "/foo?user=bar"
|
428
|
+
{:param! => "user"} # does not matches "/foo", "/foo?user="
|
343
429
|
|
344
430
|
=== false, nil
|
345
431
|
|
@@ -361,10 +447,8 @@ You can always set the status code manually via the status attribute
|
|
361
447
|
for the response.
|
362
448
|
|
363
449
|
route do |r|
|
364
|
-
r.get do
|
365
|
-
|
366
|
-
response.status = 200
|
367
|
-
end
|
450
|
+
r.get "hello" do
|
451
|
+
response.status = 200
|
368
452
|
end
|
369
453
|
end
|
370
454
|
|
@@ -372,22 +456,27 @@ for the response.
|
|
372
456
|
|
373
457
|
The main match method is +r.on+, but as displayed above, you can also
|
374
458
|
use +r.get+ or +r.post+. When called without any arguments, these
|
375
|
-
|
459
|
+
match as long as the request has the appropriate method, so:
|
460
|
+
|
461
|
+
r.get do end
|
376
462
|
|
377
|
-
|
463
|
+
matches any +GET+ request, and
|
378
464
|
|
379
|
-
|
465
|
+
r.post do end
|
380
466
|
|
381
|
-
|
467
|
+
matches any +POST+ request
|
382
468
|
|
383
|
-
If any arguments are given to the method, these
|
384
|
-
the request
|
469
|
+
If any arguments are given to the method, these match only
|
470
|
+
if the request method matches, all arguments match, and
|
471
|
+
only the path has been fully matched by the arguments. So:
|
385
472
|
|
386
|
-
|
473
|
+
r.post "" do end
|
387
474
|
|
388
|
-
|
475
|
+
matches only +POST+ requests where the current path is +/+.
|
389
476
|
|
390
|
-
|
477
|
+
r.get "a/b" do end
|
478
|
+
|
479
|
+
matches only +GET+ requests where the current path is +/a/b+.
|
391
480
|
|
392
481
|
The reason for this difference in behavior is that if you are not
|
393
482
|
providing any arguments, you probably don't want to to also test
|
@@ -400,17 +489,17 @@ you do want, you can provide true as an argument:
|
|
400
489
|
end
|
401
490
|
|
402
491
|
If you want to match the request method and do a partial match
|
403
|
-
on the request path, you need to use
|
404
|
-
hash matcher:
|
492
|
+
on the request path instead of a full match, you need to use
|
493
|
+
+r.on+ with the <tt>:method</tt> hash matcher:
|
405
494
|
|
406
495
|
r.on "foo", :method=>:get do # Matches GET /foo(/.*)?
|
407
|
-
|
496
|
+
end
|
408
497
|
|
409
498
|
== Root Method
|
410
499
|
|
411
500
|
As displayed above, you can also use +r.root+ as a match method. This
|
412
|
-
method matches
|
413
|
-
except that it does not consume the +/+ from the path.
|
501
|
+
method matches +GET+ requests where the current path +/+. +r.root+ is
|
502
|
+
similar to <tt>r.get ""</tt>, except that it does not consume the +/+ from the path.
|
414
503
|
|
415
504
|
Unlike the other matching methods, +r.root+ takes no arguments.
|
416
505
|
|
@@ -438,8 +527,8 @@ methods, or via plugins.
|
|
438
527
|
|
439
528
|
== Pollution
|
440
529
|
|
441
|
-
Roda tries very hard to avoid polluting the scope
|
442
|
-
block
|
530
|
+
Roda tries very hard to avoid polluting the scope of the +route+
|
531
|
+
block. The only instance variables defined by default in the scope of
|
443
532
|
the +route+ block are <tt>@_request</tt> and <tt>@_response</tt>. The only methods defined
|
444
533
|
(beyond the default methods for +Object+) are: +env+, +opts+, +request+,
|
445
534
|
+response+, +call+, +session+, and +_route+ (private). Constants inside the
|
@@ -476,8 +565,8 @@ in the request (via POST or QUERY_STRING) and it pushes the value as a capture.
|
|
476
565
|
|
477
566
|
== Composition
|
478
567
|
|
479
|
-
You can mount
|
480
|
-
|
568
|
+
You can mount any Rack app (including another Roda app), with its own middlewares,
|
569
|
+
inside a Roda app, using +r.run+:
|
481
570
|
|
482
571
|
class API < Roda
|
483
572
|
use SomeMiddleware
|
@@ -499,13 +588,24 @@ via +r.run+:
|
|
499
588
|
|
500
589
|
run App.app
|
501
590
|
|
502
|
-
|
591
|
+
This will take any path starting with +/api+ and send it to +API+. In this
|
592
|
+
example, +API+ is a Roda app, but it could easily be a Sinatra, Rails, or
|
593
|
+
other Rack app.
|
594
|
+
|
595
|
+
When you use +r.run+, Roda calls the given Rack app (+API+ in this
|
596
|
+
case), and whatever the Rack app returns will be returned as the response
|
597
|
+
for the current application.
|
598
|
+
|
599
|
+
=== multi_route plugin
|
600
|
+
|
601
|
+
If you are just looking to split up the main route block up by branches, you
|
602
|
+
should use the +multi_route+ plugin, which keeps the current scope of
|
503
603
|
the route block:
|
504
604
|
|
505
605
|
class App < Roda
|
506
606
|
plugin :multi_route
|
507
607
|
|
508
|
-
route
|
608
|
+
route "api" do |r|
|
509
609
|
r.is do
|
510
610
|
# ...
|
511
611
|
end
|
@@ -513,13 +613,16 @@ the route block:
|
|
513
613
|
|
514
614
|
route do |r|
|
515
615
|
r.on "api" do
|
516
|
-
route
|
616
|
+
r.route "api"
|
517
617
|
end
|
518
618
|
end
|
519
619
|
end
|
520
620
|
|
521
621
|
run App.app
|
522
622
|
|
623
|
+
This allows you to set instance variables in the main route block, and still
|
624
|
+
have access to them inside the +api+ route block.
|
625
|
+
|
523
626
|
== Testing
|
524
627
|
|
525
628
|
It is very easy to test Roda with {Rack::Test}[https://github.com/brynary/rack-test]
|
@@ -656,6 +759,8 @@ Note that unlike most other render options, the :escape option
|
|
656
759
|
must be passed to the <tt>plugin :render</tt> call, it won't be
|
657
760
|
respected if added later.
|
658
761
|
|
762
|
+
This support requires {Erubis}[http://www.kuwata-lab.com/erubis/].
|
763
|
+
|
659
764
|
=== Other
|
660
765
|
|
661
766
|
For prevention of some other vulnerabilities, such as click-jacking,
|
@@ -687,6 +792,8 @@ content_for :: Allows storage of content in one template and retrieval of
|
|
687
792
|
csrf :: Adds CSRF protection and helper methods using
|
688
793
|
{rack_csrf}[https://github.com/baldowl/rack_csrf].
|
689
794
|
default_headers :: Override the default response headers used.
|
795
|
+
error_email :: Adds an +error_email+ method that can be used to email when
|
796
|
+
an exception is raised.
|
690
797
|
error_handler :: Adds a +error+ block that is called for all responses that
|
691
798
|
raise exceptions.
|
692
799
|
flash :: Adds a flash handler.
|
@@ -710,6 +817,7 @@ not_found :: Adds a +not_found+ block that is called for all 404 responses
|
|
710
817
|
without bodies.
|
711
818
|
pass :: Adds a pass method allowing you to skip the current +r.on+ block as if
|
712
819
|
it did not match.
|
820
|
+
path :: Adds support for named paths.
|
713
821
|
per_thread_caching :: Switches the thread-safe cache from a shared cache to a
|
714
822
|
per-thread cache.
|
715
823
|
render :: Adds support for rendering templates via tilt, as described above.
|