roda-cj 0.9.6 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.
|