hobby 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8c721c77a7b912fa113e730de3ff58cdf8866e06
4
+ data.tar.gz: 4590a7005e8597a277cae934955b30b0a981b1b4
5
+ SHA512:
6
+ metadata.gz: 2bb9aa2ee633d3d06c85a7e41dd1a1b59bb4d870c48de2b351846b7e38566e1f17731bb94894bcec50e917e1fbcfab51d7784d6175ae89db37476918373d3403
7
+ data.tar.gz: efa3483ccf3ea59cc6e6e16dd4280713eaef4e7a04b1ac1cd66c07e42344cd42efb6a52ddabab7cf4ed2fee032926264fb6f7224f8750e555976309d29665364
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ ---
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.2
5
+ - ruby-head
6
+ addons:
7
+ code_climate:
8
+ repo_token:
9
+ secure: "bogVqPmJ2KlI2XK3Ln9Ki8vG08WTvKbKfvYm4ErD1A+2t3vg61utFKxJS8R3P5QKuDDIIX98eQC7r+gPeGEYwT+tDDFMnBsGQZcaeXJCYZQ3qLN36GpnPmpeZ3tTZwop5aT1AmMCF0IllDWYCjcWzeEZan23Eqt5YOyzTGAnr4g="
data/CHANGELOG.md ADDED
@@ -0,0 +1,53 @@
1
+ # 0.6.0
2
+
3
+ * Change the implementation of `Hobbit::Base#halt`. This new implementation is
4
+ more rack compliant.
5
+ * Test hobbit with [oktobertest](https://github.com/patriciomacadden/oktobertest)
6
+ instead of minitest (Because reasons!).
7
+
8
+ # 0.5.1 (Unreleased)
9
+
10
+ * A class is an object too, so allow to `run` classes.
11
+ * Add `Hobbit::Request`, which sets the path info to `/` if its empty (instead
12
+ of doing that on the call method).
13
+
14
+ # 0.5.0
15
+
16
+ * Refactor `Hobbit::Base#halt`. It now sets the status, merges the headers and
17
+ writes the body (using `Hobbit::Response#write`) when given a fixnum, a hash or
18
+ a string.
19
+ * `Hobbit::Response` headers and body are not accessors anymore. This is
20
+ because when you set the body directly, the `Content-Length` is not calculated
21
+ (it's calculated on `#write`).
22
+
23
+ # 0.4.4
24
+
25
+ * Refactor `Hobbit::Response`.
26
+
27
+ # 0.4.3
28
+
29
+ * Calculate the `Content-Length` of a `Hobbit::Response` using `#bytesize`
30
+ instead of `#size`.
31
+
32
+ # 0.4.2
33
+
34
+ * Add `Hobbit::Response#redirect`, that was missing since `Hobbit::Response`
35
+ isn't a `Rack::Response` subclass.
36
+
37
+ # 0.4.1
38
+
39
+ * `Hobbit::Response` now returns the `Content-Length` header as a string.
40
+
41
+ # 0.4.0
42
+
43
+ * Add halt method.
44
+
45
+ # 0.3.1
46
+
47
+ * Remove unused `attr_accessor` (`:length`) from `Hobbit::Response`.
48
+
49
+ # 0.3.0
50
+
51
+ * `Hobbit::Response` is no longer a subclass of `Rack::Response`.
52
+ * Forward `#map` and `#use` methods to `Rack::Builder` instead of define these
53
+ methods.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Patricio Mac Adden
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,378 @@
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).
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new
data/hobby.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'hobby'
7
+ spec.version = '0.0.0'
8
+ spec.authors = ['Patricio Mac Adden']
9
+ spec.email = ['patriciomacadden@gmail.com']
10
+ spec.description = %q{A minimalistic microframework built on top of rack}
11
+ spec.summary = %q{A minimalistic microframework built on top of rack}
12
+ spec.homepage = 'https://github.com/patriciomacadden/hobbit'
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_dependency 'rack'
21
+ spec.add_dependency 'include_constants'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.3'
24
+ spec.add_development_dependency 'codeclimate-test-reporter'
25
+ spec.add_development_dependency 'rack-test'
26
+ spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'minitest'
28
+ spec.add_development_dependency 'minitest-power_assert'
29
+ end
data/lib/hobby/app.rb ADDED
@@ -0,0 +1,66 @@
1
+ module Hobby
2
+ class App
3
+ class << self
4
+ def members
5
+ @members ||= {}
6
+ end
7
+
8
+ [:builder, :router].each do |member|
9
+ define_method member do |&custom_member|
10
+ if custom_member
11
+ members[member] = custom_member.call
12
+ else
13
+ members[member] ||= Hobby.const_get(member.capitalize).new
14
+ end
15
+ end
16
+ end
17
+
18
+ Verbs.each do |verb|
19
+ define_method verb.downcase do |path, &route|
20
+ router.add_route verb, path, &route
21
+ end
22
+ end
23
+
24
+ alias :_new :new
25
+ def new *args, &block
26
+ builder.run _new(*args, &block)
27
+ builder
28
+ end
29
+
30
+ extend Forwardable
31
+ delegate [:map, :use] => :builder
32
+ end
33
+
34
+ attr_reader :env, :request, :response
35
+
36
+ def call env
37
+ dup.handle env
38
+ end
39
+
40
+ def handle env
41
+ @env = env
42
+ @request = Request.new @env
43
+ @response = Response.new
44
+
45
+ catch(:halt) { route_eval }
46
+ end
47
+
48
+ private
49
+
50
+ def halt response
51
+ throw :halt, response
52
+ end
53
+
54
+ def route_eval
55
+ route = self.class.router.route_for request
56
+
57
+ if route
58
+ response.write instance_eval &route
59
+ else
60
+ response.status = 404
61
+ end
62
+
63
+ response.finish
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,20 @@
1
+ class Hobby::Router
2
+ class Route
3
+ attr_reader :compiled_path, :extra_params, :path
4
+ def initialize(path, &block)
5
+ @path = path
6
+ @block = block
7
+
8
+ @extra_params = []
9
+ compiled_path = path.gsub(/:\w+/) do |match|
10
+ @extra_params << match.gsub(':', '').to_sym
11
+ '([^/?#]+)'
12
+ end
13
+ @compiled_path = /^#{compiled_path}$/
14
+ end
15
+
16
+ def to_proc
17
+ @block
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ module Hobby
2
+ class Router
3
+ require_relative 'router/route'
4
+
5
+ def initialize
6
+ @routes = Hash.new { |hash, key| hash[key] = [] }
7
+ end
8
+
9
+ def add_route(verb, path, &block)
10
+ @routes[verb] << Route.new(path, &block)
11
+ self
12
+ end
13
+
14
+ def route_for(request)
15
+ route = @routes[request.request_method].detect do |route|
16
+ route.compiled_path =~ request.path_info
17
+ end
18
+
19
+ if route
20
+ $~.captures.each_with_index do |value, index|
21
+ param = route.extra_params[index]
22
+ request.params[param] = value
23
+ end
24
+ end
25
+
26
+ route
27
+ end
28
+ end
29
+ end
data/lib/hobby.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rack'
2
+ require 'forwardable'
3
+ require 'include_constants'
4
+
5
+ module Hobby
6
+ Verbs = %w!DELETE GET HEAD OPTIONS PATCH POST PUT!
7
+ require 'hobby/app'
8
+ autoload :Router, 'hobby/router'
9
+ include_constants :Builder, :Request, :Response, from: Rack
10
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'hobby'
2
+ require 'rack/test'
3
+
4
+ require 'minitest-power_assert'
5
+ require 'minitest/autorun'
data/test/test_app.rb ADDED
@@ -0,0 +1,189 @@
1
+ require_relative 'helper'
2
+
3
+ module Minitest
4
+ class Test
5
+ include Rack::Test::Methods
6
+
7
+ def mock_app(&block)
8
+ @app = Class.new(Hobby::App, &block).new
9
+ end
10
+
11
+ def app
12
+ @app
13
+ end
14
+ end
15
+ end
16
+
17
+ describe Hobby::App do
18
+ describe :main_app do
19
+ before do
20
+ mock_app do
21
+ Hobby::Verbs.each do |verb|
22
+ class_eval "#{verb.downcase}('/') { '#{verb}' }"
23
+ class_eval "#{verb.downcase}('/route.json') { '#{verb} /route.json' }"
24
+ class_eval "#{verb.downcase}('/route/:id.json') { request.params[:id] }"
25
+ class_eval "#{verb.downcase}('/:name') { request.params[:name] }"
26
+ end
27
+ end
28
+ end
29
+
30
+ Hobby::Verbs.each do |verb|
31
+ describe 'when the request matches a route' do
32
+ it "matches #{verb} ''" do
33
+ send verb.downcase, ''
34
+ assert last_response.ok?
35
+ assert_equal verb, last_response.body
36
+ end
37
+
38
+ it 'matches #{verb} /' do
39
+ send verb.downcase, '/'
40
+ assert last_response.ok?
41
+ assert_equal verb, last_response.body
42
+ end
43
+
44
+ it 'matches #{verb} /route.json' do
45
+ send verb.downcase, '/route.json'
46
+ assert last_response.ok?
47
+ assert_equal "#{verb} /route.json", last_response.body
48
+ end
49
+
50
+ it 'matches #{verb} /route/:id.json' do
51
+ send verb.downcase, '/route/1.json'
52
+ assert last_response.ok?
53
+ assert_equal '1', last_response.body
54
+ end
55
+
56
+ it 'matches #{verb} /:name' do
57
+ send verb.downcase, '/hobbit'
58
+ assert last_response.ok?
59
+ assert_equal 'hobbit', last_response.body
60
+
61
+ send verb.downcase, '/hello-hobbit'
62
+ assert last_response.ok?
63
+ assert_equal 'hello-hobbit', last_response.body
64
+ end
65
+ end
66
+
67
+ describe 'when the request not matches a route' do
68
+ it 'responds with 404 status code' do
69
+ send verb.downcase, '/not/found'
70
+ assert last_response.not_found?
71
+ assert_equal '', last_response.body
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ describe :map_app do
78
+ before do
79
+ mock_app do
80
+ map '/map' do
81
+ run Proc.new { |env| [200, {}, ['from map']] }
82
+ end
83
+
84
+ get('/') { 'hello world' }
85
+ end
86
+ end
87
+
88
+ it 'mounts an application to the rack stack' do
89
+ get '/map'
90
+ assert_equal 'from map', last_response.body
91
+ end
92
+ end
93
+
94
+ describe :use_app do
95
+ before do
96
+ mock_app do
97
+ middleware = Class.new do
98
+ def initialize(app = nil)
99
+ @app = app
100
+ end
101
+
102
+ def call(env)
103
+ request = Rack::Request.new(env)
104
+ @app.call(env) unless request.path_info == '/use'
105
+ [200, {}, 'from use']
106
+ end
107
+ end
108
+
109
+ use middleware
110
+
111
+ get('/') { 'hello world' }
112
+ end
113
+ end
114
+
115
+ it 'adds a middleware to the rack stack' do
116
+ get '/use'
117
+ assert_equal 'from use', last_response.body
118
+ end
119
+ end
120
+
121
+ describe :halt_app do
122
+ before do
123
+ mock_app do
124
+ get '/halt' do
125
+ response.status = 501
126
+ halt response.finish
127
+ end
128
+
129
+ get '/halt_finished' do
130
+ halt [404, {}, ['Not found']]
131
+ end
132
+ end
133
+ end
134
+
135
+ it 'halts the execution with a response' do
136
+ get '/halt'
137
+ assert { last_response.status == 501 }
138
+ end
139
+
140
+ it 'halts the execution with a finished response' do
141
+ get '/halt_finished'
142
+ assert { last_response.status == 404 }
143
+ end
144
+ end
145
+
146
+ describe :router_app do
147
+ before do
148
+ mock_app do
149
+ router do
150
+ Class.new do
151
+ def add_route(*)
152
+ end
153
+
154
+ def route_for _request
155
+ Proc.new { 'for any route' }
156
+ end
157
+ end.new
158
+ end
159
+ end
160
+ end
161
+
162
+ it 'returns for any route' do
163
+ get '/'
164
+ assert { last_response.body == 'for any route' }
165
+
166
+ get '/some-other-route'
167
+ assert { last_response.body == 'for any route' }
168
+ end
169
+ end
170
+
171
+ describe :custom_members do
172
+ before do
173
+ mock_app do
174
+ builder { Rack::Builder.new }
175
+ Request = Rack::Request
176
+ Response = Rack::Response
177
+
178
+ get '/' do
179
+ 'it works'
180
+ end
181
+ end
182
+ end
183
+
184
+ it 'works' do
185
+ get '/'
186
+ assert { last_response.body == 'it works' }
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,65 @@
1
+ require_relative 'helper'
2
+
3
+ def request_to path, request_method: 'GET'
4
+ Hobby::Request.new Rack::MockRequest.env_for "http://example.com:8080/#{path}", method: request_method
5
+ end
6
+
7
+ describe Hobby::Router do
8
+ before do
9
+ @router = Hobby::Router.new
10
+ @route = -> { :wrapped }
11
+ end
12
+
13
+ it 'works' do
14
+ @router.add_route 'GET', '/ololo', &@route
15
+
16
+ route = @router.route_for request_to 'ololo'
17
+ assert { route.to_proc.call == :wrapped }
18
+
19
+ route = @router.route_for request_to 'ololo2'
20
+ assert { route.nil? }
21
+
22
+ route = @router.route_for request_to 'ololo', request_method: 'POST'
23
+ assert { route.nil? }
24
+ end
25
+
26
+ it 'with .' do
27
+ @router.add_route 'GET', '/route.json', &@route
28
+
29
+ route = @router.route_for request_to 'route.json'
30
+ assert { route.to_proc.call == :wrapped }
31
+ end
32
+
33
+ it 'with -' do
34
+ @router.add_route 'GET', '/hello-world', &@route
35
+
36
+ route = @router.route_for request_to 'hello-world'
37
+ assert { route.to_proc.call == :wrapped }
38
+ end
39
+
40
+ it 'with params' do
41
+ @router
42
+ .add_route 'GET', '/hello/:name' do :first end
43
+ .add_route 'GET', '/say/:something/to/:someone' do :second end
44
+
45
+ request = request_to 'hello/ololo'
46
+ route = @router.route_for request
47
+ assert { route.to_proc.call == :first }
48
+ assert { request.params[:name] == 'ololo'}
49
+
50
+ request = request_to 'say/nothing/to/no_one'
51
+ route = @router.route_for request
52
+ assert { route.to_proc.call == :second }
53
+ assert { request.params[:something] == 'nothing'}
54
+ assert { request.params[:someone] == 'no_one'}
55
+ end
56
+
57
+ it 'with . and params' do
58
+ @router.add_route 'GET', '/route/:id.json', &@route
59
+
60
+ request = request_to 'route/42.json'
61
+ route = @router.route_for request
62
+ assert { route.to_proc.call == :wrapped }
63
+ assert { request.params[:id] == '42' }
64
+ end
65
+ end
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hobby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Patricio Mac Adden
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: include_constants
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: codeclimate-test-reporter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rack-test
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: minitest-power_assert
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: A minimalistic microframework built on top of rack
126
+ email:
127
+ - patriciomacadden@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".travis.yml"
134
+ - CHANGELOG.md
135
+ - Gemfile
136
+ - LICENSE
137
+ - README.md
138
+ - Rakefile
139
+ - hobby.gemspec
140
+ - lib/hobby.rb
141
+ - lib/hobby/app.rb
142
+ - lib/hobby/router.rb
143
+ - lib/hobby/router/route.rb
144
+ - test/helper.rb
145
+ - test/test_app.rb
146
+ - test/test_router.rb
147
+ homepage: https://github.com/patriciomacadden/hobbit
148
+ licenses:
149
+ - MIT
150
+ metadata: {}
151
+ post_install_message:
152
+ rdoc_options: []
153
+ require_paths:
154
+ - lib
155
+ required_ruby_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ required_rubygems_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ requirements: []
166
+ rubyforge_project:
167
+ rubygems_version: 2.4.5
168
+ signing_key:
169
+ specification_version: 4
170
+ summary: A minimalistic microframework built on top of rack
171
+ test_files:
172
+ - test/helper.rb
173
+ - test/test_app.rb
174
+ - test/test_router.rb
175
+ has_rdoc: