hobby 0.0.12 → 0.1.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 +4 -4
- data/Gemfile +2 -2
- data/hobby.gemspec +1 -1
- data/lib/hobby.rb +5 -6
- data/lib/hobby/helpers.rb +12 -0
- data/lib/hobby/router.rb +31 -0
- data/lib/hobby/router/builder.rb +25 -0
- data/readme.adoc +2 -3
- data/spec/app_spec.rb +101 -0
- data/spec/apps/Map.rb +3 -3
- data/spec/apps/MapInsideInitialize.rb +13 -0
- data/spec/apps/Nested.rb +11 -13
- data/spec/apps/OneRouteRouter.rb +8 -0
- data/spec/apps/UnshareableRouterMaps.rb +29 -0
- data/spec/apps/UnshareableRouterUses.rb +16 -0
- data/spec/apps/UseInsideInitialize.rb +7 -0
- data/spec/helper.rb +26 -0
- data/spec/router_matchers.rb +0 -4
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c820bc2f67ffcbd87d4de89a2e8ad53a6f83da9
|
4
|
+
data.tar.gz: e56880e61b2d283537bf44bd019709440dde9118
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f14f9c47364424a1826184cd11a670eed4509e315bb83b6f978e05022fd17da57d3fc139d1e40c62ea33c06ebf59c38996f4dfb90ea0bef779b2a67b837321b5
|
7
|
+
data.tar.gz: 27b2ac428b2a8a7b51941a4e4dd7bab6d9c28e1cbbb4e77d49c282ce58638e0500913b6320f2090511a4a5ca7793b9ba1afd9099748ba17b67afde31214b3142
|
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.1.0'
|
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
@@ -10,20 +10,19 @@ module Hobby
|
|
10
10
|
|
11
11
|
def self.included app
|
12
12
|
app.extend Singleton
|
13
|
-
app.
|
13
|
+
app.router = Router.new
|
14
14
|
app.request, app.response = Rack::Request, Rack::Response
|
15
15
|
end
|
16
16
|
|
17
17
|
module Singleton
|
18
|
-
attr_accessor :
|
18
|
+
attr_accessor :router, :request, :response
|
19
19
|
|
20
20
|
def new (*)
|
21
|
-
|
22
|
-
builder.to_app
|
21
|
+
super.router.to_rack_app
|
23
22
|
end
|
24
23
|
|
25
24
|
extend Forwardable
|
26
|
-
delegate [:map, :use] => :
|
25
|
+
delegate [:map, :use] => :router
|
27
26
|
|
28
27
|
VERBS.each do |verb|
|
29
28
|
define_method verb.downcase do |path = '/', &action|
|
@@ -41,7 +40,7 @@ module Hobby
|
|
41
40
|
protected
|
42
41
|
def handle env
|
43
42
|
catch :halt do
|
44
|
-
@route =
|
43
|
+
@route = router.route_for (@env = env)
|
45
44
|
fill_body
|
46
45
|
response
|
47
46
|
end
|
data/lib/hobby/helpers.rb
CHANGED
@@ -1,7 +1,19 @@
|
|
1
1
|
module Hobby
|
2
2
|
module Helpers
|
3
|
+
extend Forwardable
|
4
|
+
|
3
5
|
attr_reader :env, :route
|
4
6
|
|
7
|
+
def router
|
8
|
+
@router ||= begin
|
9
|
+
router = self.class.router.clone
|
10
|
+
router.app = self
|
11
|
+
router
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
delegate [:map, :use] => :router
|
16
|
+
|
5
17
|
def request
|
6
18
|
@request ||= self.class.request.new env
|
7
19
|
end
|
data/lib/hobby/router.rb
CHANGED
@@ -2,6 +2,12 @@ module Hobby
|
|
2
2
|
class Router
|
3
3
|
def initialize
|
4
4
|
@routes = Routes.new
|
5
|
+
@uses, @maps = [], []
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize_copy _router
|
9
|
+
@uses = instance_variable_get(:@uses).dup
|
10
|
+
@maps = instance_variable_get(:@maps).dup
|
5
11
|
end
|
6
12
|
|
7
13
|
def add_route verb, path, &action
|
@@ -17,8 +23,33 @@ module Hobby
|
|
17
23
|
route, params = @routes["#{env['REQUEST_METHOD']}#{env['PATH_INFO']}"]
|
18
24
|
params ? route.with_params(params) : route
|
19
25
|
end
|
26
|
+
|
27
|
+
def use *all
|
28
|
+
@uses << all
|
29
|
+
end
|
30
|
+
|
31
|
+
def map path, app = nil, &block
|
32
|
+
@maps << Builder::Map.new(path, app, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_accessor :app
|
36
|
+
|
37
|
+
def to_rack_app
|
38
|
+
builder = create_builder
|
39
|
+
builder.run app
|
40
|
+
builder.to_app
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def create_builder
|
45
|
+
builder = Builder.new
|
46
|
+
@uses.each { |all| builder.add_use *all }
|
47
|
+
@maps.each { |map| builder.add_map map }
|
48
|
+
builder
|
49
|
+
end
|
20
50
|
end
|
21
51
|
end
|
22
52
|
|
53
|
+
require 'hobby/router/builder'
|
23
54
|
require 'hobby/router/routes'
|
24
55
|
require 'hobby/router/route'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Hobby
|
2
|
+
class Router
|
3
|
+
class Builder < Rack::Builder
|
4
|
+
# To work around
|
5
|
+
# https://github.com/mbj/mutant#the-crash--stuck-problem-mri
|
6
|
+
alias add_use use
|
7
|
+
alias add_map2 map
|
8
|
+
|
9
|
+
def add_map map
|
10
|
+
if map.app
|
11
|
+
add_map2 map.path do run map.app end
|
12
|
+
else
|
13
|
+
add_map2 map.path, &map.block
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Map
|
18
|
+
attr_reader :path, :app, :block
|
19
|
+
def initialize path, app, &block
|
20
|
+
@path, @app, @block = path, app, block
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/readme.adoc
CHANGED
@@ -285,8 +285,8 @@ to '/anatoly' and '/patricio' routes:
|
|
285
285
|
class App
|
286
286
|
include Hobby
|
287
287
|
|
288
|
-
map
|
289
|
-
map
|
288
|
+
map '/anatoly', C.new('Anatoly')
|
289
|
+
map '/patricio', C.new('Patricio')
|
290
290
|
|
291
291
|
get '/' do
|
292
292
|
'Mapping app.'
|
@@ -327,7 +327,6 @@ Many components of an application can be customized or replaced.
|
|
327
327
|
class App
|
328
328
|
include Hobby
|
329
329
|
|
330
|
-
self.builder = custom_builder
|
331
330
|
self.router = custom_router
|
332
331
|
self.request = custom_request
|
333
332
|
self.response = custom_response
|
data/spec/app_spec.rb
CHANGED
@@ -75,6 +75,17 @@ describe Hobby::App do
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
+
describe '#router' do
|
79
|
+
it 'gives a distinct router to each app' do
|
80
|
+
app = Class.new { include Hobby }
|
81
|
+
|
82
|
+
first_instance = app.new
|
83
|
+
second_instance = app.new
|
84
|
+
|
85
|
+
assert { not first_instance.router.equal? second_instance.router }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
78
89
|
describe :integration do
|
79
90
|
before do
|
80
91
|
described_class.app = build_app described_class
|
@@ -89,6 +100,51 @@ describe Hobby::App do
|
|
89
100
|
get '/map'
|
90
101
|
assert { last_response.body == 'from map' }
|
91
102
|
end
|
103
|
+
|
104
|
+
it 'mounts an application to the rack stack with old deprecated syntax' do
|
105
|
+
get '/deprecated_map'
|
106
|
+
assert { last_response.body == 'from deprecated map' }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe MapInsideInitialize do
|
111
|
+
describe 'without any passed arguments' do
|
112
|
+
def app
|
113
|
+
described_class.app.new
|
114
|
+
end
|
115
|
+
|
116
|
+
it do
|
117
|
+
get '/'
|
118
|
+
assert { last_response.body == 'hello world' }
|
119
|
+
get '/first_map'
|
120
|
+
assert { last_response.body == 'first mapapp' }
|
121
|
+
get '/second_map'
|
122
|
+
assert { last_response.body == 'second mapapp' }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe 'with passed routes' do
|
127
|
+
def app
|
128
|
+
some_app = Class.new {
|
129
|
+
include Hobby
|
130
|
+
get { 'Some string.' }
|
131
|
+
}
|
132
|
+
routes = { '/third_map' => some_app.new }
|
133
|
+
described_class.app.new routes
|
134
|
+
end
|
135
|
+
|
136
|
+
it do
|
137
|
+
get '/'
|
138
|
+
assert { last_response.body == 'hello world' }
|
139
|
+
get '/first_map'
|
140
|
+
assert { last_response.body == 'first mapapp' }
|
141
|
+
get '/second_map'
|
142
|
+
assert { last_response.body == 'second mapapp' }
|
143
|
+
|
144
|
+
get '/third_map'
|
145
|
+
assert { last_response.body == 'Some string.' }
|
146
|
+
end
|
147
|
+
end
|
92
148
|
end
|
93
149
|
|
94
150
|
describe Use do
|
@@ -98,6 +154,13 @@ describe Hobby::App do
|
|
98
154
|
end
|
99
155
|
end
|
100
156
|
|
157
|
+
describe UseInsideInitialize do
|
158
|
+
it do
|
159
|
+
get '/'
|
160
|
+
assert { last_response.content_type == 'application/json' }
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
101
164
|
describe WithoutPath do
|
102
165
|
it 'is accessible as /' do
|
103
166
|
get '/'
|
@@ -171,5 +234,43 @@ describe Hobby::App do
|
|
171
234
|
assert { last_response.body == 'Created.' }
|
172
235
|
end
|
173
236
|
end
|
237
|
+
|
238
|
+
describe UnshareableRouterMaps do
|
239
|
+
it do
|
240
|
+
get '/1/first'
|
241
|
+
assert { last_response.body == 'The name is A.' }
|
242
|
+
get '/1/second'
|
243
|
+
assert { last_response.body == 'The name is B.' }
|
244
|
+
get '/1/third'
|
245
|
+
assert { last_response.body == '404' }
|
246
|
+
|
247
|
+
get '/2/first'
|
248
|
+
assert { last_response.body == 'The name is A.' }
|
249
|
+
get '/2/second'
|
250
|
+
assert { last_response.body == 'The name is B.' }
|
251
|
+
get '/2/third'
|
252
|
+
assert { last_response.body == 'The name is C.' }
|
253
|
+
|
254
|
+
get '/3/first'
|
255
|
+
assert { last_response.body == 'The name is A.' }
|
256
|
+
get '/3/second'
|
257
|
+
assert { last_response.body == 'The name is B.' }
|
258
|
+
get '/3/third'
|
259
|
+
assert { last_response.body == '404' }
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
describe UnshareableRouterUses do
|
264
|
+
it do
|
265
|
+
get '/1'
|
266
|
+
assert { last_response.content_type == 'application/html' }
|
267
|
+
|
268
|
+
get '/2'
|
269
|
+
assert { last_response.content_type == 'application/json' }
|
270
|
+
|
271
|
+
get '/3'
|
272
|
+
assert { last_response.content_type == 'application/html' }
|
273
|
+
end
|
274
|
+
end
|
174
275
|
end
|
175
276
|
end
|
data/spec/apps/Map.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
first_app = Proc.new { |env| [200, {}, ['first mapapp']] }
|
2
|
+
second_app = Proc.new { |env| [200, {}, ['second mapapp']] }
|
3
|
+
|
4
|
+
map '/first_map', first_app
|
5
|
+
map '/second_map', second_app
|
6
|
+
|
7
|
+
get('/') { 'hello world' }
|
8
|
+
|
9
|
+
def initialize hash = {}
|
10
|
+
hash.each do |route, app|
|
11
|
+
map route, app
|
12
|
+
end
|
13
|
+
end
|
data/spec/apps/Nested.rb
CHANGED
@@ -1,17 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
include Hobby::App
|
1
|
+
nested_app = Class.new do
|
2
|
+
include Hobby::App
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
get do
|
12
|
-
"#{@a}:#{@b}:#{@c}"
|
13
|
-
end
|
4
|
+
def initialize first, second
|
5
|
+
@a = first
|
6
|
+
@b = second
|
7
|
+
@c = yield
|
14
8
|
end
|
15
9
|
|
16
|
-
|
10
|
+
get do
|
11
|
+
"#{@a}:#{@b}:#{@c}"
|
12
|
+
end
|
17
13
|
end
|
14
|
+
|
15
|
+
map '/nested', nested_app.new(:a, :b) { :c }
|
data/spec/apps/OneRouteRouter.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
mapped_app = Class.new do
|
2
|
+
include Hobby
|
3
|
+
|
4
|
+
def initialize name
|
5
|
+
@name = name
|
6
|
+
end
|
7
|
+
|
8
|
+
get { "The name is #{@name}." }
|
9
|
+
end
|
10
|
+
|
11
|
+
mapping_app = Class.new do
|
12
|
+
include Hobby
|
13
|
+
|
14
|
+
map '/first', mapped_app.new('A')
|
15
|
+
map '/second', mapped_app.new('B')
|
16
|
+
|
17
|
+
def initialize routes = {}
|
18
|
+
routes.each do |route, app|
|
19
|
+
map route, app
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
map '/1', mapping_app.new
|
25
|
+
|
26
|
+
routes = { '/third' => mapped_app.new('C') }
|
27
|
+
map '/2', mapping_app.new(routes)
|
28
|
+
|
29
|
+
map '/3', mapping_app.new
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
app = Class.new do
|
4
|
+
include Hobby
|
5
|
+
get { 'hello world'.to_json }
|
6
|
+
|
7
|
+
use Rack::ContentType, 'application/html'
|
8
|
+
|
9
|
+
def initialize middleware_with_arguments = nil
|
10
|
+
use *middleware_with_arguments if middleware_with_arguments
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
map '/1', app.new
|
15
|
+
map '/2', app.new([Rack::ContentType, 'application/json'])
|
16
|
+
map '/3', app.new
|
data/spec/helper.rb
CHANGED
@@ -12,8 +12,34 @@ if defined? Mutant
|
|
12
12
|
integration.all_tests
|
13
13
|
end
|
14
14
|
end
|
15
|
+
|
16
|
+
class Mutant::Isolation::Fork
|
17
|
+
def result
|
18
|
+
yield
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Mutant::Loader
|
23
|
+
def call
|
24
|
+
source = Unparser.unparse node
|
25
|
+
|
26
|
+
puts <<~S
|
27
|
+
Current mutantion:
|
28
|
+
#{source}
|
29
|
+
S
|
30
|
+
|
31
|
+
kernel.eval source, binding, subject.source_path.to_s, subject.source_line
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module EnvFor
|
37
|
+
def env_for path, verb = 'GET'
|
38
|
+
{'REQUEST_METHOD' => verb, 'PATH_INFO' => path }
|
39
|
+
end
|
15
40
|
end
|
16
41
|
|
17
42
|
RSpec.configure do |config|
|
18
43
|
config.expect_with :rspec, :minitest
|
44
|
+
config.include EnvFor
|
19
45
|
end
|
data/spec/router_matchers.rb
CHANGED
@@ -2,10 +2,6 @@ module RouterMatchers
|
|
2
2
|
extend self
|
3
3
|
SOME_ROUTE = ->{:some_route}
|
4
4
|
|
5
|
-
def env_for path, verb = 'GET'
|
6
|
-
{'REQUEST_METHOD' => verb, 'PATH_INFO' => path }
|
7
|
-
end
|
8
|
-
|
9
5
|
def add_routes *routes
|
10
6
|
routes.each { |route| subject.add_route 'GET', route, &SOME_ROUTE }
|
11
7
|
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
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anatoly Chernow
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -39,6 +39,7 @@ files:
|
|
39
39
|
- lib/hobby.rb
|
40
40
|
- lib/hobby/helpers.rb
|
41
41
|
- lib/hobby/router.rb
|
42
|
+
- lib/hobby/router/builder.rb
|
42
43
|
- lib/hobby/router/route.rb
|
43
44
|
- lib/hobby/router/routes.rb
|
44
45
|
- readme.adoc
|
@@ -49,10 +50,14 @@ files:
|
|
49
50
|
- spec/apps/Halting.rb
|
50
51
|
- spec/apps/Main.rb
|
51
52
|
- spec/apps/Map.rb
|
53
|
+
- spec/apps/MapInsideInitialize.rb
|
52
54
|
- spec/apps/Nested.rb
|
53
55
|
- spec/apps/OneRouteRouter.rb
|
54
56
|
- spec/apps/Status.rb
|
57
|
+
- spec/apps/UnshareableRouterMaps.rb
|
58
|
+
- spec/apps/UnshareableRouterUses.rb
|
55
59
|
- spec/apps/Use.rb
|
60
|
+
- spec/apps/UseInsideInitialize.rb
|
56
61
|
- spec/apps/WithoutPath.rb
|
57
62
|
- spec/helper.rb
|
58
63
|
- spec/router_matchers.rb
|
@@ -77,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
82
|
version: '0'
|
78
83
|
requirements: []
|
79
84
|
rubyforge_project:
|
80
|
-
rubygems_version: 2.6.
|
85
|
+
rubygems_version: 2.6.13
|
81
86
|
signing_key:
|
82
87
|
specification_version: 4
|
83
88
|
summary: A minimal DSL over rack
|
@@ -89,10 +94,14 @@ test_files:
|
|
89
94
|
- spec/apps/Halting.rb
|
90
95
|
- spec/apps/Main.rb
|
91
96
|
- spec/apps/Map.rb
|
97
|
+
- spec/apps/MapInsideInitialize.rb
|
92
98
|
- spec/apps/Nested.rb
|
93
99
|
- spec/apps/OneRouteRouter.rb
|
94
100
|
- spec/apps/Status.rb
|
101
|
+
- spec/apps/UnshareableRouterMaps.rb
|
102
|
+
- spec/apps/UnshareableRouterUses.rb
|
95
103
|
- spec/apps/Use.rb
|
104
|
+
- spec/apps/UseInsideInitialize.rb
|
96
105
|
- spec/apps/WithoutPath.rb
|
97
106
|
- spec/helper.rb
|
98
107
|
- spec/router_matchers.rb
|