hobby 0.0.0 → 0.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8c721c77a7b912fa113e730de3ff58cdf8866e06
4
- data.tar.gz: 4590a7005e8597a277cae934955b30b0a981b1b4
3
+ metadata.gz: 42e7f7a0e7818909ac5d95c50484655aab19fac1
4
+ data.tar.gz: 7b0f857a9f4ceb6dfdb0eff86d6d546d2b285a6a
5
5
  SHA512:
6
- metadata.gz: 2bb9aa2ee633d3d06c85a7e41dd1a1b59bb4d870c48de2b351846b7e38566e1f17731bb94894bcec50e917e1fbcfab51d7784d6175ae89db37476918373d3403
7
- data.tar.gz: efa3483ccf3ea59cc6e6e16dd4280713eaef4e7a04b1ac1cd66c07e42344cd42efb6a52ddabab7cf4ed2fee032926264fb6f7224f8750e555976309d29665364
6
+ metadata.gz: d2f3740ca3b95e942af4bf6dc4fb5f8d5acfdd21bd6c48f0544b8f262de0f004856a31547f3739ad440a11195c80a0348e4c4237afb026d4fa566dc6cb138ad2
7
+ data.tar.gz: fe87a3f5ca1be2c5ee1a346cdeb9e26800c642e4de8251217f8461ba91c8dbb63c7b52ea1a208edb35f6851d27b47e385df4bfb153849065e826fc1b2ace1fed
data/Gemfile CHANGED
@@ -1,3 +1,10 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gem 'devtools', github: 'mbj/devtools'
4
+ gem 'minitest'
5
+ gem 'minitest-power_assert'
6
+ gem 'rack-test'
7
+ gem 'pry'
8
+ gem 'awesome_print'
9
+
3
10
  gemspec
data/LICENSE CHANGED
@@ -1,4 +1,5 @@
1
1
  Copyright (c) 2013 Patricio Mac Adden
2
+ Copyright (c) 2015 Anatoly Cherno
2
3
 
3
4
  MIT License
4
5
 
data/hobby.gemspec CHANGED
@@ -4,12 +4,11 @@ $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.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'
7
+ spec.version = '0.0.1'
8
+ spec.authors = ['Anatoly Cherno']
9
+ spec.email = ['anatoly.cherno@gmail.com']
10
+ spec.summary = %q{A minimal DSL over rack}
11
+ spec.homepage = 'https://github.com/ch1c0t/hobby'
13
12
  spec.license = 'MIT'
14
13
 
15
14
  spec.files = `git ls-files`.split($/)
@@ -18,12 +17,4 @@ Gem::Specification.new do |spec|
18
17
  spec.require_paths = ['lib']
19
18
 
20
19
  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
20
  end
data/lib/hobby/app.rb CHANGED
@@ -1,66 +1,59 @@
1
1
  module Hobby
2
- class App
3
- class << self
4
- def members
5
- @members ||= {}
6
- end
2
+ module App
3
+ def self.included app
4
+ app.extend Singleton
5
+ app.builder, app.router = Rack::Builder.new, Router.new
6
+ app.request, app.response = Rack::Request, Rack::Response
7
+ end
7
8
 
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
9
+ module Singleton
10
+ attr_accessor :builder, :router, :request, :response
11
+
12
+ def new (*)
13
+ builder.run super
14
+ builder.to_app
16
15
  end
17
16
 
17
+ extend Forwardable
18
+ delegate [:map, :use] => :builder
19
+
18
20
  Verbs.each do |verb|
19
- define_method verb.downcase do |path, &route|
21
+ define_method verb.downcase do |path = '/', &route|
20
22
  router.add_route verb, path, &route
21
23
  end
22
24
  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
25
  end
33
26
 
34
- attr_reader :env, :request, :response
35
-
36
27
  def call env
37
28
  dup.handle env
38
29
  end
39
30
 
40
- def handle env
41
- @env = env
42
- @request = Request.new @env
43
- @response = Response.new
31
+ protected
32
+ def handle env
33
+ route = self.class.router.route_for (@env = env)
44
34
 
45
- catch(:halt) { route_eval }
46
- end
35
+ if route
36
+ response.write instance_exec &route
37
+ else
38
+ response.status = 404
39
+ end
47
40
 
