hobby 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](http://img.shields.io/travis/patriciomacadden/hobbit.svg)](https://travis-ci.org/patriciomacadden/hobbit) [![Code Climate](http://img.shields.io/codeclimate/github/patriciomacadden/hobbit.svg)](https://codeclimate.com/github/patriciomacadden/hobbit) [![Code Climate Coverage](http://img.shields.io/codeclimate/coverage/github/patriciomacadden/hobbit.svg)](https://codeclimate.com/github/patriciomacadden/hobbit) [![Dependency Status](http://img.shields.io/gemnasium/patriciomacadden/hobbit.svg)](https://gemnasium.com/patriciomacadden/hobbit) [![Gem Version](http://img.shields.io/gem/v/hobbit.svg)](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).
|