jellyfish 1.0.2 → 1.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/.travis.yml +1 -0
- data/CHANGES.md +14 -0
- data/README.md +194 -119
- data/bench/bench_builder.rb +44 -0
- data/config.ru +5 -39
- data/jellyfish.gemspec +12 -18
- data/lib/jellyfish.rb +1 -3
- data/lib/jellyfish/builder.rb +52 -0
- data/lib/jellyfish/test.rb +8 -8
- data/lib/jellyfish/urlmap.rb +26 -0
- data/lib/jellyfish/version.rb +1 -1
- data/task/gemgem.rb +11 -2
- data/test/rack/test_builder.rb +154 -0
- data/test/rack/test_urlmap.rb +180 -0
- data/test/sinatra/test_base.rb +1 -1
- data/test/sinatra/test_routing.rb +0 -60
- data/test/test_from_readme.rb +31 -20
- metadata +15 -17
- data/lib/jellyfish/multi_actions.rb +0 -31
- data/lib/jellyfish/sinatra.rb +0 -13
- data/lib/jellyfish/swagger.rb +0 -166
- data/public/css/screen.css +0 -1070
- data/public/index.html +0 -45
- data/public/js/shred.bundle.js +0 -2765
- data/public/js/shred/content.js +0 -193
- data/public/js/swagger-ui.js +0 -2116
- data/public/js/swagger.js +0 -1400
- data/test/sinatra/test_multi_actions.rb +0 -217
- data/test/test_swagger.rb +0 -131
@@ -0,0 +1,180 @@
|
|
1
|
+
|
2
|
+
require 'jellyfish/test'
|
3
|
+
require 'jellyfish/urlmap'
|
4
|
+
|
5
|
+
require 'rack/mock'
|
6
|
+
|
7
|
+
describe Jellyfish::URLMap do
|
8
|
+
would "dispatches paths correctly" do
|
9
|
+
app = lambda { |env|
|
10
|
+
[200, {
|
11
|
+
'X-ScriptName' => env['SCRIPT_NAME'],
|
12
|
+
'X-PathInfo' => env['PATH_INFO'],
|
13
|
+
'Content-Type' => 'text/plain'
|
14
|
+
}, [""]]
|
15
|
+
}
|
16
|
+
map = Rack::Lint.new(Jellyfish::URLMap.new({
|
17
|
+
'/bar' => app,
|
18
|
+
'/foo' => app,
|
19
|
+
'/foo/bar' => app
|
20
|
+
}))
|
21
|
+
|
22
|
+
res = Rack::MockRequest.new(map).get("/")
|
23
|
+
res.should.not_found?
|
24
|
+
|
25
|
+
res = Rack::MockRequest.new(map).get("/qux")
|
26
|
+
res.should.not_found?
|
27
|
+
|
28
|
+
res = Rack::MockRequest.new(map).get("/foo")
|
29
|
+
res.should.ok?
|
30
|
+
res["X-ScriptName"].should.eq "/foo"
|
31
|
+
res["X-PathInfo"].should.eq ""
|
32
|
+
|
33
|
+
res = Rack::MockRequest.new(map).get("/foo/")
|
34
|
+
res.should.ok?
|
35
|
+
res["X-ScriptName"].should.eq "/foo"
|
36
|
+
res["X-PathInfo"].should.eq "/"
|
37
|
+
|
38
|
+
res = Rack::MockRequest.new(map).get("/foo/bar")
|
39
|
+
res.should.ok?
|
40
|
+
res["X-ScriptName"].should.eq "/foo/bar"
|
41
|
+
res["X-PathInfo"].should.eq ""
|
42
|
+
|
43
|
+
res = Rack::MockRequest.new(map).get("/foo/bar/")
|
44
|
+
res.should.ok?
|
45
|
+
res["X-ScriptName"].should.eq "/foo/bar"
|
46
|
+
res["X-PathInfo"].should.eq "/"
|
47
|
+
|
48
|
+
res = Rack::MockRequest.new(map).get("/foo///bar//quux")
|
49
|
+
res.status.should.eq 200
|
50
|
+
res.should.ok?
|
51
|
+
res["X-ScriptName"].should.eq "/foo/bar"
|
52
|
+
res["X-PathInfo"].should.eq "//quux"
|
53
|
+
|
54
|
+
res = Rack::MockRequest.new(map).get("/foo/quux", "SCRIPT_NAME" => "/bleh")
|
55
|
+
res.should.ok?
|
56
|
+
res["X-ScriptName"].should.eq "/bleh/foo"
|
57
|
+
res["X-PathInfo"].should.eq "/quux"
|
58
|
+
|
59
|
+
res = Rack::MockRequest.new(map).get("/bar", 'HTTP_HOST' => 'foo.org')
|
60
|
+
res.should.ok?
|
61
|
+
res["X-ScriptName"].should.eq "/bar"
|
62
|
+
res["X-PathInfo"].should.empty?
|
63
|
+
|
64
|
+
res = Rack::MockRequest.new(map).get("/bar/", 'HTTP_HOST' => 'foo.org')
|
65
|
+
res.should.ok?
|
66
|
+
res["X-ScriptName"].should.eq "/bar"
|
67
|
+
res["X-PathInfo"].should.eq '/'
|
68
|
+
end
|
69
|
+
|
70
|
+
would "be nestable" do
|
71
|
+
map = Rack::Lint.new(Rack::URLMap.new("/foo" =>
|
72
|
+
Rack::URLMap.new("/bar" =>
|
73
|
+
Rack::URLMap.new("/quux" => lambda { |env|
|
74
|
+
[200,
|
75
|
+
{ "Content-Type" => "text/plain",
|
76
|
+
"X-Position" => "/foo/bar/quux",
|
77
|
+
"X-PathInfo" => env["PATH_INFO"],
|
78
|
+
"X-ScriptName" => env["SCRIPT_NAME"],
|
79
|
+
}, [""]]}
|
80
|
+
))))
|
81
|
+
|
82
|
+
res = Rack::MockRequest.new(map).get("/foo/bar")
|
83
|
+
res.should.not_found?
|
84
|
+
|
85
|
+
res = Rack::MockRequest.new(map).get("/foo/bar/quux")
|
86
|
+
res.should.ok?
|
87
|
+
res["X-Position"].should.eq "/foo/bar/quux"
|
88
|
+
res["X-PathInfo"].should.eq ""
|
89
|
+
res["X-ScriptName"].should.eq "/foo/bar/quux"
|
90
|
+
end
|
91
|
+
|
92
|
+
would "route root apps correctly" do
|
93
|
+
map = Rack::Lint.new(Rack::URLMap.new("/" => lambda { |env|
|
94
|
+
[200,
|
95
|
+
{ "Content-Type" => "text/plain",
|
96
|
+
"X-Position" => "root",
|
97
|
+
"X-PathInfo" => env["PATH_INFO"],
|
98
|
+
"X-ScriptName" => env["SCRIPT_NAME"]
|
99
|
+
}, [""]]},
|
100
|
+
"/foo" => lambda { |env|
|
101
|
+
[200,
|
102
|
+
{ "Content-Type" => "text/plain",
|
103
|
+
"X-Position" => "foo",
|
104
|
+
"X-PathInfo" => env["PATH_INFO"],
|
105
|
+
"X-ScriptName" => env["SCRIPT_NAME"]
|
106
|
+
}, [""]]}
|
107
|
+
))
|
108
|
+
|
109
|
+
res = Rack::MockRequest.new(map).get("/foo/bar")
|
110
|
+
res.should.ok?
|
111
|
+
res["X-Position"].should.eq "foo"
|
112
|
+
res["X-PathInfo"].should.eq "/bar"
|
113
|
+
res["X-ScriptName"].should.eq "/foo"
|
114
|
+
|
115
|
+
res = Rack::MockRequest.new(map).get("/foo")
|
116
|
+
res.should.ok?
|
117
|
+
res["X-Position"].should.eq "foo"
|
118
|
+
res["X-PathInfo"].should.eq ""
|
119
|
+
res["X-ScriptName"].should.eq "/foo"
|
120
|
+
|
121
|
+
res = Rack::MockRequest.new(map).get("/bar")
|
122
|
+
res.should.ok?
|
123
|
+
res["X-Position"].should.eq "root"
|
124
|
+
res["X-PathInfo"].should.eq "/bar"
|
125
|
+
res["X-ScriptName"].should.eq ""
|
126
|
+
|
127
|
+
res = Rack::MockRequest.new(map).get("")
|
128
|
+
res.should.ok?
|
129
|
+
res["X-Position"].should.eq "root"
|
130
|
+
res["X-PathInfo"].should.eq "/"
|
131
|
+
res["X-ScriptName"].should.eq ""
|
132
|
+
end
|
133
|
+
|
134
|
+
would "not squeeze slashes" do
|
135
|
+
map = Rack::Lint.new(Rack::URLMap.new("/" => lambda { |env|
|
136
|
+
[200,
|
137
|
+
{ "Content-Type" => "text/plain",
|
138
|
+
"X-Position" => "root",
|
139
|
+
"X-PathInfo" => env["PATH_INFO"],
|
140
|
+
"X-ScriptName" => env["SCRIPT_NAME"]
|
141
|
+
}, [""]]},
|
142
|
+
"/foo" => lambda { |env|
|
143
|
+
[200,
|
144
|
+
{ "Content-Type" => "text/plain",
|
145
|
+
"X-Position" => "foo",
|
146
|
+
"X-PathInfo" => env["PATH_INFO"],
|
147
|
+
"X-ScriptName" => env["SCRIPT_NAME"]
|
148
|
+
}, [""]]}
|
149
|
+
))
|
150
|
+
|
151
|
+
res = Rack::MockRequest.new(map).get("/http://example.org/bar")
|
152
|
+
res.should.ok?
|
153
|
+
res["X-Position"].should.eq "root"
|
154
|
+
res["X-PathInfo"].should.eq "/http://example.org/bar"
|
155
|
+
res["X-ScriptName"].should.eq ""
|
156
|
+
end
|
157
|
+
|
158
|
+
would "not be case sensitive with hosts" do
|
159
|
+
map = Rack::Lint.new(Rack::URLMap.new("/" => lambda { |env|
|
160
|
+
[200,
|
161
|
+
{ "Content-Type" => "text/plain",
|
162
|
+
"X-Position" => "root",
|
163
|
+
"X-PathInfo" => env["PATH_INFO"],
|
164
|
+
"X-ScriptName" => env["SCRIPT_NAME"]
|
165
|
+
}, [""]]}
|
166
|
+
))
|
167
|
+
|
168
|
+
res = Rack::MockRequest.new(map).get("/")
|
169
|
+
res.should.ok?
|
170
|
+
res["X-Position"].should.eq "root"
|
171
|
+
res["X-PathInfo"].should.eq "/"
|
172
|
+
res["X-ScriptName"].should.eq ""
|
173
|
+
|
174
|
+
res = Rack::MockRequest.new(map).get("/")
|
175
|
+
res.should.ok?
|
176
|
+
res["X-Position"].should.eq "root"
|
177
|
+
res["X-PathInfo"].should.eq "/"
|
178
|
+
res["X-ScriptName"].should.eq ""
|
179
|
+
end
|
180
|
+
end
|
data/test/sinatra/test_base.rb
CHANGED
@@ -98,7 +98,7 @@ describe 'Sinatra base_test.rb' do
|
|
98
98
|
status .should.eq 210
|
99
99
|
headers['X-Downstream'] .should.eq 'true'
|
100
100
|
headers['Content-Length'].should.eq '28'
|
101
|
-
body
|
101
|
+
body.to_a .should.eq ['Hello after explicit forward']
|
102
102
|
end
|
103
103
|
end
|
104
104
|
end
|
@@ -292,66 +292,6 @@ describe 'Sinatra routing_test.rb' do
|
|
292
292
|
should.raise(TypeError)
|
293
293
|
end
|
294
294
|
|
295
|
-
would 'return response immediately on next or halt' do
|
296
|
-
app = Class.new{
|
297
|
-
include Jellyfish
|
298
|
-
controller_include Jellyfish::MultiActions
|
299
|
-
|
300
|
-
get '/next' do
|
301
|
-
body 'Hello World'
|
302
|
-
next
|
303
|
-
end
|
304
|
-
|
305
|
-
get '/halt' do
|
306
|
-
body 'Hello World'
|
307
|
-
halt
|
308
|
-
'Boo-hoo World'
|
309
|
-
end
|
310
|
-
}.new
|
311
|
-
|
312
|
-
%w[/next /halt].each do |path|
|
313
|
-
status, _, body = get(path, app)
|
314
|
-
status.should.eq 200
|
315
|
-
body .should.eq ['Hello World']
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
would 'halt with a response tuple' do
|
320
|
-
app = Class.new{
|
321
|
-
include Jellyfish
|
322
|
-
controller_include Jellyfish::MultiActions
|
323
|
-
|
324
|
-
get '/' do
|
325
|
-
halt [295, {'Content-Type' => 'text/plain'}, ['Hello World']]
|
326
|
-
end
|
327
|
-
}.new
|
328
|
-
|
329
|
-
status, headers, body = get('/', app)
|
330
|
-
status .should.eq 295
|
331
|
-
headers['Content-Type'].should.eq 'text/plain'
|
332
|
-
body .should.eq ['Hello World']
|
333
|
-
end
|
334
|
-
|
335
|
-
would 'transition to the next matching route on next' do
|
336
|
-
app = Class.new{
|
337
|
-
include Jellyfish
|
338
|
-
controller_include Jellyfish::MultiActions, Jellyfish::NormalizedParams
|
339
|
-
get %r{^/(?<foo>\w+)} do
|
340
|
-
params['foo'].should.eq 'bar'
|
341
|
-
next
|
342
|
-
end
|
343
|
-
|
344
|
-
get do
|
345
|
-
params.should.not.include?('foo')
|
346
|
-
'Hello World'
|
347
|
-
end
|
348
|
-
}.new
|
349
|
-
|
350
|
-
status, _, body = get('/bar', app)
|
351
|
-
status.should.eq 200
|
352
|
-
body .should.eq ['Hello World']
|
353
|
-
end
|
354
|
-
|
355
295
|
would 'match routes defined in superclasses' do
|
356
296
|
sup = Class.new{
|
357
297
|
include Jellyfish
|
data/test/test_from_readme.rb
CHANGED
@@ -20,27 +20,38 @@ describe 'from README.md' do
|
|
20
20
|
next if title =~ /NewRelic/i
|
21
21
|
|
22
22
|
would "pass from README.md #%02d #{title}" % index do
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
23
|
+
app = Rack::Builder.app{ eval(code) }
|
24
|
+
|
25
|
+
test.split("\n\n").each do |t|
|
26
|
+
method_path, expect = t.strip.split("\n", 2)
|
27
|
+
method, path = method_path.split(' ')
|
28
|
+
uri = URI.parse(path)
|
29
|
+
pinfo, query = uri.path, uri.query
|
30
|
+
|
31
|
+
sock = nil
|
32
|
+
status, headers, body = File.open(File::NULL) do |input|
|
33
|
+
app.call(
|
34
|
+
'HTTP_VERSION' => 'HTTP/1.1',
|
35
|
+
'REQUEST_METHOD' => method, 'PATH_INFO' => pinfo,
|
36
|
+
'QUERY_STRING' => query , 'SCRIPT_NAME'=> '' ,
|
37
|
+
'rack.input' => input ,
|
38
|
+
'rack.hijack' => lambda{
|
39
|
+
sock = StringIO.new
|
40
|
+
# or TypeError: no implicit conversion of StringIO into IO
|
41
|
+
mock(IO).select([sock]){ [[sock], [], []] }
|
42
|
+
sock
|
43
|
+
})
|
44
|
+
end
|
41
45
|
|
42
|
-
|
43
|
-
|
46
|
+
if hijack = headers.delete('rack.hijack')
|
47
|
+
sock = StringIO.new
|
48
|
+
hijack.call(sock)
|
49
|
+
body = sock.string.each_line("\n\n")
|
50
|
+
end
|
51
|
+
|
52
|
+
body.extend(Enumerable)
|
53
|
+
[status, headers, body.to_a].should.eq eval(expect, binding, __FILE__)
|
54
|
+
end
|
44
55
|
end
|
45
56
|
end
|
46
57
|
end
|
metadata
CHANGED
@@ -1,18 +1,22 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jellyfish
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lin Jen-Shin (godfat)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |-
|
14
14
|
Pico web framework for building API-centric web applications.
|
15
|
-
For Rack applications or Rack
|
15
|
+
For Rack applications or Rack middleware. Around 250 lines of code.
|
16
|
+
|
17
|
+
Check [jellyfish-contrib][] for extra extensions.
|
18
|
+
|
19
|
+
[jellyfish-contrib]: https://github.com/godfat/jellyfish-contrib
|
16
20
|
email:
|
17
21
|
- godfat (XD) godfat.org
|
18
22
|
executables: []
|
@@ -28,42 +32,36 @@ files:
|
|
28
32
|
- README.md
|
29
33
|
- Rakefile
|
30
34
|
- TODO.md
|
35
|
+
- bench/bench_builder.rb
|
31
36
|
- config.ru
|
32
37
|
- jellyfish.gemspec
|
33
38
|
- jellyfish.png
|
34
39
|
- lib/jellyfish.rb
|
40
|
+
- lib/jellyfish/builder.rb
|
35
41
|
- lib/jellyfish/chunked_body.rb
|
36
42
|
- lib/jellyfish/json.rb
|
37
|
-
- lib/jellyfish/multi_actions.rb
|
38
43
|
- lib/jellyfish/newrelic.rb
|
39
44
|
- lib/jellyfish/normalized_params.rb
|
40
45
|
- lib/jellyfish/normalized_path.rb
|
41
46
|
- lib/jellyfish/public/302.html
|
42
47
|
- lib/jellyfish/public/404.html
|
43
48
|
- lib/jellyfish/public/500.html
|
44
|
-
- lib/jellyfish/sinatra.rb
|
45
|
-
- lib/jellyfish/swagger.rb
|
46
49
|
- lib/jellyfish/test.rb
|
50
|
+
- lib/jellyfish/urlmap.rb
|
47
51
|
- lib/jellyfish/version.rb
|
48
52
|
- lib/jellyfish/websocket.rb
|
49
|
-
- public/css/screen.css
|
50
|
-
- public/index.html
|
51
|
-
- public/js/shred.bundle.js
|
52
|
-
- public/js/shred/content.js
|
53
|
-
- public/js/swagger-ui.js
|
54
|
-
- public/js/swagger.js
|
55
53
|
- task/README.md
|
56
54
|
- task/gemgem.rb
|
55
|
+
- test/rack/test_builder.rb
|
56
|
+
- test/rack/test_urlmap.rb
|
57
57
|
- test/sinatra/test_base.rb
|
58
58
|
- test/sinatra/test_chunked_body.rb
|
59
59
|
- test/sinatra/test_error.rb
|
60
|
-
- test/sinatra/test_multi_actions.rb
|
61
60
|
- test/sinatra/test_routing.rb
|
62
61
|
- test/test_from_readme.rb
|
63
62
|
- test/test_inheritance.rb
|
64
63
|
- test/test_log.rb
|
65
64
|
- test/test_misc.rb
|
66
|
-
- test/test_swagger.rb
|
67
65
|
- test/test_threads.rb
|
68
66
|
- test/test_websocket.rb
|
69
67
|
homepage: https://github.com/godfat/jellyfish
|
@@ -86,20 +84,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
84
|
version: '0'
|
87
85
|
requirements: []
|
88
86
|
rubyforge_project:
|
89
|
-
rubygems_version: 2.4.
|
87
|
+
rubygems_version: 2.4.8
|
90
88
|
signing_key:
|
91
89
|
specification_version: 4
|
92
90
|
summary: Pico web framework for building API-centric web applications.
|
93
91
|
test_files:
|
92
|
+
- test/rack/test_builder.rb
|
93
|
+
- test/rack/test_urlmap.rb
|
94
94
|
- test/sinatra/test_base.rb
|
95
95
|
- test/sinatra/test_chunked_body.rb
|
96
96
|
- test/sinatra/test_error.rb
|
97
|
-
- test/sinatra/test_multi_actions.rb
|
98
97
|
- test/sinatra/test_routing.rb
|
99
98
|
- test/test_from_readme.rb
|
100
99
|
- test/test_inheritance.rb
|
101
100
|
- test/test_log.rb
|
102
101
|
- test/test_misc.rb
|
103
|
-
- test/test_swagger.rb
|
104
102
|
- test/test_threads.rb
|
105
103
|
- test/test_websocket.rb
|
@@ -1,31 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'jellyfish'
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
module Jellyfish
|
7
|
-
module MultiActions
|
8
|
-
def call env
|
9
|
-
@env = env
|
10
|
-
dispatch.inject(nil){ |_, route_block| block_call(*route_block) }
|
11
|
-
end
|
12
|
-
|
13
|
-
def dispatch
|
14
|
-
acts = actions.map{ |(route, block)|
|
15
|
-
case route
|
16
|
-
when String
|
17
|
-
[route, block] if route == path_info
|
18
|
-
else#Regexp, using else allows you to use custom matcher
|
19
|
-
match = route.match(path_info)
|
20
|
-
[match, block] if match
|
21
|
-
end
|
22
|
-
}.compact
|
23
|
-
|
24
|
-
if acts.empty?
|
25
|
-
action_missing
|
26
|
-
else
|
27
|
-
acts
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
data/lib/jellyfish/sinatra.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'jellyfish'
|
3
|
-
require 'jellyfish/multi_actions'
|
4
|
-
require 'jellyfish/normalized_params'
|
5
|
-
require 'jellyfish/normalized_path'
|
6
|
-
|
7
|
-
module Jellyfish
|
8
|
-
module Sinatra
|
9
|
-
include MultiActions
|
10
|
-
include NormalizedParams
|
11
|
-
include NormalizedPath
|
12
|
-
end
|
13
|
-
end
|