48
- private
41
+ response
42
+ end
49
43
 
50
- def halt response
51
- throw :halt, response
52
- end
44
+ private
45
+ attr_reader :env
53
46
 
54
- def route_eval
55
- route = self.class.router.route_for request
47
+ def request
48
+ @request ||= self.class.request.new env
49
+ end
56
50
 
57
- if route
58
- response.write instance_eval &route
59
- else
60
- response.status = 404
51
+ def response
52
+ @response ||= self.class.response.new
61
53
  end
62
54
 
63
- response.finish
64
- end
55
+ def my
56
+ env.fetch :path_params, {}
57
+ end
65
58
  end
66
59
  end
data/lib/hobby/router.rb CHANGED
@@ -1,29 +1,41 @@
1
1
  module Hobby
2
2
  class Router
3
- require_relative 'router/route'
4
-
5
3
  def initialize
6
- @routes = Hash.new { |hash, key| hash[key] = [] }
4
+ @routes = Routes.new
5
+ end
6
+
7
+ def add_route verb, path, &route
8
+ path = nil if path.eql? '/'
9
+ @routes["#{verb}#{path}"] = route
7
10
  end
8
11
 
9
- def add_route(verb, path, &block)
10
- @routes[verb] << Route.new(path, &block)
11
- self
12
+ def route_for env
13
+ route, params = @routes["#{env['REQUEST_METHOD']}#{env['PATH_INFO']}"]
14
+ env[:path_params] = params if params
15
+ route
12
16
  end
13
17
 
14
- def route_for(request)
15
- route = @routes[request.request_method].detect do |route|
16
- route.compiled_path =~ request.path_info
18
+ class Routes < Hash
19
+ def initialize
20
+ @patterns = {}
21
+ super { |hash, key| hash[key] = find key }
17
22
  end
18
23
 
