hobby 0.0.6 → 0.0.7
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.
- checksums.yaml +4 -4
- data/Gemfile +2 -1
- data/hobby.gemspec +1 -1
- data/lib/hobby.rb +4 -0
- data/readme.adoc +360 -0
- data/spec/app_spec.rb +1 -1
- data/spec/apps/{Throw.rb → Halting.rb} +2 -1
- metadata +6 -6
- data/README.md +0 -378
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c943dce2451a4154082cfe2d8fc823273b28c627
|
4
|
+
data.tar.gz: 78ab9a63570bea6044c18307c8bb2cb7b355b935
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12fc9f283cd851d77de6132caa8ac74401854547b2f0f2639726857327dcf01da99fc8a7e962c924a0f1a644645576c94f51544e596eac98bf280f0a6ce11f9c
|
7
|
+
data.tar.gz: 3bb0e84f2b8195a51dbbe61bb37d7caea77cfda4dcf02ccea9812a7c037d0ce2d43ee13bf0e4fc12638cb3e5512f8aa24a0ac330460907da70878107b8ddc339
|
data/Gemfile
CHANGED
data/hobby.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'hobby'
|
7
|
-
spec.version = '0.0.
|
7
|
+
spec.version = '0.0.7'
|
8
8
|
spec.authors = ['Anatoly Chernow']
|
9
9
|
spec.email = ['chertoly@gmail.com']
|
10
10
|
spec.summary = %q{A minimal DSL over rack}
|
data/lib/hobby.rb
CHANGED
data/readme.adoc
ADDED
@@ -0,0 +1,360 @@
|
|
1
|
+
[[installation]]
|
2
|
+
== Installation
|
3
|
+
|
4
|
+
Add this line to your application's Gemfile:
|
5
|
+
|
6
|
+
[source,ruby]
|
7
|
+
----
|
8
|
+
gem 'hobby'
|
9
|
+
# or this if you want to use hobby master
|
10
|
+
# gem 'hobby', github: 'ch1c0t/hobby'
|
11
|
+
----
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
[source,bash]
|
16
|
+
----
|
17
|
+
$ bundle
|
18
|
+
----
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
[source,bash]
|
23
|
+
----
|
24
|
+
$ gem install hobby
|
25
|
+
----
|
26
|
+
|
27
|
+
[[introduction]]
|
28
|
+
== Introduction
|
29
|
+
|
30
|
+
Hobby features a Sinatra-like DSL, but in contrast to Sinatra,
|
31
|
+
Hobby applications behave like usual Ruby classes.
|
32
|
+
|
33
|
+
To create a Hobby application, you create a class and include `Hobby` in it.
|
34
|
+
For example:
|
35
|
+
|
36
|
+
[source,ruby]
|
37
|
+
----
|
38
|
+
require 'hobby'
|
39
|
+
|
40
|
+
class C
|
41
|
+
include Hobby
|
42
|
+
|
43
|
+
get("/hello") {
|
44
|
+
"Hello, world."
|
45
|
+
}
|
46
|
+
end
|
47
|
+
----
|
48
|
+
|
49
|
+
Then, you can create an instance of `C` with
|
50
|
+
|
51
|
+
[source,ruby]
|
52
|
+
----
|
53
|
+
C.new
|
54
|
+
----
|
55
|
+
|
56
|
+
which will return a Rack application(an object which complies to
|
57
|
+
http://rubydoc.info/github/rack/rack/master/file/SPEC[Rack SPEC]).
|
58
|
+
|
59
|
+
Because a Hobby application is just a Ruby class,
|
60
|
+
you can do with it pretty much anything
|
61
|
+
you would expect to be able to do with a Ruby class.
|
62
|
+
|
63
|
+
[[using-initialize]]
|
64
|
+
=== Using #initialize
|
65
|
+
|
66
|
+
You can set some state in `#initialize` and then use it in the route's action:
|
67
|
+
|
68
|
+
[source,ruby]
|
69
|
+
----
|
70
|
+
class C
|
71
|
+
include Hobby
|
72
|
+
|
73
|
+
def initialize name
|
74
|
+
@name = name
|
75
|
+
end
|
76
|
+
|
77
|
+
get("/hello") {
|
78
|
+
"Hello, #{@name}."
|
79
|
+
}
|
80
|
+
end
|
81
|
+
----
|
82
|
+
|
83
|
+
[[using-intance-methods]]
|
84
|
+
=== Using instance methods
|
85
|
+
[source,ruby]
|
86
|
+
----
|
87
|
+
class C
|
88
|
+
include Hobby
|
89
|
+
|
90
|
+
def initialize name
|
91
|
+
@name = name
|
92
|
+
end
|
93
|
+
|
94
|
+
def name
|
95
|
+
@name.upcase
|
96
|
+
end
|
97
|
+
|
98
|
+
get("/hello") {
|
99
|
+
"Hello, #{name}."
|
100
|
+
}
|
101
|
+
end
|
102
|
+
----
|
103
|
+
|
104
|
+
[[how-to-run]]
|
105
|
+
=== How to run
|
106
|
+
To run an application, you can put it into `config.ru`:
|
107
|
+
|
108
|
+
[source,ruby]
|
109
|
+
----
|
110
|
+
run C.new 'Hobby'
|
111
|
+
----
|
112
|
+
|
113
|
+
and then use `rackup`:
|
114
|
+
|
115
|
+
[source,bash]
|
116
|
+
----
|
117
|
+
$ rackup
|
118
|
+
----
|
119
|
+
|
120
|
+
Or, if you are using Rails, you can mount it in `config/routes.rb` with:
|
121
|
+
[source,ruby]
|
122
|
+
----
|
123
|
+
mount C.new('Hobby') => '/some_path'
|
124
|
+
----
|
125
|
+
|
126
|
+
[[features]]
|
127
|
+
Features
|
128
|
+
~~~~~~~~
|
129
|
+
|
130
|
+
* DSL inspired by http://www.sinatrarb.com/[Sinatra].
|
131
|
+
* https://github.com/luislavena/bench-micro[Speed].
|
132
|
+
* Extensible with standard ruby classes and modules, with no extra
|
133
|
+
logic. See https://github.com/ch1c0t/hobby-auth[hobby-auth] and
|
134
|
+
https://github.com/ch1c0t/hobby-json[hobby-json].
|
135
|
+
* Zero configuration.
|
136
|
+
|
137
|
+
[[routes]]
|
138
|
+
== Routes
|
139
|
+
|
140
|
+
For common HTTP verbs, Hobby provides the route definers(methods named accordingly):
|
141
|
+
|
142
|
+
[source,ruby]
|
143
|
+
----
|
144
|
+
class App
|
145
|
+
include Hobby
|
146
|
+
|
147
|
+
get '/' do
|
148
|
+
# ...
|
149
|
+
end
|
150
|
+
|
151
|
+
post '/' do
|
152
|
+
# ...
|
153
|
+
end
|
154
|
+
|
155
|
+
put '/' do
|
156
|
+
# ...
|
157
|
+
end
|
158
|
+
|
159
|
+
patch '/' do
|
160
|
+
# ...
|
161
|
+
end
|
162
|
+
|
163
|
+
delete '/' do
|
164
|
+
# ...
|
165
|
+
end
|
166
|
+
|
167
|
+
options '/' do
|
168
|
+
# ...
|
169
|
+
end
|
170
|
+
end
|
171
|
+
----
|
172
|
+
|
173
|
+
A definer should be called with a path(optional) and an action(passed as a block).
|
174
|
+
|
175
|
+
Calling a definer has a side effect of defining a route in the router.
|
176
|
+
When an incoming request matches a route,
|
177
|
+
the action is executed and a response is sent back to the client.
|
178
|
+
The return value of the action will be the `body` of the response.
|
179
|
+
|
180
|
+
If a path was omitted
|
181
|
+
[source,ruby]
|
182
|
+
----
|
183
|
+
get do
|
184
|
+
'The body returned to the HTTP client making the request.'
|
185
|
+
end
|
186
|
+
----
|
187
|
+
|
188
|
+
the action is attached to the root route, like if
|
189
|
+
[source,ruby]
|
190
|
+
----
|
191
|
+
get '/' do
|
192
|
+
'The body returned to the HTTP client making the request.'
|
193
|
+
end
|
194
|
+
----
|
195
|
+
|
196
|
+
were called.
|
197
|
+
|
198
|
+
|
199
|
+
[[default-methods]]
|
200
|
+
== Default methods
|
201
|
+
|
202
|
+
The following methods are predefined:
|
203
|
+
|
204
|
+
* `env`: a `Hash`, http://www.rubydoc.info/github/rack/rack/master/file/SPEC#The_Environment[a Rack environment].
|
205
|
+
* `request`: a http://www.rubydoc.info/gems/rack/Rack/Request[`Rack::Request`].
|
206
|
+
* `response`: a http://www.rubydoc.info/gems/rack/Rack/Response[`Rack::Response`].
|
207
|
+
* `my`: a `Hash` which stores route variables. See <<routes-with-variables>> for a usage example.
|
208
|
+
* `halt`: returns the `response` immediately. See <<halting>> for a usage example.
|
209
|
+
|
210
|
+
[[routes-with-variables]]
|
211
|
+
=== Routes with variables
|
212
|
+
|
213
|
+
[source,ruby]
|
214
|
+
----
|
215
|
+
class App
|
216
|
+
include Hobby
|
217
|
+
# matches both /hi/hobbit and /hi/patricio
|
218
|
+
get '/hi/:name' do
|
219
|
+
"Hello #{my[:name]}"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
----
|
223
|
+
|
224
|
+
[[halting]]
|
225
|
+
=== Halting
|
226
|
+
|
227
|
+
[source,ruby]
|
228
|
+
----
|
229
|
+
class App
|
230
|
+
include Hobby
|
231
|
+
|
232
|
+
use Rack::Session::Cookie, secret: SecureRandom.hex(64)
|
233
|
+
|
234
|
+
def session
|
235
|
+
env['rack.session']
|
236
|
+
end
|
237
|
+
|
238
|
+
get '/' do
|
239
|
+
response.status = 401
|
240
|
+
halt
|
241
|
+
'This line is never going to be returned.'
|
242
|
+
end
|
243
|
+
end
|
244
|
+
----
|
245
|
+
|
246
|
+
[[extensions]]
|
247
|
+
== Extensions
|
248
|
+
|
249
|
+
You can extend Hobby with usual modules:
|
250
|
+
|
251
|
+
[source,ruby]
|
252
|
+
----
|
253
|
+
module MyExtension
|
254
|
+
def do_something
|
255
|
+
# do something
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
class App
|
260
|
+
include Hobby
|
261
|
+
include MyExtension
|
262
|
+
|
263
|
+
get '/' do
|
264
|
+
do_something
|
265
|
+
'Hello World!'
|
266
|
+
end
|
267
|
+
end
|
268
|
+
----
|
269
|
+
|
270
|
+
[[available-extensions]]
|
271
|
+
=== Available extensions
|
272
|
+
|
273
|
+
* https://github.com/ch1c0t/hobby-json[hobby-json]: JSON requests and responses.
|
274
|
+
* https://github.com/ch1c0t/hobby-auth[hobby-auth]: User authorization.
|
275
|
+
|
276
|
+
|
277
|
+
[[using-rack-builder]]
|
278
|
+
== Using Rack::Builder
|
279
|
+
|
280
|
+
You can use `map` and `use` from http://www.rubydoc.info/gems/rack/Rack/Builder[Rack::Builder].
|
281
|
+
|
282
|
+
[[mapping-applications]]
|
283
|
+
=== Mapping applications
|
284
|
+
|
285
|
+
You can mount any Rack application to a Hobby application with `map`.
|
286
|
+
Here is an example of mounting the application from <<using-initialize>>
|
287
|
+
to '/anatoly' and '/patricio' routes:
|
288
|
+
|
289
|
+
[source,ruby]
|
290
|
+
----
|
291
|
+
class App
|
292
|
+
include Hobby
|
293
|
+
|
294
|
+
map('/anatoly') { run C.new 'Anatoly' }
|
295
|
+
map('/patricio') { run C.new 'Patricio' }
|
296
|
+
|
297
|
+
get '/' do
|
298
|
+
'Mapping app.'
|
299
|
+
end
|
300
|
+
end
|
301
|
+
----
|
302
|
+
|
303
|
+
[[using-middleware]]
|
304
|
+
=== Using middleware
|
305
|
+
|
306
|
+
You can use any Rack middleware with `use`:
|
307
|
+
|
308
|
+
[source,ruby]
|
309
|
+
----
|
310
|
+
class App
|
311
|
+
include Hobby
|
312
|
+
|
313
|
+
use Rack::Session::Cookie, secret: SecureRandom.hex(64)
|
314
|
+
use Rack::ShowExceptions
|
315
|
+
|
316
|
+
def session
|
317
|
+
env['rack.session']
|
318
|
+
end
|
319
|
+
|
320
|
+
get '/' do
|
321
|
+
session[:name] = 'username'
|
322
|
+
end
|
323
|
+
end
|
324
|
+
----
|
325
|
+
|
326
|
+
== Custom components
|
327
|
+
|
328
|
+
Hobby was designed to be very modular.
|
329
|
+
Many components of an application can be customized or replaced.
|
330
|
+
|
331
|
+
[source,ruby]
|
332
|
+
----
|
333
|
+
class App
|
334
|
+
include Hobby
|
335
|
+
|
336
|
+
self.builder = custom_builder
|
337
|
+
self.router = custom_router
|
338
|
+
self.request = custom_request
|
339
|
+
self.response = custom_response
|
340
|
+
end
|
341
|
+
----
|
342
|
+
|
343
|
+
TODO: document the API which is expected from each of these components
|
344
|
+
and provide usage examples.
|
345
|
+
|
346
|
+
== Development
|
347
|
+
|
348
|
+
To run the specs:
|
349
|
+
|
350
|
+
[source,bash]
|
351
|
+
----
|
352
|
+
bundle exec rspec
|
353
|
+
----
|
354
|
+
|
355
|
+
To perform mutantion analysis:
|
356
|
+
|
357
|
+
[source,bash]
|
358
|
+
----
|
359
|
+
bundle exec mutant --use rspec 'Hobby*'
|
360
|
+
----
|
data/spec/app_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hobby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anatoly Chernow
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-05-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -36,21 +36,21 @@ files:
|
|
36
36
|
- CHANGELOG.md
|
37
37
|
- Gemfile
|
38
38
|
- LICENSE
|
39
|
-
- README.md
|
40
39
|
- Rakefile
|
41
40
|
- hobby.gemspec
|
42
41
|
- lib/hobby.rb
|
43
42
|
- lib/hobby/router.rb
|
44
43
|
- lib/hobby/router/route.rb
|
45
44
|
- lib/hobby/router/routes.rb
|
45
|
+
- readme.adoc
|
46
46
|
- spec/app_spec.rb
|
47
47
|
- spec/apps/Decorator.rb
|
48
48
|
- spec/apps/Env.rb
|
49
|
+
- spec/apps/Halting.rb
|
49
50
|
- spec/apps/Main.rb
|
50
51
|
- spec/apps/Map.rb
|
51
52
|
- spec/apps/Nested.rb
|
52
53
|
- spec/apps/OneRouteRouter.rb
|
53
|
-
- spec/apps/Throw.rb
|
54
54
|
- spec/apps/Use.rb
|
55
55
|
- spec/apps/WithoutPath.rb
|
56
56
|
- spec/helper.rb
|
@@ -76,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
76
|
version: '0'
|
77
77
|
requirements: []
|
78
78
|
rubyforge_project:
|
79
|
-
rubygems_version: 2.
|
79
|
+
rubygems_version: 2.6.11
|
80
80
|
signing_key:
|
81
81
|
specification_version: 4
|
82
82
|
summary: A minimal DSL over rack
|
@@ -84,11 +84,11 @@ test_files:
|
|
84
84
|
- spec/app_spec.rb
|
85
85
|
- spec/apps/Decorator.rb
|
86
86
|
- spec/apps/Env.rb
|
87
|
+
- spec/apps/Halting.rb
|
87
88
|
- spec/apps/Main.rb
|
88
89
|
- spec/apps/Map.rb
|
89
90
|
- spec/apps/Nested.rb
|
90
91
|
- spec/apps/OneRouteRouter.rb
|
91
|
-
- spec/apps/Throw.rb
|
92
92
|
- spec/apps/Use.rb
|
93
93
|
- spec/apps/WithoutPath.rb
|
94
94
|
- spec/helper.rb
|
data/README.md
DELETED
@@ -1,378 +0,0 @@
|
|
1
|
-
# Hobbit [](https://travis-ci.org/patriciomacadden/hobbit) [](https://codeclimate.com/github/patriciomacadden/hobbit) [](https://codeclimate.com/github/patriciomacadden/hobbit) [](https://gemnasium.com/patriciomacadden/hobbit) [](http://badge.fury.io/rb/hobbit)
|
2
|
-
|
3
|
-
A minimalistic microframework built on top of [Rack](http://rack.github.io/).
|
4
|
-
|
5
|
-
## Installation
|
6
|
-
|
7
|
-
Add this line to your application's Gemfile:
|
8
|
-
|
9
|
-
```ruby
|
10
|
-
gem 'hobbit'
|
11
|
-
# or this if you want to use hobbit master
|
12
|
-
# gem 'hobbit', github: 'patriciomacadden/hobbit'
|
13
|
-
```
|
14
|
-
|
15
|
-
And then execute:
|
16
|
-
|
17
|
-
```bash
|
18
|
-
$ bundle
|
19
|
-
```
|
20
|
-
|
21
|
-
Or install it yourself as:
|
22
|
-
|
23
|
-
```bash
|
24
|
-
$ gem install hobbit
|
25
|
-
```
|
26
|
-
|
27
|
-
## Features
|
28
|
-
|
29
|
-
* DSL inspired by [Sinatra](http://www.sinatrarb.com/).
|
30
|
-
* [Speed](https://github.com/luislavena/bench-micro).
|
31
|
-
* Extensible with standard ruby classes and modules, with no extra logic. See
|
32
|
-
[hobbit-contrib](https://github.com/patriciomacadden/hobbit-contrib).
|
33
|
-
* Zero configuration.
|
34
|
-
|
35
|
-
## Philosophy
|
36
|
-
|
37
|
-
* [Don't repeat yourself](http://en.wikipedia.org/wiki/Don't_repeat_yourself)
|
38
|
-
* Encourages the understanding and use of [Rack](http://rack.github.io/) and
|
39
|
-
its extensions instead of providing such functionality.
|
40
|
-
|
41
|
-
## Usage
|
42
|
-
|
43
|
-
Hobbit applications are just instances of classes that inherits from
|
44
|
-
`Hobbit::Base`, which complies the
|
45
|
-
[Rack SPEC](http://rubydoc.info/github/rack/rack/master/file/SPEC).
|
46
|
-
|
47
|
-
### Hello World example
|
48
|
-
|
49
|
-
Create a file called `app.rb`:
|
50
|
-
|
51
|
-
```ruby
|
52
|
-
require 'hobbit'
|
53
|
-
|
54
|
-
class App < Hobbit::Base
|
55
|
-
get '/' do
|
56
|
-
'Hello World!'
|
57
|
-
end
|
58
|
-
end
|
59
|
-
```
|
60
|
-
|
61
|
-
Create a `config.ru` file:
|
62
|
-
|
63
|
-
```ruby
|
64
|
-
require './app'
|
65
|
-
|
66
|
-
run App.new # or just `run App`
|
67
|
-
```
|
68
|
-
|
69
|
-
Run it with `rackup`:
|
70
|
-
|
71
|
-
```bash
|
72
|
-
$ rackup
|
73
|
-
```
|
74
|
-
|
75
|
-
View your app at [http://localhost:9292](http://localhost:9292).
|
76
|
-
|
77
|
-
### Routes
|
78
|
-
|
79
|
-
Every route is composed of a verb, a path (optional) and a block. When an
|
80
|
-
incoming request matches a route, the block is executed and a response is sent
|
81
|
-
back to the client. The return value of the block will be the `body` of the
|
82
|
-
response. The `headers` and `status code` of the response will be calculated by
|
83
|
-
`Hobbit::Response`, but you could modify it anyway you want it.
|
84
|
-
|
85
|
-
See an example:
|
86
|
-
|
87
|
-
```ruby
|
88
|
-
class App < Hobbit::Base
|
89
|
-
get '/' do
|
90
|
-
# ...
|
91
|
-
end
|
92
|
-
|
93
|
-
post '/' do
|
94
|
-
# ...
|
95
|
-
end
|
96
|
-
|
97
|
-
put '/' do
|
98
|
-
# ...
|
99
|
-
end
|
100
|
-
|
101
|
-
patch '/' do
|
102
|
-
# ...
|
103
|
-
end
|
104
|
-
|
105
|
-
delete '/' do
|
106
|
-
# ...
|
107
|
-
end
|
108
|
-
|
109
|
-
options '/' do
|
110
|
-
# ...
|
111
|
-
end
|
112
|
-
end
|
113
|
-
```
|
114
|
-
|
115
|
-
When a route gets called you have this methods available:
|
116
|
-
|
117
|
-
* `env`: The Rack environment.
|
118
|
-
* `request`: a `Hobbit::Request` instance.
|
119
|
-
* `response`: a `Hobbit::Response` instance.
|
120
|
-
|
121
|
-
And any other method defined in your application.
|
122
|
-
|
123
|
-
#### Available methods
|
124
|
-
|
125
|
-
* `delete`
|
126
|
-
* `get`
|
127
|
-
* `head`
|
128
|
-
* `options`
|
129
|
-
* `patch`
|
130
|
-
* `post`
|
131
|
-
* `put`
|
132
|
-
|
133
|
-
**Note**: Since most browsers don't support methods other than **GET** and
|
134
|
-
**POST** you must use the `Rack::MethodOverride` middleware. (See
|
135
|
-
[Rack::MethodOverride](https://github.com/rack/rack/blob/master/lib/rack/methodoverride.rb)).
|
136
|
-
|
137
|
-
#### Routes with parameters
|
138
|
-
|
139
|
-
Besides the standard `GET` and `POST` parameters, you can have routes with
|
140
|
-
parameters:
|
141
|
-
|
142
|
-
```ruby
|
143
|
-
require 'hobbit'
|
144
|
-
|
145
|
-
class App < Hobbit::Base
|
146
|
-
# matches both /hi/hobbit and /hi/patricio
|
147
|
-
get '/hi/:name' do
|
148
|
-
# request.params is filled with the route paramters, like this:
|
149
|
-
"Hello #{request.params[:name]}"
|
150
|
-
end
|
151
|
-
end
|
152
|
-
```
|
153
|
-
|
154
|
-
#### Redirecting
|
155
|
-
|
156
|
-
If you look at Hobbit implementation, you may notice that there is no
|
157
|
-
`redirect` method (or similar). This is because such functionality is provided
|
158
|
-
by [Rack::Response](https://github.com/rack/rack/blob/master/lib/rack/response.rb)
|
159
|
-
and for now we [don't wan't to repeat ourselves](http://en.wikipedia.org/wiki/Don't_repeat_yourself)
|
160
|
-
(obviously you can create an extension!). So, if you want to redirect to
|
161
|
-
another route, do it like this:
|
162
|
-
|
163
|
-
```ruby
|
164
|
-
require 'hobbit'
|
165
|
-
|
166
|
-
class App < Hobbit::Base
|
167
|
-
get '/' do
|
168
|
-
response.redirect '/hi'
|
169
|
-
end
|
170
|
-
|
171
|
-
get '/hi' do
|
172
|
-
'Hello World!'
|
173
|
-
end
|
174
|
-
end
|
175
|
-
```
|
176
|
-
|
177
|
-
#### Halting
|
178
|
-
|
179
|
-
To immediately stop a request within route you can use `halt`.
|
180
|
-
|
181
|
-
```ruby
|
182
|
-
require 'hobbit'
|
183
|
-
|
184
|
-
class App < Hobbit::Base
|
185
|
-
use Rack::Session::Cookie, secret: SecureRandom.hex(64)
|
186
|
-
|
187
|
-
def session
|
188
|
-
env['rack.session']
|
189
|
-
end
|
190
|
-
|
191
|
-
get '/' do
|
192
|
-
response.status = 401
|
193
|
-
halt response.finish
|
194
|
-
end
|
195
|
-
end
|
196
|
-
```
|
197
|
-
|
198
|
-
### Built on top of rack
|
199
|
-
|
200
|
-
Each Hobbit application is a Rack stack (See this
|
201
|
-
[blog post](http://m.onkey.org/ruby-on-rack-2-the-builder) for more
|
202
|
-
information).
|
203
|
-
|
204
|
-
#### Mapping applications
|
205
|
-
|
206
|
-
You can mount any Rack application to the stack by using the `map` class
|
207
|
-
method:
|
208
|
-
|
209
|
-
```ruby
|
210
|
-
require 'hobbit'
|
211
|
-
|
212
|
-
class InnerApp < Hobbit::Base
|
213
|
-
# gets called when path_info = '/inner'
|
214
|
-
get do
|
215
|
-
'Hello InnerApp!'
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
class App < Hobbit::Base
|
220
|
-
map('/inner') { run InnerApp.new }
|
221
|
-
|
222
|
-
get '/' do
|
223
|
-
'Hello App!'
|
224
|
-
end
|
225
|
-
end
|
226
|
-
```
|
227
|
-
|
228
|
-
#### Using middleware
|
229
|
-
|
230
|
-
You can add any Rack middleware to the stack by using the `use` class method:
|
231
|
-
|
232
|
-
```ruby
|
233
|
-
require 'hobbit'
|
234
|
-
|
235
|
-
class App < Hobbit::Base
|
236
|
-
use Rack::Session::Cookie, secret: SecureRandom.hex(64)
|
237
|
-
use Rack::ShowExceptions
|
238
|
-
|
239
|
-
def session
|
240
|
-
env['rack.session']
|
241
|
-
end
|
242
|
-
|
243
|
-
get '/' do
|
244
|
-
session[:name] = 'hobbit'
|
245
|
-
end
|
246
|
-
|
247
|
-
# more routes...
|
248
|
-
end
|
249
|
-
|
250
|
-
run App.new
|
251
|
-
```
|
252
|
-
|
253
|
-
### Security
|
254
|
-
|
255
|
-
By default, Hobbit (nor Rack) comes without any protection against web
|
256
|
-
attacks. The use of [rack-protection](https://github.com/rkh/rack-protection)
|
257
|
-
is highly recommended:
|
258
|
-
|
259
|
-
```ruby
|
260
|
-
require 'hobbit'
|
261
|
-
require 'rack/protection'
|
262
|
-
require 'securerandom'
|
263
|
-
|
264
|
-
class App < Hobbit::Base
|
265
|
-
use Rack::Session::Cookie, secret: SecureRandom.hex(64)
|
266
|
-
use Rack::Protection
|
267
|
-
|
268
|
-
get '/' do
|
269
|
-
'Hello World!'
|
270
|
-
end
|
271
|
-
end
|
272
|
-
```
|
273
|
-
|
274
|
-
See the [rack-protection](https://github.com/rkh/rack-protection)
|
275
|
-
documentation for futher information.
|
276
|
-
|
277
|
-
### Testing
|
278
|
-
|
279
|
-
[rack-test](https://github.com/brynary/rack-test) is highly recommended. See
|
280
|
-
an example:
|
281
|
-
|
282
|
-
In `app.rb`:
|
283
|
-
|
284
|
-
```ruby
|
285
|
-
require 'hobbit'
|
286
|
-
|
287
|
-
class App < Hobbit::Base
|
288
|
-
get '/' do
|
289
|
-
'Hello World!'
|
290
|
-
end
|
291
|
-
end
|
292
|
-
```
|
293
|
-
|
294
|
-
In `app_spec.rb`:
|
295
|
-
|
296
|
-
```ruby
|
297
|
-
require 'minitest/autorun'
|
298
|
-
# imagine that app.rb and app_spec.rb are stored in the same directory
|
299
|
-
require 'app'
|
300
|
-
|
301
|
-
describe App do
|
302
|
-
include Rack::Test::Methods
|
303
|
-
|
304
|
-
def app
|
305
|
-
App.new
|
306
|
-
end
|
307
|
-
|
308
|
-
describe 'GET /' do
|
309
|
-
it 'must be ok' do
|
310
|
-
get '/'
|
311
|
-
last_response.must_be :ok?
|
312
|
-
last_response.body.must_match /Hello World!/
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
|
-
```
|
317
|
-
|
318
|
-
See the [rack-test](https://github.com/brynary/rack-test) documentation
|
319
|
-
for futher information.
|
320
|
-
|
321
|
-
### Extensions
|
322
|
-
|
323
|
-
You can extend Hobbit by creating standard ruby modules. See an example:
|
324
|
-
|
325
|
-
```ruby
|
326
|
-
module MyExtension
|
327
|
-
def do_something
|
328
|
-
# do something
|
329
|
-
end
|
330
|
-
end
|
331
|
-
|
332
|
-
class App < Hobbit::Base
|
333
|
-
include MyExtension
|
334
|
-
|
335
|
-
get '/' do
|
336
|
-
do_something
|
337
|
-
'Hello World!'
|
338
|
-
end
|
339
|
-
end
|
340
|
-
```
|
341
|
-
|
342
|
-
#### Hobbit::Contrib
|
343
|
-
|
344
|
-
[hobbit-contrib](https://github.com/patriciomacadden/hobbit-contrib) is a ruby
|
345
|
-
gem that comes with a lot of hobbit extensions, such as:
|
346
|
-
|
347
|
-
* `Hobbit::Render`: provides basic template rendering.
|
348
|
-
* `Hobbit::Session`: provides helper methods for handling user sessions.
|
349
|
-
* `Hobbit::Environment`: provides helper methods for handling application
|
350
|
-
environments.
|
351
|
-
* `Hobbit::Filter`: provides helper class methods for handling Sinatra-like
|
352
|
-
filters.
|
353
|
-
* `Hobbit::ErrorHandling`: provides helper class methods for handling
|
354
|
-
Sinatra-like error handling.
|
355
|
-
|
356
|
-
... And many more!
|
357
|
-
|
358
|
-
## Community
|
359
|
-
|
360
|
-
* [Wiki](https://github.com/patriciomacadden/hobbit/wiki): Guides, how-tos and recipes
|
361
|
-
* IRC: [#hobbitrb](irc://chat.freenode.net/#hobbitrb) on [http://freenode.net](http://freenode.net)
|
362
|
-
|
363
|
-
## Presentations
|
364
|
-
|
365
|
-
* Building web applications in Ruby, by [Krzysztof Wawer](https://github.com/wafcio)
|
366
|
-
([english](https://speakerdeck.com/wafcio/hobbit-english), [polish](https://speakerdeck.com/wafcio/hobbit))
|
367
|
-
|
368
|
-
## Contributing
|
369
|
-
|
370
|
-
1. Fork it
|
371
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
372
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
373
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
374
|
-
5. Create new Pull Request
|
375
|
-
|
376
|
-
## License
|
377
|
-
|
378
|
-
See the [LICENSE](https://github.com/patriciomacadden/hobbit/blob/master/LICENSE).
|