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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 866906249cfb187bc16dad3e74ddb38aac06fa32
4
- data.tar.gz: 7f654e325e34a802370869c4713260df9f169756
3
+ metadata.gz: c943dce2451a4154082cfe2d8fc823273b28c627
4
+ data.tar.gz: 78ab9a63570bea6044c18307c8bb2cb7b355b935
5
5
  SHA512:
6
- metadata.gz: 5aafd05f85c81e0d8af6ce2bbf9cfd9d0da3fd4bf7ff70ea7d1df7bc837eab50824c6a2222ff393974d8fb09b850e9b5fffa25c6c7b91796d6313fe542a7165e
7
- data.tar.gz: 5cf2deda1c0d46698af9a9607cd9003ae6c98dffc4abc68c0a3b3799f6eb633b8edb0f02015a715a5e1674a428c8e88a0d24619676bcf946fd807c0651a2bf7b
6
+ metadata.gz: 12fc9f283cd851d77de6132caa8ac74401854547b2f0f2639726857327dcf01da99fc8a7e962c924a0f1a644645576c94f51544e596eac98bf280f0a6ce11f9c
7
+ data.tar.gz: 3bb0e84f2b8195a51dbbe61bb37d7caea77cfda4dcf02ccea9812a7c037d0ce2d43ee13bf0e4fc12638cb3e5512f8aa24a0ac330460907da70878107b8ddc339
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'devtools'
3
+ gem 'devtools', github: 'mbj/devtools'
4
+ gem 'mutant', github: 'mbj/mutant'
4
5
  gem 'minitest'
5
6
  gem 'minitest-power_assert'
6
7
  gem 'rack-test'
@@ -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.6'
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}
@@ -64,4 +64,8 @@ module Hobby
64
64
  def my
65
65
  env.fetch :path_params, {}
66
66
  end
67
+
68
+ def halt
69
+ throw :halt, response
70
+ end
67
71
  end
@@ -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
+ ----
@@ -150,7 +150,7 @@ describe Hobby::App do
150
150
  end
151
151
  end
152
152
 
153
- describe Throw do
153
+ describe Halting do
154
154
  it do
155
155
  get '/'
156
156
  assert { last_response.status == 400 }
@@ -1,4 +1,5 @@
1
1
  get do
2
2
  response.status = 400
3
- throw :halt, response
3
+ halt
4
+ response.status = 200
4
5
  end
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.6
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: 2016-12-27 00:00:00.000000000 Z
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.5.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).