19
- if route
20
- $~.captures.each_with_index do |value, index|
21
- param = route.extra_params[index]
22
- request.params[param] = value
24
+ def []= key, route
25
+ if key.include? ?:
26
+ string = key.gsub(/(:\w+)/) { "(?<#{$1[1..-1]}>[^/?#]+)" }
27
+ @patterns[/^#{string}$/] = route
28
+ else
29
+ super and super "#{key}/", route
23
30
  end
24
31
  end
25
32
 
26
- route
33
+ private
34
+
35
+ def find key
36
+ _, route = @patterns.find { |pattern, _| pattern.match key }
37
+ [route, $~.names.map(&:to_sym).zip($~.captures).to_h] if route
38
+ end
27
39
  end
28
40
  end
29
41
  end
@@ -0,0 +1,35 @@
1
+ module Hobby::RSpec
2
+ module Router
3
+ extend self
4
+ SOME_ROUTE = ->{}
5
+
6
+ def env_for path, verb = 'GET'
7
+ {'REQUEST_METHOD' => verb, 'PATH_INFO' => path }
8
+ end
9
+
10
+ def add_routes *routes
11
+ routes.each { |route| subject.add_route 'GET', route, &SOME_ROUTE }
12
+ end
13
+
14
+ extend RSpec::Matchers::DSL
15
+
16
+ define :find_route do |path, verb = 'GET'|
17
+ match do |subject|
18
+ env = env_for path, verb
19
+ route = subject.route_for env
20
+
21
+ params_are_ok = (@params ? (@params.to_a - env[:path_params].to_a).empty? : true)
22
+
23
+ (route == SOME_ROUTE) && params_are_ok
24
+ end
25
+
26
+ chain :and_set_params do |**params|
27
+ @params = params
28
+ end
29
+ end
30
+
31
+ def self.included example_group
32
+ example_group.extend self
33
+ end
34
+ end
35
+ end
data/lib/hobby.rb CHANGED
@@ -1,10 +1,9 @@
1
1
  require 'rack'
2
2
  require 'forwardable'
3
- require 'include_constants'
4
3
 
5
4
  module Hobby
6
5
  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
6
  end
7
+
8
+ require 'hobby/router'
9
+ require 'hobby/app'
data/spec/app_spec.rb ADDED
@@ -0,0 +1,146 @@
1
+ require 'helper'
2
+ require 'rack/test'
3
+
4
+ $sources = {}
5
+
6
+ Dir['spec/apps/*.rb'].each do |file|
7
+ name = File.basename file, '.rb'
8
+
9
+ eval %!
10
+ class #{name}
11
+ class << self
12
+ attr_accessor :app
13
+ end
14
+ end
15
+ !
16
+
17
+ $sources[Object.const_get name] = IO.read file
18
+ end
19
+
20
+ def build_app described_class
21
+ body = $sources[described_class]
22
+
23
+ eval %!
24
+ Class.new do
25
+ include Hobby::App
26
+ #{body}
27
+ end
28
+ !
29
+ end
30
+
31
+ describe Hobby::App do
32
+ include Rack::Test::Methods
33
+
34
+ describe '.new' do
35
+ context 'an app with nested app(s)' do
36
+ let(:subject) { build_app(Nested).new }
37
+ it { should be_a Rack::URLMap }
38
+ end
39
+
40
+ context 'an app without nested app(s)' do
41
+ let(:subject) { build_app(Main).new }
42
+ it { should be_a Hobby::App }
43
+ end
44
+ end
45
+
46
+ describe '#call' do
47
+ def app
48
+ build_app(Main).new
49
+ end
50
+
51
+ context 'when a route was found' do
52
+ it 'evaluates the route' do
53
+ get '/existent'
54
+
55
+ assert { last_response.ok? }
56
+ assert { last_response.body == 'existent' }
57
+ end
58
+ end
59
+
60
+ context 'when a route was not found' do
61
+ it 'responds with 404 status code' do
62
+ get '/nonexistent/route'
63
+
64
+ assert { last_response.not_found? }
65
+ assert { last_response.body.empty? }
66
+ end
67
+ end
68
+
69
+ it 'gives a distinct object to each request' do
70
+ get '/first'
71
+ assert { last_response.body == 'first' }
72
+
73
+ get '/second'
74
+ assert { last_response.body != 'first' }
75
+ assert { last_response.body == 'second' }
76
+ end
77
+ end
78
+
79
+ describe :integration do
80
+ before do
81
+ described_class.app = build_app described_class
82
+ end
83
+
84
+ def app
85
+ described_class.app.new
86
+ end
87
+
88
+ describe Map do
89
+ it 'mounts an application to the rack stack' do
90
+ get '/map'
91
+ assert { last_response.body == 'from map' }
92
+ end
93
+ end
94
+
95
+ describe Use do
96
+ it 'adds a middleware to the rack stack' do
97
+ get '/use'
98
+ assert { last_response.body == 'from use' }
99
+ end
100
+ end
101
+
102
+ describe WithoutPath do
103
+ it 'is accessible as /' do
104
+ get '/'
105
+ assert { last_response.body == 'root' }
106
+ end
107
+ end
108
+
109
+ describe OneRouteRouter do
110
+ it 'returns for any route' do
111
+ get '/'
112
+ assert { last_response.body == 'for any route' }
113
+
114
+ get '/some-other-route'
115
+ assert { last_response.body == 'for any route' }
116
+ end
117
+ end
118
+
119
+ describe Env do
120
+ it do
121
+ get '/query_string?1=2&3=4'
122
+ assert { last_response.body == '1=2&3=4' }
123
+ end
124
+
125
+ it do
126
+ get '/access_params?key=value'
127
+ assert { last_response.body == 'value' }
128
+ end
129
+
130
+ it do
131
+ get '/access_path_params_via_my'
132
+ assert { last_response.body == 'true' }
133
+
134
+ get '/access_path_params_via_env'
135
+ assert { last_response.body == 'true' }
136
+ end
137
+ end
138
+
139
+ describe Nested do
140
+ it do
141
+ get '/nested'
142
+ assert { last_response.body == 'a:b:c' }
143
+ end
144
+ end
145
+ end
146
+ end
data/spec/apps/Env.rb ADDED
@@ -0,0 +1,15 @@
1
+ get '/query_string' do
2
+ env['QUERY_STRING']
3
+ end
4
+
5
+ get '/access_params' do
6
+ request.params['key']
7
+ end
8
+
9
+ get '/access_path_params_via_my' do
10
+ my[:key].nil?
11
+ end
12
+
13
+ get '/access_path_params_via_env' do
14
+ env[:path_params].nil?
15
+ end
data/spec/apps/Main.rb ADDED
@@ -0,0 +1,4 @@
1
+ Hobby::Verbs.each do |verb|
2
+ class_eval "#{verb.downcase}('/') { '#{verb}' }"
3
+ class_eval "#{verb.downcase}('/:name') { my[:name] }"
4
+ end
data/spec/apps/Map.rb ADDED
@@ -0,0 +1,5 @@
1
+ map '/map' do
2
+ run Proc.new { |env| [200, {}, ['from map']] }
3
+ end
4
+
5
+ get('/') { 'hello world' }
@@ -0,0 +1,17 @@
1
+ map('/nested') do
2
+ nested_app = Class.new do
3
+ include Hobby::App
4
+
5
+ def initialize first, second
6
+ @a = first
7
+ @b = second
8
+ @c = yield
9
+ end
10
+
11
+ get do
12
+ "#{@a}:#{@b}:#{@c}"
13
+ end
14
+ end
15
+
16
+ run nested_app.new(:a, :b) { :c }
17
+ end
@@ -0,0 +1,8 @@
1
+ self.router = Class.new {
2
+ def add_route(*)
3
+ end
4
+
5
+ def route_for _request
6
+ -> { 'for any route' }
7
+ end
8
+ }.new
data/spec/apps/Use.rb ADDED
@@ -0,0 +1,15 @@
1
+ middleware = Class.new do
2
+ def initialize(app = nil)
3
+ @app = app
4
+ end
5
+
6
+ def call(env)
7
+ request = Rack::Request.new(env)
8
+ @app.call(env) unless request.path_info == '/use'
9
+ [200, {}, 'from use']
10
+ end
11
+ end
12
+
13
+ use middleware
14
+
15
+ get('/') { 'hello world' }
@@ -0,0 +1,3 @@
1
+ get do
2
+ 'root'
3
+ end
data/spec/helper.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'devtools/spec_helper'
2
+
3
+ require 'hobby'
4
+ require 'hobby/rspec/router'
5
+
6
+ require 'minitest'
7
+ require 'minitest-power_assert'
8
+ Minitest::Assertions.prepend Minitest::PowerAssert::Assertions
9
+
10
+ if defined? Mutant
11
+ class Mutant::Selector::Expression
12
+ def call _subject
13
+ integration.all_tests
14
+ end
15
+ end
16
+ end
17
+
18
+ RSpec.configure do |config|
19
+ config.expect_with :rspec, :minitest
20
+ config.include Hobby::RSpec::Router, type: :router
21
+ end
@@ -0,0 +1,46 @@
1
+ require 'helper'
2
+
3
+ describe Hobby::RSpec::Router do
4
+ before do
5
+ @Group = Class.new do
6
+ def subject
7
+ @router ||= Hobby::Router.new
8
+ end
9
+ end.include described_class
10
+ end
11
+
12
+ it 'contains a few helpers in its singleton' do
13
+ [:env_for, :add_routes, :find_route].each do |name|
14
+ assert { @Group.respond_to? name }
15
+ end
16
+ end
17
+
18
+ describe 'env_for' do
19
+ context 'two arguments passed' do
20
+ it 'returns an environment' do
21
+ env = { "REQUEST_METHOD" => 'POST', "PATH_INFO" => '/some_path' }
22
+ assert { env == (@Group.env_for '/some_path', 'POST') }
23
+ end
24
+ end
25
+
26
+ context 'one argument passed' do
27
+ it 'defaults to GET' do
28
+ env = { "REQUEST_METHOD" => 'GET', "PATH_INFO" => '/some_path' }
29
+ assert { env == (@Group.env_for '/some_path') }
30
+ end
31
+ end
32
+ end
33
+
34
+ describe 'add_routes' do
35
+ it do
36
+ routes = %w! first second third!
37
+ group = @Group.new
38
+
39
+ group.add_routes *routes
40
+
41
+ routes.each do |route|
42
+ expect(group.subject.route_for group.env_for 'first').to be_truthy
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,37 @@
1
+ require 'helper'
2
+
3
+ describe Hobby::Router, type: :router do
4
+ routes = %w!
5
+ /with.dot
6
+ /with-hyphen
7
+ /hello/:name
8
+ /say/:something/to/:someone
9
+ /route/:id.json
10
+ /existent/only/for/GET
11
+ !
12
+
13
+ before { add_routes *routes }
14
+
15
+ it { should find_route '/with.dot' }
16
+ it { should find_route '/with-hyphen' }
17
+ it { should find_route '/with.dot/' }
18
+ it { should find_route '/with-hyphen/' }
19
+
20
+ it { should find_route '/existent/only/for/GET' }
21
+ it { should_not find_route '/nonexistent' }
22
+ it { should_not find_route '/existent/only/for/GET', 'POST' }
23
+
24
+ it { should find_route('/hello/ololo').and_set_params(name: 'ololo') }
25
+ it { should find_route('/route/66.json').and_set_params(id: '66') }
26
+ it do
27
+ should find_route('/say/nothing/to/no_one').
28
+ and_set_params(something: 'nothing', someone: 'no_one')
29
+ end
30
+
31
+
32
+ it 'memoizes requests with params' do
33
+ subject.route_for env_for '/hello/ololo'
34
+
35
+ assert { subject.instance_variable_get(:@routes).include? 'GET/hello/ololo' }
36
+ end
37
+ 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.0
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
- - Patricio Mac Adden
7
+ - Anatoly Cherno
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-16 00:00:00.000000000 Z
11
+ date: 2016-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -24,107 +24,9 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
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
27
+ description:
126
28
  email:
127
- - patriciomacadden@gmail.com
29
+ - anatoly.cherno@gmail.com
128
30
  executables: []
129
31
  extensions: []
130
32
  extra_rdoc_files: []
@@ -140,11 +42,19 @@ files:
140
42
  - lib/hobby.rb
141
43
  - lib/hobby/app.rb
142
44
  - 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
45
+ - lib/hobby/rspec/router.rb
46
+ - spec/app_spec.rb
47
+ - spec/apps/Env.rb
48
+ - spec/apps/Main.rb
49
+ - spec/apps/Map.rb
50
+ - spec/apps/Nested.rb
51
+ - spec/apps/OneRouteRouter.rb
52
+ - spec/apps/Use.rb
53
+ - spec/apps/WithoutPath.rb
54
+ - spec/helper.rb
55
+ - spec/router_group_spec.rb
56
+ - spec/router_spec.rb
57
+ homepage: https://github.com/ch1c0t/hobby
148
58
  licenses:
149
59
  - MIT
150
60
  metadata: {}
@@ -164,12 +74,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
74
  version: '0'
165
75
  requirements: []
166
76
  rubyforge_project:
167
- rubygems_version: 2.4.5
77
+ rubygems_version: 2.5.1
168
78
  signing_key:
169
79
  specification_version: 4
170
- summary: A minimalistic microframework built on top of rack
80
+ summary: A minimal DSL over rack
171
81
  test_files:
172
- - test/helper.rb
173
- - test/test_app.rb
174
- - test/test_router.rb
175
- has_rdoc:
82
+ - spec/app_spec.rb
83
+ - spec/apps/Env.rb
84
+ - spec/apps/Main.rb
85
+ - spec/apps/Map.rb
86
+ - spec/apps/Nested.rb
87
+ - spec/apps/OneRouteRouter.rb
88
+ - spec/apps/Use.rb
89
+ - spec/apps/WithoutPath.rb
90
+ - spec/helper.rb
91
+ - spec/router_group_spec.rb
92
+ - spec/router_spec.rb
@@ -1,20 +0,0 @@
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
data/test/helper.rb DELETED
@@ -1,5 +0,0 @@
1
- require 'hobby'
2
- require 'rack/test'
3
-
4
- require 'minitest-power_assert'
5
- require 'minitest/autorun'
data/test/test_app.rb DELETED
@@ -1,189 +0,0 @@
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
data/test/test_router.rb DELETED
@@ -1,65 +0,0 @@
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