expressr 0.0.2 → 0.0.3
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/README.md +725 -0
- data/lib/expressr.rb +7 -1
- data/lib/expressr/app.rb +108 -0
- data/lib/expressr/json.rb +15 -0
- data/lib/expressr/listeners/request.rb +11 -0
- data/lib/expressr/listeners/response.rb +11 -0
- data/lib/expressr/renderer.rb +39 -0
- data/lib/expressr/renderers.rb +9 -0
- data/lib/expressr/renderers/base.rb +10 -0
- data/lib/expressr/renderers/haml.rb +13 -0
- data/lib/expressr/renderers/slim.rb +12 -0
- data/lib/expressr/request.rb +118 -0
- data/lib/expressr/response.rb +188 -0
- data/lib/expressr/route.rb +33 -0
- data/lib/expressr/route_item.rb +103 -0
- data/lib/expressr/route_node.rb +22 -0
- data/lib/expressr/router.rb +68 -0
- data/lib/expressr/utils.rb +46 -0
- data/lib/expressr/version.rb +1 -1
- metadata +98 -3
- data/Rakefile +0 -12
data/README.md
CHANGED
@@ -0,0 +1,725 @@
|
|
1
|
+
Expressr
|
2
|
+
=======
|
3
|
+
Express.js for Ruby
|
4
|
+
|
5
|
+
Overview
|
6
|
+
--------
|
7
|
+
|
8
|
+
Expressr brings the architecture of Express.js to Ruby. It's a minimal and flexible web application framework that couples the concepts of Express.js and Node.js with the beauty of Ruby.
|
9
|
+
|
10
|
+
Expressr runs on top of [Noder](https://github.com/tombenner/noder) (Node.js for Ruby).
|
11
|
+
|
12
|
+
Quick Start
|
13
|
+
-----------
|
14
|
+
|
15
|
+
A web app can be created and started using the following script:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
require 'expressr'
|
19
|
+
|
20
|
+
app = Expressr::App.new
|
21
|
+
|
22
|
+
app.get('/hello.txt') do |request, response|
|
23
|
+
response.out('Hello World')
|
24
|
+
end
|
25
|
+
|
26
|
+
app.listen(3000)
|
27
|
+
```
|
28
|
+
|
29
|
+
To start the app, put the code into a file named `my_app.rb` and run it:
|
30
|
+
|
31
|
+
```bash
|
32
|
+
$ ruby my_app.rb
|
33
|
+
Running Noder at 0.0.0.0:3000...
|
34
|
+
```
|
35
|
+
|
36
|
+
Examples
|
37
|
+
--------
|
38
|
+
|
39
|
+
Here are some other examples of common usage:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
require 'expressr'
|
43
|
+
|
44
|
+
app = Expressr::App.new
|
45
|
+
|
46
|
+
# Log every request to URLs beginning with /admin/
|
47
|
+
app.all('/admin/*') do |request, response|
|
48
|
+
Noder.logger.info "#{request.locals.user} accessed #{request.url}"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Render JSON
|
52
|
+
app.get('/some_json') do |request, response|
|
53
|
+
response.out({ some: 'json' })
|
54
|
+
end
|
55
|
+
|
56
|
+
# Render a view
|
57
|
+
app.get('/users/:id') do (request, response)
|
58
|
+
Noder.with ->{ User.find(request.params.id) } do |user|
|
59
|
+
response.render('users/show', user: user.attributes)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Respond to a POST request by creating a record and then redirecting
|
64
|
+
app.post('/comment') do |request, response|
|
65
|
+
Noder.with ->{ Comment.create(request.params.comment) } do |comment|
|
66
|
+
response.redirect("/comment/#{comment.id}")
|
67
|
+
endd
|
68
|
+
end
|
69
|
+
|
70
|
+
app.listen(3000)
|
71
|
+
```
|
72
|
+
|
73
|
+
See the API section below for complete documentation.
|
74
|
+
|
75
|
+
Please note that the datastore-related lines in the examples above will block the event loop as written. You'll want to use [EM-Synchrony](https://github.com/igrigorik/em-synchrony)'s support for whichever datastore you're using and for other IO operations.
|
76
|
+
|
77
|
+
API
|
78
|
+
---
|
79
|
+
|
80
|
+
### Expressr::App
|
81
|
+
|
82
|
+
`Expressr::App` lets you create and run web apps.
|
83
|
+
|
84
|
+
#### Settings
|
85
|
+
|
86
|
+
An app has settings which configure it:
|
87
|
+
|
88
|
+
* `'jsonp callback name'` - The param used for determining the JSONP callback's name. The default is `'callback'` (e.g. for `?callback=myFunction`).
|
89
|
+
* `'locals'` - A hash of name-value pairs that will be passed to views as local variables.
|
90
|
+
* `'root'` - The root directory of the app. This is set automatically.
|
91
|
+
* `'view engine'` - The template engine used for views. The default is `'slim'`, and `'haml'` is also supported.
|
92
|
+
* `'views'` - The path to the views within the app's root directory. The default value is `'views'`.
|
93
|
+
|
94
|
+
Settings can be set using `#set` and retrieved using `#get`:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
app.set('view engine', 'haml')
|
98
|
+
app.get('view engine') # "haml"
|
99
|
+
```
|
100
|
+
|
101
|
+
A hash of all settings can be accessed by using `app.settings`.
|
102
|
+
|
103
|
+
#### .new(server_options={})
|
104
|
+
|
105
|
+
Creates the app.
|
106
|
+
|
107
|
+
##### server_options
|
108
|
+
|
109
|
+
Please see [Noder's docs](https://github.com/tombenner/noder) for the options that can be passed to `Noder::HTTP::Server`. These include options like the server's address, port, whether HTTPS is enabled, etc.
|
110
|
+
|
111
|
+
#### #set(name, value)
|
112
|
+
|
113
|
+
Sets the value of a setting.
|
114
|
+
|
115
|
+
#### #get(name)
|
116
|
+
|
117
|
+
Gets the value of a setting.
|
118
|
+
|
119
|
+
#### #enable(name)
|
120
|
+
|
121
|
+
Sets the value of a setting to `true`.
|
122
|
+
|
123
|
+
#### #disable(name)
|
124
|
+
|
125
|
+
Sets the value of a setting to `false`.
|
126
|
+
|
127
|
+
#### #enabled?(name)
|
128
|
+
|
129
|
+
Returns a boolean of whether the setting is enabled or not.
|
130
|
+
|
131
|
+
#### #disabled?(name)
|
132
|
+
|
133
|
+
Returns a boolean of whether the setting is disabled or not.
|
134
|
+
|
135
|
+
#### #engine(value)
|
136
|
+
|
137
|
+
Sets the view engine. This is the equivalent of `set('view engine', value)`. Valid values are `'slim'` and `'haml'`.
|
138
|
+
|
139
|
+
#### #param(name, &block)
|
140
|
+
|
141
|
+
Registers a listener for any request that includes the specified param. For example, in a request is made to `/user/5` (with a `/user/:user_id` route) or `/profile?user_id=5`, the following will the log the `user_id` value:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
app.param('user_id') do |request, response, continue, user_id|
|
145
|
+
user = User.find(user_id)
|
146
|
+
if user
|
147
|
+
request.locals.user = user
|
148
|
+
else
|
149
|
+
Noder.logger.info "User not found: #{user_id}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
```
|
153
|
+
|
154
|
+
#### #VERB(path, &block)
|
155
|
+
|
156
|
+
Registers a listener for any request that matches the VERB (e.g. `get`, `post`, `put`, `delete`) and the path.
|
157
|
+
|
158
|
+
Respond with `Welcome!` for GET requests to `/welcome`:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
app.get('/welcome') do |request, response|
|
162
|
+
response.out('Welcome!')
|
163
|
+
end
|
164
|
+
```
|
165
|
+
|
166
|
+
Respond with JSON for POST requests to `/user/5/settings`:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
app.post('/user/:id/settings') do |request, response|
|
170
|
+
response.out({
|
171
|
+
user_id: request.params.id,
|
172
|
+
params: request.params
|
173
|
+
})
|
174
|
+
end
|
175
|
+
```
|
176
|
+
|
177
|
+
Regular expressions can also be used:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
app.get(/^\/commits\/(\w+)\.\.(\w+)/) do |request, response|
|
181
|
+
response.out({
|
182
|
+
from: request.params[0],
|
183
|
+
to: request.params[1]
|
184
|
+
})
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
#### #all(path, &block)
|
189
|
+
|
190
|
+
This method functions just like the `#VERB(path, &block)` method, but it matches all HTTP verbs.
|
191
|
+
|
192
|
+
It's very useful for creating global logic for all requests or for requests to specific paths:
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
app.all('/admin/*') do |request, response|
|
196
|
+
if !is_admin?
|
197
|
+
response.status = 403
|
198
|
+
response.out('Not authorized.')
|
199
|
+
end
|
200
|
+
end
|
201
|
+
```
|
202
|
+
|
203
|
+
#### #route(path)
|
204
|
+
|
205
|
+
Returns an instance of a single route which can then be used to handle HTTP verbs with optional middleware. Using `#route(path)` is a recommended approach to avoiding duplicate route naming and thus typo errors.
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
app.route('/users').
|
209
|
+
all do |request, response|
|
210
|
+
Noder.logger.info "Users request performed"
|
211
|
+
end.
|
212
|
+
get do |request, response|
|
213
|
+
response.out(User.find(request.params.user_id))
|
214
|
+
end.
|
215
|
+
post do |request, response|
|
216
|
+
user = User.create(request.params.user)
|
217
|
+
response.out(user.attributes)
|
218
|
+
end
|
219
|
+
```
|
220
|
+
|
221
|
+
#### #locals
|
222
|
+
|
223
|
+
Application local variables are provided to all templates rendered within the application. This is useful for providing helper functions to templates, as well as app-level data.
|
224
|
+
|
225
|
+
```ruby
|
226
|
+
app.locals.site_name = 'My Site'
|
227
|
+
app.locals.contact_email = 'contact@mysite.com'
|
228
|
+
```
|
229
|
+
|
230
|
+
#### #listen(port=nil, address=nil, &block)
|
231
|
+
|
232
|
+
Bind and listen for connections on the given host and port. This method is identical to Noder's `Noder::HTTP::Server#listen`.
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
app = Expressr::App.new
|
236
|
+
app.get('/hello.txt') do |request, response|
|
237
|
+
response.out('Hello World')
|
238
|
+
end
|
239
|
+
app.listen(3000)
|
240
|
+
```
|
241
|
+
|
242
|
+
A block which will be called for all requests can be passed to it, too:
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
app = Expressr::App.new
|
246
|
+
app.listen do |request, response|
|
247
|
+
response.out('Hello World')
|
248
|
+
end
|
249
|
+
```
|
250
|
+
|
251
|
+
#### #close
|
252
|
+
|
253
|
+
Stops the app. This is the same as Noder's `Noder::HTTP::Server#close` and is called when an `INT` or `TERM` signal is sent to a running server's process (e.g. when `Control-C` is pressed).
|
254
|
+
|
255
|
+
#### #settings
|
256
|
+
|
257
|
+
A hash of the app's settings:
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
app.set('my setting', 'My value')
|
261
|
+
value = app.settings['my setting']
|
262
|
+
```
|
263
|
+
|
264
|
+
### Expressr::Request
|
265
|
+
|
266
|
+
`Expressr::Request` inherits from (and thus also includes methods from) `Noder::HTTP::Request`.
|
267
|
+
|
268
|
+
#### #params
|
269
|
+
|
270
|
+
Similar to Rails' `params`, this includes params from the query string, POST data, and route parameters. Params can be accessed in three ways: `params.user_id`, `params[:user_id]`, or `params['user_id']`.
|
271
|
+
|
272
|
+
For example, a request to `/user/3?comment_id=4` will include two params:
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
app.get('/user/:user_id') do |request, response|
|
276
|
+
response.out({
|
277
|
+
user_id: request.params.user_id,
|
278
|
+
comment_id: request.params.comment_id
|
279
|
+
})
|
280
|
+
end
|
281
|
+
```
|
282
|
+
|
283
|
+
If a regex route is used, the matches can be accessed at their integer indexes:
|
284
|
+
|
285
|
+
```ruby
|
286
|
+
app.get(/\/user\/(\d+)\/comment\/(\d+)/) do |request, response|
|
287
|
+
response.out({
|
288
|
+
user_id: request.params[0],
|
289
|
+
comment_id: request.params[1]
|
290
|
+
})
|
291
|
+
end
|
292
|
+
```
|
293
|
+
|
294
|
+
#### #query
|
295
|
+
|
296
|
+
Similar to `#params`, but it only includes params from the query string.
|
297
|
+
|
298
|
+
For example, a request to `/user/3?comment_id=4` will only include `comment_id`:
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
app.get('/user/:user_id') do |request, response|
|
302
|
+
response.out({
|
303
|
+
comment_id: request.query.comment_id
|
304
|
+
})
|
305
|
+
end
|
306
|
+
```
|
307
|
+
|
308
|
+
#### #param(name)
|
309
|
+
|
310
|
+
Returns the value of param `name` when present. This is the equivalent of `params.name` or `params[name]`, which are the preferred forms.
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
request.param('user_id')
|
314
|
+
```
|
315
|
+
|
316
|
+
#### #get(name)
|
317
|
+
|
318
|
+
Returns the value of the `name` header when present.
|
319
|
+
|
320
|
+
```ruby
|
321
|
+
request.get('Content-Type') # "text/plain"
|
322
|
+
request.get('Something') # nil
|
323
|
+
```
|
324
|
+
|
325
|
+
Aliased as `#header(name)`.
|
326
|
+
|
327
|
+
#### #accepts(types)
|
328
|
+
|
329
|
+
Check if the given types are acceptable, returning the best match when true, otherwise `nil`.
|
330
|
+
|
331
|
+
```ruby
|
332
|
+
# Accept: text/*, application/json
|
333
|
+
request.accepts('text/html') # "text/html"
|
334
|
+
request.accepts('image/png') # nil
|
335
|
+
```
|
336
|
+
|
337
|
+
#### #is?(type)
|
338
|
+
|
339
|
+
Check if the given types are acceptable, returning the best match when true, otherwise `nil`.
|
340
|
+
|
341
|
+
```ruby
|
342
|
+
# Content-Type: text/html; charset=utf-8
|
343
|
+
request.is('text/html') # true
|
344
|
+
request.is('image/png') # false
|
345
|
+
```
|
346
|
+
|
347
|
+
#### #ip
|
348
|
+
|
349
|
+
Returns the remote IP address.
|
350
|
+
|
351
|
+
```ruby
|
352
|
+
request.ip # "68.1.8.45"
|
353
|
+
```
|
354
|
+
|
355
|
+
#### #path
|
356
|
+
|
357
|
+
Returns the path of the requested URL.
|
358
|
+
|
359
|
+
```ruby
|
360
|
+
# example.com/users?sort=desc
|
361
|
+
request.path # "/users"
|
362
|
+
```
|
363
|
+
|
364
|
+
#### #host
|
365
|
+
|
366
|
+
Returns the hostname from the "Host" header field (without the port).
|
367
|
+
|
368
|
+
```ruby
|
369
|
+
# Host: "example.com:3000"
|
370
|
+
request.host # "example.com"
|
371
|
+
```
|
372
|
+
|
373
|
+
#### #xhr?
|
374
|
+
|
375
|
+
Check whether the request was issued with the "X-Requested-With" header field set to "XMLHttpRequest" (jQuery etc).
|
376
|
+
|
377
|
+
```ruby
|
378
|
+
# Host: "example.com:3000"
|
379
|
+
request.xhr? # false
|
380
|
+
```
|
381
|
+
|
382
|
+
#### #protocol
|
383
|
+
|
384
|
+
Returns the protocol string of the request (e.g. `'http'`, `'https'`).
|
385
|
+
|
386
|
+
```ruby
|
387
|
+
# "http://example.com/"
|
388
|
+
request.protocol # 'http'
|
389
|
+
```
|
390
|
+
|
391
|
+
#### #secure?
|
392
|
+
|
393
|
+
Checks whether a TLS connection is established. This is the equivalent of `request.protocol == 'https'`.
|
394
|
+
|
395
|
+
```ruby
|
396
|
+
# "http://example.com/"
|
397
|
+
request.secure? # false
|
398
|
+
```
|
399
|
+
|
400
|
+
#### #subdomains
|
401
|
+
|
402
|
+
Returns the subdomains as an array
|
403
|
+
|
404
|
+
```ruby
|
405
|
+
# Host: "tobi.ferrets.example.com"
|
406
|
+
request.subdomains # ["ferrets", "tobi"]
|
407
|
+
```
|
408
|
+
|
409
|
+
#### #original_url
|
410
|
+
|
411
|
+
This is similar to `#url`, except that it retains the original URL, allowing you to rewrite `#url` freely.
|
412
|
+
|
413
|
+
```ruby
|
414
|
+
# /search?q=something
|
415
|
+
request.original_url # "/search?q=something"
|
416
|
+
```
|
417
|
+
|
418
|
+
### Expressr::Response
|
419
|
+
|
420
|
+
`Expressr::Response` inherits from (and thus also includes methods from) `Noder::HTTP::Response`.
|
421
|
+
|
422
|
+
#### #set(name, value=nil)
|
423
|
+
|
424
|
+
Set a header's value, or pass a hash as a single argument to set multiple headers at once.
|
425
|
+
|
426
|
+
```ruby
|
427
|
+
response.set('Content-Type', 'text/plain')
|
428
|
+
response.set({
|
429
|
+
'Content-Type' => 'text/plain',
|
430
|
+
'Content-Length' => '123',
|
431
|
+
'ETag' => '12345'
|
432
|
+
})
|
433
|
+
```
|
434
|
+
|
435
|
+
#### #get(name)
|
436
|
+
|
437
|
+
Returns a header's value.
|
438
|
+
|
439
|
+
```ruby
|
440
|
+
response.get('Content-Type') # "text/plain"
|
441
|
+
```
|
442
|
+
|
443
|
+
#### #cookie(name, value, options={})
|
444
|
+
|
445
|
+
Sets a cookie. All of the options supported by [CGI::Cookie](http://ruby-doc.org/stdlib-1.9.3/libdoc/cgi/rdoc/CGI/Cookie.html) are supported.
|
446
|
+
|
447
|
+
```ruby
|
448
|
+
response.cookie('user_id', '15')
|
449
|
+
response.cookie('remember_me', '1', {
|
450
|
+
'expires' => Time.now + 14.days,
|
451
|
+
'domain' => 'example.com'
|
452
|
+
})
|
453
|
+
```
|
454
|
+
|
455
|
+
#### #clear_cookie(name, value, options={})
|
456
|
+
|
457
|
+
Sets a cookie. All of the options supported by [CGI::Cookie](http://ruby-doc.org/stdlib-1.9.3/libdoc/cgi/rdoc/CGI/Cookie.html) are supported.
|
458
|
+
|
459
|
+
```ruby
|
460
|
+
response.cookie('user_id', '15')
|
461
|
+
response.clear_cookie('user_id')
|
462
|
+
```
|
463
|
+
|
464
|
+
#### #redirect(status_or_url, url=nil)
|
465
|
+
|
466
|
+
Redirects to the specified URL with an optional status (default is `302`).
|
467
|
+
|
468
|
+
```ruby
|
469
|
+
response.redirect('/foo/bar')
|
470
|
+
response.redirect(303, '/foo/bar')
|
471
|
+
response.redirect('https://www.google.com')
|
472
|
+
```
|
473
|
+
|
474
|
+
#### #location(url)
|
475
|
+
|
476
|
+
Sets the `Location` header's value.
|
477
|
+
|
478
|
+
```ruby
|
479
|
+
response.location('/foo/bar')
|
480
|
+
response.location('https://www.google.com')
|
481
|
+
```
|
482
|
+
|
483
|
+
#### #out(status_or_content=nil, content=nil)
|
484
|
+
|
485
|
+
Sends the response. (This is the equivalent of Express.js's `send` method, which has another use in Ruby.)
|
486
|
+
|
487
|
+
```ruby
|
488
|
+
response.out({ some: 'json' })
|
489
|
+
response.out('some html')
|
490
|
+
response.out(404, 'Sorry, we cannot find that!')
|
491
|
+
response.out(500, { error: 'something blew up' })
|
492
|
+
response.out(200)
|
493
|
+
```
|
494
|
+
|
495
|
+
When the content is a string, the Content-Type is set to `text/html`.
|
496
|
+
|
497
|
+
When the content is a hash, the hash is converted to JSON and the Content-Type is set to `application/json`.
|
498
|
+
|
499
|
+
#### #json(status_or_content=nil, content=nil)
|
500
|
+
|
501
|
+
Sends a JSON response. This identical to `#out` when an array or object is passed.
|
502
|
+
|
503
|
+
```ruby
|
504
|
+
response.json({ some: 'json' })
|
505
|
+
response.json(500, { error: 'something blew up' })
|
506
|
+
```
|
507
|
+
|
508
|
+
#### #jsonp(status_or_content=nil, content=nil)
|
509
|
+
|
510
|
+
Sends a JSONP response. This identical to `#json`, but it provides JSONP support if the request specifies a JSONP callback.
|
511
|
+
|
512
|
+
```ruby
|
513
|
+
# /?callback=foo
|
514
|
+
response.jsonp({ some: 'json' }) # "foo({"some":"json"});"
|
515
|
+
# /
|
516
|
+
response.jsonp({ some: 'json' }) # "{"some":"json"}"
|
517
|
+
```
|
518
|
+
|
519
|
+
The JSONP callback name defaults to `'callback'`, but it can be set using the app's settings:
|
520
|
+
|
521
|
+
```ruby
|
522
|
+
app.settings.set('jsonp callback name', 'cb')
|
523
|
+
# /?cb=foo
|
524
|
+
response.jsonp({ some: 'json' }) # "foo({"some":"json"});"
|
525
|
+
```
|
526
|
+
|
527
|
+
#### #type(value)
|
528
|
+
|
529
|
+
Sets the `Content-Type` header to the value.
|
530
|
+
|
531
|
+
```ruby
|
532
|
+
response.type('html')
|
533
|
+
response.type('application/json')
|
534
|
+
```
|
535
|
+
|
536
|
+
#### #format(hash)
|
537
|
+
|
538
|
+
Performs content-negotiation on the request Accept header field when present.
|
539
|
+
|
540
|
+
```ruby
|
541
|
+
response.format({
|
542
|
+
'text/html' => proc { |request, response|
|
543
|
+
response.out("<h3>Some HTML</h3>")
|
544
|
+
},
|
545
|
+
'text/plain' => proc { |request, response|
|
546
|
+
response.out("Some text")
|
547
|
+
},
|
548
|
+
'application/json' => proc { |request, response|
|
549
|
+
response.out({ some: json })
|
550
|
+
},
|
551
|
+
})
|
552
|
+
```
|
553
|
+
|
554
|
+
Content type synonyms are supported (e.g. `'json'` and `'application/json'` are equivalent):
|
555
|
+
|
556
|
+
```ruby
|
557
|
+
response.format({
|
558
|
+
'html' => proc { |request, response|
|
559
|
+
response.out("<h3>Some HTML</h3>")
|
560
|
+
},
|
561
|
+
'text' => proc { |request, response|
|
562
|
+
response.out("Some text")
|
563
|
+
},
|
564
|
+
'json' => proc { |request, response|
|
565
|
+
response.out({ some: json })
|
566
|
+
},
|
567
|
+
})
|
568
|
+
```
|
569
|
+
|
570
|
+
#### #attachment(filename=nil)
|
571
|
+
|
572
|
+
Sets the Content-Disposition header field to "attachment". If a filename is given then the Content-Type will be automatically set based on the extension via `#type`, and the Content-Disposition's "filename=" parameter will be set.
|
573
|
+
|
574
|
+
```ruby
|
575
|
+
response.attachment
|
576
|
+
# Content-Disposition: attachment
|
577
|
+
|
578
|
+
response.attachment('path/to/logo.png')
|
579
|
+
# Content-Disposition: attachment; filename="logo.png"
|
580
|
+
# Content-Type: image/png
|
581
|
+
```
|
582
|
+
|
583
|
+
#### #send_file(path, options={})
|
584
|
+
|
585
|
+
Transfers the file at the given path.
|
586
|
+
|
587
|
+
Automatically defaults the Content-Type response header field based on the filename's extension.
|
588
|
+
|
589
|
+
##### options
|
590
|
+
|
591
|
+
* `root` - Root directory for relative filenames
|
592
|
+
|
593
|
+
```ruby
|
594
|
+
app.get('/user/:uid/photos/:file') do |request, response|
|
595
|
+
uid = request.params.uid
|
596
|
+
file = request.params.file
|
597
|
+
|
598
|
+
if request.locals.user.may_view_files_from(uid)
|
599
|
+
response.sendfile("/uploads/#{uid}/#{file}")
|
600
|
+
else
|
601
|
+
response.out(403, "Sorry! You can't see that.")
|
602
|
+
end
|
603
|
+
end
|
604
|
+
```
|
605
|
+
|
606
|
+
#### #download(path, filename=nil)
|
607
|
+
|
608
|
+
Transfer the file at path as an "attachment". Typically browsers will prompt the user for download. The Content-Disposition "filename=" parameter (the one that will appear in the brower dialog is set to path by default), but you can also provide an override filename.
|
609
|
+
|
610
|
+
```ruby
|
611
|
+
response.download('/report-12345.pdf')
|
612
|
+
response.download('/report-12345.pdf', 'report.pdf')
|
613
|
+
```
|
614
|
+
|
615
|
+
#### #links(links)
|
616
|
+
|
617
|
+
Join the given links to populate the "Link" response header field.
|
618
|
+
|
619
|
+
```ruby
|
620
|
+
response.links({
|
621
|
+
next: 'http://api.example.com/users?page=2',
|
622
|
+
last: 'http://api.example.com/users?page=5'
|
623
|
+
})
|
624
|
+
|
625
|
+
# Link: <http://api.example.com/users?page=2>; rel="next",
|
626
|
+
# <http://api.example.com/users?page=5>; rel="last"
|
627
|
+
```
|
628
|
+
|
629
|
+
#### #locals
|
630
|
+
|
631
|
+
Response local variables are scoped to the request, thus only available to the view(s) rendered during that request / response cycle, if any.
|
632
|
+
|
633
|
+
This object is useful for exposing request-level information such as the request pathname, authenticated user, user settings, etc.
|
634
|
+
|
635
|
+
```ruby
|
636
|
+
app.use do (request, response)
|
637
|
+
response.locals.user = User.find(request.params.user_id)
|
638
|
+
response.locals.authenticated = !response.locals.user.is_anonymous?
|
639
|
+
end
|
640
|
+
```
|
641
|
+
|
642
|
+
#### #render(view, locals=nil, &block)
|
643
|
+
|
644
|
+
Renders a `view`. The view's local variables are supplied by both the `locals` argument and the app's `locals` setting. If the rendering raises an exception, the `&block` is called with the exception as an argument.
|
645
|
+
|
646
|
+
```ruby
|
647
|
+
app.get('/users/:id') do (request, response)
|
648
|
+
user = User.find(request.params.id)
|
649
|
+
response.render('profile', user: user.attributes)
|
650
|
+
end
|
651
|
+
|
652
|
+
app.get('/contact') do (request, response)
|
653
|
+
response.render('contact') do |exception|
|
654
|
+
response.render('error')
|
655
|
+
end
|
656
|
+
end
|
657
|
+
```
|
658
|
+
|
659
|
+
To set the locals that will be passed to all views, use:
|
660
|
+
|
661
|
+
```ruby
|
662
|
+
app.locals.site_name = 'My Site'
|
663
|
+
app.locals.contact_email = 'contact@mysite.com'
|
664
|
+
```
|
665
|
+
|
666
|
+
By default, Expressr looks for views in the `views` directory (e.g. `views/profile.slim`).
|
667
|
+
|
668
|
+
To set the directory of the views, use:
|
669
|
+
|
670
|
+
```ruby
|
671
|
+
app.set('views', File.expand_path('../my_views', __FILE__))
|
672
|
+
```
|
673
|
+
|
674
|
+
Expressr uses the Slim template engine by default, but it also supports Haml:
|
675
|
+
|
676
|
+
```ruby
|
677
|
+
app.set('view engine', 'haml')
|
678
|
+
```
|
679
|
+
|
680
|
+
If you'd like to add support for other template engines, doing so is fairly straightforward; just grep for `'slim'` in the codebase, and the steps needed to support a new engine should be clear.
|
681
|
+
|
682
|
+
### Expressr::Router
|
683
|
+
|
684
|
+
`Expressr::App` lets you create routes for your app. An app's router can be accessed at `app.router`.
|
685
|
+
|
686
|
+
```ruby
|
687
|
+
app = Expressr::App.new
|
688
|
+
app.router.get('/hello.txt') do |request, response|
|
689
|
+
response.out('Hello World')
|
690
|
+
end
|
691
|
+
```
|
692
|
+
|
693
|
+
#### #use(path=nil, &block)
|
694
|
+
|
695
|
+
Please see the documentation for `Expressr::App#use`, which has the same behavior.
|
696
|
+
|
697
|
+
#### #param(name, &block)
|
698
|
+
|
699
|
+
Please see the documentation for `Expressr::App#use`, which has the same behavior.
|
700
|
+
|
701
|
+
#### #use(path=nil, &block)
|
702
|
+
|
703
|
+
Please see the documentation for `Expressr::App#use`, which has the same behavior.
|
704
|
+
|
705
|
+
#### #VERB(path, &block)
|
706
|
+
|
707
|
+
Please see the documentation for `Expressr::App#use`, which has the same behavior.
|
708
|
+
|
709
|
+
#### #use(path=nil, &block)
|
710
|
+
|
711
|
+
Please see the documentation for `Expressr::App#use`, which has the same behavior.
|
712
|
+
|
713
|
+
#### #use(path=nil, &block)
|
714
|
+
|
715
|
+
Please see the documentation for `Expressr::App#use`, which has the same behavior.
|
716
|
+
|
717
|
+
#### #use(path=nil, &block)
|
718
|
+
|
719
|
+
Please see the documentation for `Expressr::App#use`, which has the same behavior.
|
720
|
+
|
721
|
+
|
722
|
+
License
|
723
|
+
-------
|
724
|
+
|
725
|
+
Expressr is released under the MIT License. Please see the MIT-LICENSE file for details.
|