jellyfish 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +41 -0
- data/.gitmodules +1 -1
- data/CHANGES.md +21 -0
- data/Gemfile +0 -4
- data/README.md +45 -49
- data/config.ru +1 -2
- data/jellyfish.gemspec +5 -5
- data/lib/jellyfish/builder.rb +3 -3
- data/lib/jellyfish/version.rb +1 -1
- data/lib/jellyfish.rb +30 -28
- data/task/README.md +4 -4
- data/task/gemgem.rb +3 -1
- data/test/rack/test_builder.rb +6 -6
- data/test/rack/test_urlmap.rb +86 -86
- data/test/sinatra/test_base.rb +6 -6
- data/test/sinatra/test_routing.rb +3 -3
- data/test/test_from_readme.rb +1 -1
- data/test/test_log.rb +2 -1
- data/test/test_rewrite.rb +14 -0
- metadata +7 -8
- data/.travis.yml +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2ac4c1c5b9beff9266516aa120e637e7c1b3d09010e0f0cf0df7b8728e26646
|
4
|
+
data.tar.gz: 8cd5fff611eea7b8fc454aa8a4d2a844225cf2904d6fcf46dacfc118f9090d84
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87587d0f02f1896aa15fb8b72daf2e1cd22b129a89f277680f56ada903778ff2d23c86765273a6199e97c85563e458225a8079bd97e660b4085103b548d99a78
|
7
|
+
data.tar.gz: 35071bfc020d030e952c2023a3bfb7c8cdcf9723194bb8f70212e4cb01b0dc74105a9ccfd93e4c7921f94b37c10049e74e42322cc0532447b87c8e90ceacfd38
|
data/.gitlab-ci.yml
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
stages:
|
3
|
+
- test
|
4
|
+
|
5
|
+
.test:
|
6
|
+
stage: test
|
7
|
+
image: ruby:${RUBY_VERSION}-bullseye
|
8
|
+
variables:
|
9
|
+
GIT_DEPTH: "1"
|
10
|
+
GIT_SUBMODULE_STRATEGY: recursive
|
11
|
+
GIT_SUBMODULE_PATHS: task
|
12
|
+
# websocket_parser does not work with frozen string literal
|
13
|
+
# RUBYOPT: --enable-frozen-string-literal
|
14
|
+
before_script:
|
15
|
+
- bundle install --retry=3
|
16
|
+
- unset CI # Coverage doesn't work well with frozen literal
|
17
|
+
script:
|
18
|
+
- ruby -vr bundler/setup -S rake test
|
19
|
+
|
20
|
+
ruby:3.0:
|
21
|
+
extends:
|
22
|
+
- .test
|
23
|
+
variables:
|
24
|
+
RUBY_VERSION: '3.0'
|
25
|
+
|
26
|
+
ruby:3.1:
|
27
|
+
extends:
|
28
|
+
- .test
|
29
|
+
variables:
|
30
|
+
RUBY_VERSION: '3.1'
|
31
|
+
|
32
|
+
ruby:3.2:
|
33
|
+
extends:
|
34
|
+
- .test
|
35
|
+
variables:
|
36
|
+
RUBY_VERSION: '3.2'
|
37
|
+
|
38
|
+
jruby:latest:
|
39
|
+
extends:
|
40
|
+
- .test
|
41
|
+
image: jruby:latest
|
data/.gitmodules
CHANGED
data/CHANGES.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# CHANGES
|
2
2
|
|
3
|
+
## Jellyfish 1.4.0 -- 2023-02-22
|
4
|
+
|
5
|
+
### Incompatible changes
|
6
|
+
|
7
|
+
* Adopted Rack 3. Technically, just lower the cases for headers.
|
8
|
+
* Internal strings are all frozen now.
|
9
|
+
* `log` and `log_error` now takes the `env` for the second argument,
|
10
|
+
rather than the error stream.
|
11
|
+
* `handle` now takes the `env` for the third argument,
|
12
|
+
rather than the error stream.
|
13
|
+
|
14
|
+
### Enhancements
|
15
|
+
|
16
|
+
* The default error logging will now also show `env['PATH_INFO']`.
|
17
|
+
|
18
|
+
## Jellyfish 1.3.1 -- 2018-11-11
|
19
|
+
|
20
|
+
### Bugs fixed
|
21
|
+
|
22
|
+
* Fixed `Jellyfish::Rewrite` for SCRIPT_NAME when host is also used.
|
23
|
+
|
3
24
|
## Jellyfish 1.3.0 -- 2018-11-11
|
4
25
|
|
5
26
|
### Incompatible changes
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# Jellyfish [![
|
1
|
+
# Jellyfish [![Pipeline status](https://gitlab.com/godfat/jellyfish/badges/master/pipeline.svg)](https://gitlab.com/godfat/jellyfish/-/pipelines)
|
2
2
|
|
3
|
-
by Lin Jen-Shin ([godfat](
|
3
|
+
by Lin Jen-Shin ([godfat](https://godfat.org))
|
4
4
|
|
5
5
|
![logo](https://github.com/godfat/jellyfish/raw/master/jellyfish.png)
|
6
6
|
|
@@ -8,7 +8,7 @@ by Lin Jen-Shin ([godfat](http://godfat.org))
|
|
8
8
|
|
9
9
|
* [github](https://github.com/godfat/jellyfish)
|
10
10
|
* [rubygems](https://rubygems.org/gems/jellyfish)
|
11
|
-
* [rdoc](
|
11
|
+
* [rdoc](https://rubydoc.info/github/godfat/jellyfish)
|
12
12
|
* [issues](https://github.com/godfat/jellyfish/issues) (feel free to ask for support)
|
13
13
|
|
14
14
|
## DESCRIPTION:
|
@@ -42,7 +42,7 @@ Check [jellyfish-contrib][] for extra extensions.
|
|
42
42
|
* Simple
|
43
43
|
* Modular
|
44
44
|
* No templates (You could use [tilt](https://github.com/rtomayko/tilt))
|
45
|
-
* No ORM (You could use [sequel](
|
45
|
+
* No ORM (You could use [sequel](https://sequel.jeremyevans.net))
|
46
46
|
* No `dup` in `call`
|
47
47
|
* Regular expression routes, e.g. `get %r{^/(?<id>\d+)$}`
|
48
48
|
* String routes, e.g. `get '/'`
|
@@ -56,7 +56,7 @@ Because Sinatra is too complex and inconsistent for me.
|
|
56
56
|
|
57
57
|
## REQUIREMENTS:
|
58
58
|
|
59
|
-
* Tested with MRI (official CRuby)
|
59
|
+
* Tested with MRI (official CRuby) and JRuby.
|
60
60
|
|
61
61
|
## INSTALLATION:
|
62
62
|
|
@@ -84,7 +84,7 @@ run Tank.new
|
|
84
84
|
<!---
|
85
85
|
GET /
|
86
86
|
[200,
|
87
|
-
{'
|
87
|
+
{'content-length' => '12', 'content-type' => 'text/plain'},
|
88
88
|
["Jelly Kelly\n"]]
|
89
89
|
-->
|
90
90
|
|
@@ -106,7 +106,7 @@ run Tank.new
|
|
106
106
|
<!---
|
107
107
|
GET /123
|
108
108
|
[200,
|
109
|
-
{'
|
109
|
+
{'content-length' => '11', 'content-type' => 'text/plain'},
|
110
110
|
["Jelly #123\n"]]
|
111
111
|
-->
|
112
112
|
|
@@ -133,7 +133,7 @@ run Tank.new
|
|
133
133
|
<!---
|
134
134
|
GET /hctam
|
135
135
|
[200,
|
136
|
-
{'
|
136
|
+
{'content-length' => '5', 'content-type' => 'text/plain'},
|
137
137
|
["true\n"]]
|
138
138
|
-->
|
139
139
|
|
@@ -159,7 +159,7 @@ run Tank.new
|
|
159
159
|
<!---
|
160
160
|
POST /
|
161
161
|
[201,
|
162
|
-
{'
|
162
|
+
{'content-length' => '18', 'content-type' => 'text/plain',
|
163
163
|
'X-Jellyfish-Life' => '100', 'X-Jellyfish-Mana' => '200'},
|
164
164
|
["Jellyfish 100/200\n"]]
|
165
165
|
-->
|
@@ -185,8 +185,8 @@ body = File.read("#{File.dirname(
|
|
185
185
|
File.expand_path(__FILE__))}/../lib/jellyfish/public/302.html").
|
186
186
|
gsub('VAR_URL', 'http://host/')
|
187
187
|
[302,
|
188
|
-
{'
|
189
|
-
'
|
188
|
+
{'content-length' => body.bytesize.to_s, 'content-type' => 'text/html',
|
189
|
+
'location' => 'http://host/'},
|
190
190
|
[body]]
|
191
191
|
-->
|
192
192
|
|
@@ -210,7 +210,7 @@ GET /crash
|
|
210
210
|
body = File.read("#{File.dirname(
|
211
211
|
File.expand_path(__FILE__))}/../lib/jellyfish/public/500.html")
|
212
212
|
[500,
|
213
|
-
{'
|
213
|
+
{'content-length' => body.bytesize.to_s, 'content-type' => 'text/html'},
|
214
214
|
[body]]
|
215
215
|
-->
|
216
216
|
|
@@ -244,7 +244,7 @@ body = case RUBY_ENGINE
|
|
244
244
|
"No one hears you: (eval):9:in `block in <class:Tank>'\n"
|
245
245
|
end
|
246
246
|
[403,
|
247
|
-
{'
|
247
|
+
{'content-length' => body.bytesize.to_s, 'content-type' => 'text/plain'},
|
248
248
|
[body]]
|
249
249
|
-->
|
250
250
|
|
@@ -267,7 +267,7 @@ run Tank.new
|
|
267
267
|
<!---
|
268
268
|
GET /
|
269
269
|
[404,
|
270
|
-
{'
|
270
|
+
{'content-length' => '18', 'content-type' => 'text/plain'},
|
271
271
|
["You found nothing."]]
|
272
272
|
-->
|
273
273
|
|
@@ -293,7 +293,7 @@ run Tank.new
|
|
293
293
|
<!---
|
294
294
|
GET /
|
295
295
|
[404,
|
296
|
-
{'
|
296
|
+
{'content-length' => '18', 'content-type' => 'text/plain'},
|
297
297
|
["You found nothing."]]
|
298
298
|
-->
|
299
299
|
|
@@ -315,7 +315,7 @@ run Tank.new
|
|
315
315
|
<!---
|
316
316
|
GET /report?name=godfat
|
317
317
|
[200,
|
318
|
-
{'
|
318
|
+
{'content-length' => '20', 'content-type' => 'text/plain'},
|
319
319
|
["Your name is godfat\n"]]
|
320
320
|
-->
|
321
321
|
|
@@ -341,7 +341,7 @@ run Tank.new
|
|
341
341
|
<!---
|
342
342
|
GET /report
|
343
343
|
[200,
|
344
|
-
{'
|
344
|
+
{'content-length' => '3', 'content-type' => 'text/plain'},
|
345
345
|
["OK\n"]]
|
346
346
|
-->
|
347
347
|
|
@@ -374,7 +374,7 @@ run Heater.new
|
|
374
374
|
<!---
|
375
375
|
GET /status
|
376
376
|
[200,
|
377
|
-
{'
|
377
|
+
{'content-length' => '6', 'content-type' => 'text/plain'},
|
378
378
|
["30\u{2103}\n"]]
|
379
379
|
-->
|
380
380
|
|
@@ -406,7 +406,7 @@ run Heater.new
|
|
406
406
|
<!---
|
407
407
|
GET /status
|
408
408
|
[200,
|
409
|
-
{'
|
409
|
+
{'content-length' => '6', 'content-type' => 'text/plain'},
|
410
410
|
["30\u{2103}\n"]]
|
411
411
|
-->
|
412
412
|
|
@@ -438,7 +438,7 @@ run Tank.new
|
|
438
438
|
<!---
|
439
439
|
GET /123
|
440
440
|
[200,
|
441
|
-
{'
|
441
|
+
{'content-length' => '13', 'content-type' => 'text/plain'},
|
442
442
|
["Jelly jumps.\n"]]
|
443
443
|
-->
|
444
444
|
|
@@ -554,13 +554,13 @@ GET /m/x
|
|
554
554
|
[200, {}, ["m\n"]]
|
555
555
|
|
556
556
|
GET /
|
557
|
-
[200, {'
|
557
|
+
[200, {'content-length' => '2'}, ["/\n"]]
|
558
558
|
|
559
559
|
GET /x
|
560
|
-
[200, {'
|
560
|
+
[200, {'content-length' => '2'}, ["/\n"]]
|
561
561
|
|
562
562
|
GET /ab
|
563
|
-
[200, {'
|
563
|
+
[200, {'content-length' => '2'}, ["/\n"]]
|
564
564
|
-->
|
565
565
|
|
566
566
|
You could try a stupid benchmark yourself:
|
@@ -807,7 +807,7 @@ run Tank.new
|
|
807
807
|
<!---
|
808
808
|
GET /123
|
809
809
|
[200,
|
810
|
-
{'
|
810
|
+
{'content-length' => '11', 'content-type' => 'text/plain'},
|
811
811
|
["Jelly #123\n"]]
|
812
812
|
-->
|
813
813
|
|
@@ -831,7 +831,7 @@ run Tank.new
|
|
831
831
|
<!---
|
832
832
|
GET /%E5%9B%A7
|
833
833
|
[200,
|
834
|
-
{'
|
834
|
+
{'content-length' => '16', 'content-type' => 'text/plain'},
|
835
835
|
["/%E5%9B%A7=/\u{56e7}\n"]]
|
836
836
|
-->
|
837
837
|
|
@@ -862,7 +862,7 @@ run Tank.new
|
|
862
862
|
<!---
|
863
863
|
GET /123
|
864
864
|
[200,
|
865
|
-
{'
|
865
|
+
{'content-length' => '18', 'content-type' => 'text/plain'},
|
866
866
|
["Jelly #123 jumps.\n"]]
|
867
867
|
-->
|
868
868
|
|
@@ -896,7 +896,7 @@ run Tank.new
|
|
896
896
|
<!---
|
897
897
|
GET /
|
898
898
|
[200,
|
899
|
-
{'
|
899
|
+
{'content-length' => '12', 'content-type' => 'text/plain'},
|
900
900
|
["Jelly Kelly\n"]]
|
901
901
|
-->
|
902
902
|
|
@@ -934,7 +934,7 @@ run Tank.new
|
|
934
934
|
<!---
|
935
935
|
GET /status
|
936
936
|
[200,
|
937
|
-
{'
|
937
|
+
{'content-length' => '25', 'content-type' => 'text/plain',
|
938
938
|
'X-Temperature' => "30\u{2103}"},
|
939
939
|
["See header X-Temperature\n"]]
|
940
940
|
-->
|
@@ -980,7 +980,7 @@ run Tank.new
|
|
980
980
|
<!---
|
981
981
|
GET /status
|
982
982
|
[200,
|
983
|
-
{'
|
983
|
+
{'content-length' => '1', 'content-type' => 'text/plain',
|
984
984
|
'X-Temperature' => "35\u{2103}"},
|
985
985
|
["\n"]]
|
986
986
|
-->
|
@@ -1013,7 +1013,7 @@ run Tank.new
|
|
1013
1013
|
<!---
|
1014
1014
|
GET /status
|
1015
1015
|
[200,
|
1016
|
-
{'
|
1016
|
+
{'content-length' => '6', 'content-type' => 'text/plain'},
|
1017
1017
|
["30\u{2103}\n"]]
|
1018
1018
|
-->
|
1019
1019
|
|
@@ -1048,7 +1048,7 @@ run HugeTank
|
|
1048
1048
|
<!---
|
1049
1049
|
GET /status
|
1050
1050
|
[200,
|
1051
|
-
{'
|
1051
|
+
{'content-length' => '6', 'content-type' => 'text/plain'},
|
1052
1052
|
["30\u{2103}\n"]]
|
1053
1053
|
-->
|
1054
1054
|
|
@@ -1081,7 +1081,7 @@ run Tank.new
|
|
1081
1081
|
<!---
|
1082
1082
|
GET /
|
1083
1083
|
[200,
|
1084
|
-
{'
|
1084
|
+
{'content-length' => '29', 'content-type' => 'text/plain'},
|
1085
1085
|
["Protected: Oops, tank broken\n"]]
|
1086
1086
|
-->
|
1087
1087
|
|
@@ -1099,7 +1099,6 @@ class Tank
|
|
1099
1099
|
}
|
1100
1100
|
end
|
1101
1101
|
end
|
1102
|
-
use Rack::Chunked
|
1103
1102
|
use Rack::ContentType, 'text/plain'
|
1104
1103
|
run Tank.new
|
1105
1104
|
```
|
@@ -1107,9 +1106,8 @@ run Tank.new
|
|
1107
1106
|
<!---
|
1108
1107
|
GET /chunked
|
1109
1108
|
[200,
|
1110
|
-
{'
|
1111
|
-
["
|
1112
|
-
"2\r\n3\n\r\n", "2\r\n4\n\r\n", "0\r\n\r\n"]]
|
1109
|
+
{'content-type' => 'text/plain'},
|
1110
|
+
["0\n", "1\n", "2\n", "3\n", "4\n"]]
|
1113
1111
|
-->
|
1114
1112
|
|
1115
1113
|
### Chunked transfer encoding (streaming) with custom body
|
@@ -1126,7 +1124,6 @@ class Tank
|
|
1126
1124
|
Body.new
|
1127
1125
|
end
|
1128
1126
|
end
|
1129
|
-
use Rack::Chunked
|
1130
1127
|
use Rack::ContentType, 'text/plain'
|
1131
1128
|
run Tank.new
|
1132
1129
|
```
|
@@ -1134,9 +1131,8 @@ run Tank.new
|
|
1134
1131
|
<!---
|
1135
1132
|
GET /chunked
|
1136
1133
|
[200,
|
1137
|
-
{'
|
1138
|
-
["
|
1139
|
-
"2\r\n3\n\r\n", "2\r\n4\n\r\n", "0\r\n\r\n"]]
|
1134
|
+
{'content-type' => 'text/plain'},
|
1135
|
+
["0\n", "1\n", "2\n", "3\n", "4\n"]]
|
1140
1136
|
-->
|
1141
1137
|
|
1142
1138
|
### Server Sent Event (SSE)
|
@@ -1150,7 +1146,7 @@ class Tank
|
|
1150
1146
|
end
|
1151
1147
|
end
|
1152
1148
|
get '/sse' do
|
1153
|
-
headers_merge('
|
1149
|
+
headers_merge('content-type' => 'text/event-stream')
|
1154
1150
|
Body.new
|
1155
1151
|
end
|
1156
1152
|
end
|
@@ -1160,7 +1156,7 @@ run Tank.new
|
|
1160
1156
|
<!---
|
1161
1157
|
GET /sse
|
1162
1158
|
[200,
|
1163
|
-
{'
|
1159
|
+
{'content-type' => 'text/event-stream'},
|
1164
1160
|
["data: 0\n\n", "data: 1\n\n", "data: 2\n\n", "data: 3\n\n", "data: 4\n\n"]]
|
1165
1161
|
-->
|
1166
1162
|
|
@@ -1171,7 +1167,7 @@ class Tank
|
|
1171
1167
|
include Jellyfish
|
1172
1168
|
get '/sse' do
|
1173
1169
|
headers_merge(
|
1174
|
-
'
|
1170
|
+
'content-type' => 'text/event-stream',
|
1175
1171
|
'rack.hijack' => lambda do |sock|
|
1176
1172
|
(0..4).each do |i|
|
1177
1173
|
sock.write("data: #{i}\n\n")
|
@@ -1186,7 +1182,7 @@ run Tank.new
|
|
1186
1182
|
<!---
|
1187
1183
|
GET /sse
|
1188
1184
|
[200,
|
1189
|
-
{'
|
1185
|
+
{'content-type' => 'text/event-stream'},
|
1190
1186
|
["data: 0\n\n", "data: 1\n\n", "data: 2\n\n", "data: 3\n\n", "data: 4\n\n"]]
|
1191
1187
|
-->
|
1192
1188
|
|
@@ -1201,9 +1197,9 @@ EventMachine is basically dead, we could see if there would be a
|
|
1201
1197
|
[Celluloid-IO][] based web server production ready in the future,
|
1202
1198
|
so that we could take the advantage of event based approach.
|
1203
1199
|
|
1204
|
-
[hijack]:
|
1205
|
-
[Rainbows!]:
|
1206
|
-
[Puma]:
|
1200
|
+
[hijack]: https://github.com/rack/rack/blob/main/SPEC.rdoc#label-Hijacking
|
1201
|
+
[Rainbows!]: https://yhbt.net/rainbows/
|
1202
|
+
[Puma]: https://puma.io
|
1207
1203
|
[Celluloid-IO]: https://github.com/celluloid/celluloid-io
|
1208
1204
|
|
1209
1205
|
``` ruby
|
@@ -1244,13 +1240,13 @@ HTTP
|
|
1244
1240
|
|
1245
1241
|
Apache License 2.0 (Apache-2.0)
|
1246
1242
|
|
1247
|
-
Copyright (c) 2012-
|
1243
|
+
Copyright (c) 2012-2023, Lin Jen-Shin (godfat)
|
1248
1244
|
|
1249
1245
|
Licensed under the Apache License, Version 2.0 (the "License");
|
1250
1246
|
you may not use this file except in compliance with the License.
|
1251
1247
|
You may obtain a copy of the License at
|
1252
1248
|
|
1253
|
-
<
|
1249
|
+
<https://www.apache.org/licenses/LICENSE-2.0>
|
1254
1250
|
|
1255
1251
|
Unless required by applicable law or agreed to in writing, software
|
1256
1252
|
distributed under the License is distributed on an "AS IS" BASIS,
|
data/config.ru
CHANGED
@@ -7,7 +7,7 @@ class Jelly
|
|
7
7
|
|
8
8
|
controller_include Module.new{
|
9
9
|
def dispatch
|
10
|
-
headers_merge '
|
10
|
+
headers_merge 'content-type' => 'application/json; charset=utf-8',
|
11
11
|
'Access-Control-Allow-Origin' => '*'
|
12
12
|
super
|
13
13
|
end
|
@@ -59,7 +59,6 @@ end
|
|
59
59
|
|
60
60
|
App = Jellyfish::Builder.app do
|
61
61
|
use Rack::CommonLogger
|
62
|
-
use Rack::Chunked
|
63
62
|
use Rack::ContentLength
|
64
63
|
use Rack::Deflater
|
65
64
|
|
data/jellyfish.gemspec
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: jellyfish 1.
|
2
|
+
# stub: jellyfish 1.4.0 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "jellyfish".freeze
|
6
|
-
s.version = "1.
|
6
|
+
s.version = "1.4.0"
|
7
7
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
9
9
|
s.require_paths = ["lib".freeze]
|
10
10
|
s.authors = ["Lin Jen-Shin (godfat)".freeze]
|
11
|
-
s.date = "
|
11
|
+
s.date = "2023-02-22"
|
12
12
|
s.description = "Pico web framework for building API-centric web applications.\nFor Rack applications or Rack middleware. Around 250 lines of code.\n\nCheck [jellyfish-contrib][] for extra extensions.\n\n[jellyfish-contrib]: https://github.com/godfat/jellyfish-contrib".freeze
|
13
13
|
s.email = ["godfat (XD) godfat.org".freeze]
|
14
14
|
s.files = [
|
15
15
|
".gitignore".freeze,
|
16
|
+
".gitlab-ci.yml".freeze,
|
16
17
|
".gitmodules".freeze,
|
17
|
-
".travis.yml".freeze,
|
18
18
|
"CHANGES.md".freeze,
|
19
19
|
"Gemfile".freeze,
|
20
20
|
"LICENSE".freeze,
|
@@ -56,7 +56,7 @@ Gem::Specification.new do |s|
|
|
56
56
|
"test/test_websocket.rb".freeze]
|
57
57
|
s.homepage = "https://github.com/godfat/jellyfish".freeze
|
58
58
|
s.licenses = ["Apache-2.0".freeze]
|
59
|
-
s.rubygems_version = "
|
59
|
+
s.rubygems_version = "3.4.3".freeze
|
60
60
|
s.summary = "Pico web framework for building API-centric web applications.".freeze
|
61
61
|
s.test_files = [
|
62
62
|
"test/rack/test_builder.rb".freeze,
|
data/lib/jellyfish/builder.rb
CHANGED
@@ -31,7 +31,7 @@ module Jellyfish
|
|
31
31
|
|
32
32
|
def map path, to: nil, host: nil, &block
|
33
33
|
key = if host then "http://#{File.join(host, path)}" else path end
|
34
|
-
(@map ||= {})[key] = [block, to]
|
34
|
+
(@map ||= {})[key] = [block, path, to]
|
35
35
|
end
|
36
36
|
|
37
37
|
def listen host, &block
|
@@ -56,8 +56,8 @@ module Jellyfish
|
|
56
56
|
private
|
57
57
|
def generate_map current_map, app
|
58
58
|
mapped = if app then {'' => app} else {} end
|
59
|
-
current_map.each do |path, (block, to)|
|
60
|
-
mapped[path] = self.class.app(app,
|
59
|
+
current_map.each do |path, (block, from, to)|
|
60
|
+
mapped[path] = self.class.app(app, from, to, &block)
|
61
61
|
end
|
62
62
|
URLMap.new(mapped)
|
63
63
|
end
|
data/lib/jellyfish/version.rb
CHANGED
data/lib/jellyfish.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module Jellyfish
|
3
4
|
autoload :VERSION , 'jellyfish/version'
|
@@ -15,7 +16,7 @@ module Jellyfish
|
|
15
16
|
|
16
17
|
class Response < RuntimeError
|
17
18
|
def headers
|
18
|
-
@headers ||= {'
|
19
|
+
@headers ||= {'content-type' => 'text/html'}
|
19
20
|
end
|
20
21
|
|
21
22
|
def body
|
@@ -29,7 +30,7 @@ module Jellyfish
|
|
29
30
|
attr_reader :url
|
30
31
|
def initialize url; @url = url ; end
|
31
32
|
def status ; 302 ; end
|
32
|
-
def headers ; super.merge('
|
33
|
+
def headers ; super.merge('location' => url) ; end
|
33
34
|
def body ; super.map{ |b| b.gsub('VAR_URL', url) }; end
|
34
35
|
end
|
35
36
|
|
@@ -55,8 +56,8 @@ module Jellyfish
|
|
55
56
|
raise
|
56
57
|
end
|
57
58
|
|
58
|
-
def log message; jellyfish.log( message, env
|
59
|
-
def log_error error; jellyfish.log_error(error, env
|
59
|
+
def log message; jellyfish.log( message, env); end
|
60
|
+
def log_error error; jellyfish.log_error(error, env); end
|
60
61
|
def request ; @request ||= Rack::Request.new(env); end
|
61
62
|
def halt *args; throw(:halt, *args) ; end
|
62
63
|
def cascade ; halt(Jellyfish::Cascade) ; end
|
@@ -190,7 +191,7 @@ module Jellyfish
|
|
190
191
|
when Cascade
|
191
192
|
cascade(ctrl, env)
|
192
193
|
when Response
|
193
|
-
handle(ctrl, res, env
|
194
|
+
handle(ctrl, res, env)
|
194
195
|
when Array
|
195
196
|
res
|
196
197
|
when NilClass # make sure we return rack triple
|
@@ -199,47 +200,48 @@ module Jellyfish
|
|
199
200
|
raise TypeError.new("Expect the response to be a Jellyfish::Response" \
|
200
201
|
" or Rack triple (Array), but got: #{res.inspect}")
|
201
202
|
end
|
202
|
-
rescue =>
|
203
|
-
handle(ctrl,
|
203
|
+
rescue => error
|
204
|
+
handle(ctrl, error, env)
|
204
205
|
end
|
205
206
|
|
206
|
-
def log_error
|
207
|
-
|
208
|
-
|
207
|
+
def log_error error, env
|
208
|
+
env['rack.errors']&.
|
209
|
+
puts("[#{self.class.name}] #{error.inspect}" \
|
210
|
+
" for #{env['PATH_INFO'] || '/'} #{error.backtrace}")
|
209
211
|
end
|
210
212
|
|
211
|
-
def log msg,
|
212
|
-
|
213
|
-
|
213
|
+
def log msg, env
|
214
|
+
env['rack.errors']&.
|
215
|
+
puts("[#{self.class.name}] #{msg}")
|
214
216
|
end
|
215
217
|
|
216
218
|
private
|
217
219
|
def cascade ctrl, env
|
218
220
|
app.call(env)
|
219
|
-
rescue =>
|
220
|
-
handle(ctrl,
|
221
|
+
rescue => error
|
222
|
+
handle(ctrl, error, env)
|
221
223
|
end
|
222
224
|
|
223
|
-
def handle ctrl,
|
224
|
-
if handler = best_handler(
|
225
|
-
ctrl.block_call(
|
225
|
+
def handle ctrl, error, env
|
226
|
+
if handler = best_handler(error)
|
227
|
+
ctrl.block_call(error, handler)
|
226
228
|
elsif !self.class.handle_exceptions
|
227
|
-
raise
|
228
|
-
elsif
|
229
|
-
[
|
229
|
+
raise error
|
230
|
+
elsif error.kind_of?(Response) # InternalError ends up here if no handlers
|
231
|
+
[error.status, error.headers, error.body]
|
230
232
|
else # fallback and see if there's any InternalError handler
|
231
|
-
log_error(
|
232
|
-
handle(ctrl, InternalError.new)
|
233
|
+
log_error(error, env)
|
234
|
+
handle(ctrl, InternalError.new, env)
|
233
235
|
end
|
234
236
|
end
|
235
237
|
|
236
|
-
def best_handler
|
238
|
+
def best_handler error
|
237
239
|
handlers = self.class.handlers
|
238
|
-
if handlers.key?(
|
239
|
-
handlers[
|
240
|
+
if handlers.key?(error.class)
|
241
|
+
handlers[error.class]
|
240
242
|
else # or find the nearest match and cache it
|
241
|
-
ancestors
|
242
|
-
handlers[
|
243
|
+
ancestors = error.class.ancestors
|
244
|
+
handlers[error.class] = handlers.dup. # thread safe iteration
|
243
245
|
inject([nil, Float::INFINITY]){ |(handler, val), (klass, block)|
|
244
246
|
idx = ancestors.index(klass) || Float::INFINITY # lower is better
|
245
247
|
if idx < val then [block, idx] else [handler, val] end }.first
|
data/task/README.md
CHANGED
@@ -13,11 +13,11 @@ Provided tasks:
|
|
13
13
|
|
14
14
|
## REQUIREMENTS:
|
15
15
|
|
16
|
-
* Tested with MRI (official CRuby)
|
16
|
+
* Tested with MRI (official CRuby) and JRuby.
|
17
17
|
|
18
18
|
## INSTALLATION:
|
19
19
|
|
20
|
-
git submodule add
|
20
|
+
git submodule add https://github.com/godfat/gemgem.git task
|
21
21
|
|
22
22
|
And in Rakefile:
|
23
23
|
|
@@ -39,13 +39,13 @@ end
|
|
39
39
|
|
40
40
|
Apache License 2.0 (Apache-2.0)
|
41
41
|
|
42
|
-
Copyright (c) 2011-
|
42
|
+
Copyright (c) 2011-2023, Lin Jen-Shin (godfat)
|
43
43
|
|
44
44
|
Licensed under the Apache License, Version 2.0 (the "License");
|
45
45
|
you may not use this file except in compliance with the License.
|
46
46
|
You may obtain a copy of the License at
|
47
47
|
|
48
|
-
<
|
48
|
+
<https://www.apache.org/licenses/LICENSE-2.0>
|
49
49
|
|
50
50
|
Unless required by applicable law or agreed to in writing, software
|
51
51
|
distributed under the License is distributed on an "AS IS" BASIS,
|
data/task/gemgem.rb
CHANGED
@@ -42,6 +42,7 @@ module Gemgem
|
|
42
42
|
|
43
43
|
def gem_install
|
44
44
|
require 'rubygems/commands/install_command'
|
45
|
+
require 'rubygems/package'
|
45
46
|
# read ~/.gemrc
|
46
47
|
Gem.use_paths(Gem.configuration[:gemhome], Gem.configuration[:gempath])
|
47
48
|
Gem::Command.extra_args = Gem.configuration[:gem]
|
@@ -51,7 +52,8 @@ module Gemgem
|
|
51
52
|
cmd.handle_options([])
|
52
53
|
|
53
54
|
# install
|
54
|
-
|
55
|
+
gem_package = Gem::Package.new(gem_path)
|
56
|
+
install = Gem::Installer.new(gem_package, cmd.options)
|
55
57
|
install.install
|
56
58
|
puts "\e[35mGem installed: \e[33m#{strip_path(install.gem_dir)}\e[0m"
|
57
59
|
end
|
data/test/rack/test_builder.rb
CHANGED
@@ -28,10 +28,10 @@ describe Jellyfish::Builder do
|
|
28
28
|
would "supports mapping" do
|
29
29
|
app = builder_to_app do
|
30
30
|
map '/' do |outer_env|
|
31
|
-
run lambda { |inner_env| [200, {"
|
31
|
+
run lambda { |inner_env| [200, {"content-type" => "text/plain"}, ['root']] }
|
32
32
|
end
|
33
33
|
map '/sub' do
|
34
|
-
run lambda { |inner_env| [200, {"
|
34
|
+
run lambda { |inner_env| [200, {"content-type" => "text/plain"}, ['sub']] }
|
35
35
|
end
|
36
36
|
end
|
37
37
|
Rack::MockRequest.new(app).get("/").body.to_s.should.eq 'root'
|
@@ -56,7 +56,7 @@ describe Jellyfish::Builder do
|
|
56
56
|
'secret' == password
|
57
57
|
end
|
58
58
|
|
59
|
-
run lambda { |env| [200, {"
|
59
|
+
run lambda { |env| [200, {"content-type" => "text/plain"}, ['Hi Boss']] }
|
60
60
|
end
|
61
61
|
|
62
62
|
response = Rack::MockRequest.new(app).get("/")
|
@@ -84,9 +84,9 @@ describe Jellyfish::Builder do
|
|
84
84
|
would "can mix map and run for endpoints" do
|
85
85
|
app = builder_to_app do
|
86
86
|
map '/sub' do
|
87
|
-
run lambda { |inner_env| [200, {"
|
87
|
+
run lambda { |inner_env| [200, {"content-type" => "text/plain"}, ['sub']] }
|
88
88
|
end
|
89
|
-
run lambda { |inner_env| [200, {"
|
89
|
+
run lambda { |inner_env| [200, {"content-type" => "text/plain"}, ['root']] }
|
90
90
|
end
|
91
91
|
|
92
92
|
Rack::MockRequest.new(app).get("/").body.to_s.should.eq 'root'
|
@@ -123,7 +123,7 @@ describe Jellyfish::Builder do
|
|
123
123
|
def call(env)
|
124
124
|
raise "bzzzt" if @called > 0
|
125
125
|
@called += 1
|
126
|
-
[200, {'
|
126
|
+
[200, {'content-type' => 'text/plain'}, ['OK']]
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
data/test/rack/test_urlmap.rb
CHANGED
@@ -8,9 +8,9 @@ describe Jellyfish::URLMap do
|
|
8
8
|
would "dispatches paths correctly" do
|
9
9
|
app = lambda { |env|
|
10
10
|
[200, {
|
11
|
-
'
|
12
|
-
'
|
13
|
-
'
|
11
|
+
'x-scriptname' => env['SCRIPT_NAME'],
|
12
|
+
'x-pathinfo' => env['PATH_INFO'],
|
13
|
+
'content-type' => 'text/plain'
|
14
14
|
}, [""]]
|
15
15
|
}
|
16
16
|
map = Rack::Lint.new(Jellyfish::URLMap.new({
|
@@ -27,102 +27,102 @@ describe Jellyfish::URLMap do
|
|
27
27
|
|
28
28
|
res = Rack::MockRequest.new(map).get("/foo")
|
29
29
|
res.should.ok?
|
30
|
-
res["
|
31
|
-
res["
|
30
|
+
res["x-scriptname"].should.eq "/foo"
|
31
|
+
res["x-pathinfo"].should.eq ""
|
32
32
|
|
33
33
|
res = Rack::MockRequest.new(map).get("/foo/")
|
34
34
|
res.should.ok?
|
35
|
-
res["
|
36
|
-
res["
|
35
|
+
res["x-scriptname"].should.eq "/foo"
|
36
|
+
res["x-pathinfo"].should.eq "/"
|
37
37
|
|
38
38
|
res = Rack::MockRequest.new(map).get("/foo/bar")
|
39
39
|
res.should.ok?
|
40
|
-
res["
|
41
|
-
res["
|
40
|
+
res["x-scriptname"].should.eq "/foo/bar"
|
41
|
+
res["x-pathinfo"].should.eq ""
|
42
42
|
|
43
43
|
res = Rack::MockRequest.new(map).get("/foo/bar/")
|
44
44
|
res.should.ok?
|
45
|
-
res["
|
46
|
-
res["
|
45
|
+
res["x-scriptname"].should.eq "/foo/bar"
|
46
|
+
res["x-pathinfo"].should.eq "/"
|
47
47
|
|
48
48
|
res = Rack::MockRequest.new(map).get("/foo///bar//quux")
|
49
49
|
res.status.should.eq 200
|
50
50
|
res.should.ok?
|
51
|
-
res["
|
52
|
-
res["
|
51
|
+
res["x-scriptname"].should.eq "/foo/bar"
|
52
|
+
res["x-pathinfo"].should.eq "//quux"
|
53
53
|
|
54
54
|
res = Rack::MockRequest.new(map).get("/foo/quux", "SCRIPT_NAME" => "/bleh")
|
55
55
|
res.should.ok?
|
56
|
-
res["
|
57
|
-
res["
|
56
|
+
res["x-scriptname"].should.eq "/bleh/foo"
|
57
|
+
res["x-pathinfo"].should.eq "/quux"
|
58
58
|
|
59
59
|
res = Rack::MockRequest.new(map).get("/bar", 'HTTP_HOST' => 'foo.org')
|
60
60
|
res.should.ok?
|
61
|
-
res["
|
62
|
-
res["
|
61
|
+
res["x-scriptname"].should.eq "/bar"
|
62
|
+
res["x-pathinfo"].should.empty?
|
63
63
|
|
64
64
|
res = Rack::MockRequest.new(map).get("/bar/", 'HTTP_HOST' => 'foo.org')
|
65
65
|
res.should.ok?
|
66
|
-
res["
|
67
|
-
res["
|
66
|
+
res["x-scriptname"].should.eq "/bar"
|
67
|
+
res["x-pathinfo"].should.eq '/'
|
68
68
|
end
|
69
69
|
|
70
70
|
would "dispatches hosts correctly" do
|
71
71
|
map = Rack::Lint.new(Jellyfish::URLMap.new("http://foo.org/" => lambda { |env|
|
72
72
|
[200,
|
73
|
-
{ "
|
74
|
-
"
|
75
|
-
"
|
73
|
+
{ "content-type" => "text/plain",
|
74
|
+
"x-position" => "foo.org",
|
75
|
+
"x-host" => env["HTTP_HOST"] || env["SERVER_NAME"],
|
76
76
|
}, [""]]},
|
77
77
|
"http://subdomain.foo.org/" => lambda { |env|
|
78
78
|
[200,
|
79
|
-
{ "
|
80
|
-
"
|
81
|
-
"
|
79
|
+
{ "content-type" => "text/plain",
|
80
|
+
"x-position" => "subdomain.foo.org",
|
81
|
+
"x-host" => env["HTTP_HOST"] || env["SERVER_NAME"],
|
82
82
|
}, [""]]},
|
83
83
|
"http://bar.org/" => lambda { |env|
|
84
84
|
[200,
|
85
|
-
{ "
|
86
|
-
"
|
87
|
-
"
|
85
|
+
{ "content-type" => "text/plain",
|
86
|
+
"x-position" => "bar.org",
|
87
|
+
"x-host" => env["HTTP_HOST"] || env["SERVER_NAME"],
|
88
88
|
}, [""]]},
|
89
89
|
"/" => lambda { |env|
|
90
90
|
[200,
|
91
|
-
{ "
|
92
|
-
"
|
93
|
-
"
|
91
|
+
{ "content-type" => "text/plain",
|
92
|
+
"x-position" => "default.org",
|
93
|
+
"x-host" => env["HTTP_HOST"] || env["SERVER_NAME"],
|
94
94
|
}, [""]]}
|
95
95
|
))
|
96
96
|
|
97
97
|
res = Rack::MockRequest.new(map).get("/")
|
98
98
|
res.should.ok?
|
99
|
-
res["
|
99
|
+
res["x-position"].should.eq "default.org"
|
100
100
|
|
101
101
|
res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "bar.org")
|
102
102
|
res.should.ok?
|
103
|
-
res["
|
103
|
+
res["x-position"].should.eq "bar.org"
|
104
104
|
|
105
105
|
res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "foo.org")
|
106
106
|
res.should.ok?
|
107
|
-
res["
|
107
|
+
res["x-position"].should.eq "foo.org"
|
108
108
|
|
109
109
|
res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "subdomain.foo.org", "SERVER_NAME" => "foo.org")
|
110
110
|
res.should.ok?
|
111
|
-
res["
|
111
|
+
res["x-position"].should.eq "subdomain.foo.org"
|
112
112
|
|
113
113
|
res = Rack::MockRequest.new(map).get("http://foo.org/")
|
114
114
|
res.should.ok?
|
115
|
-
res["
|
115
|
+
res["x-position"].should.eq "foo.org"
|
116
116
|
|
117
117
|
res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "example.org")
|
118
118
|
res.should.ok?
|
119
|
-
res["
|
119
|
+
res["x-position"].should.eq "default.org"
|
120
120
|
|
121
121
|
res = Rack::MockRequest.new(map).get("/",
|
122
122
|
"HTTP_HOST" => "example.org:9292",
|
123
123
|
"SERVER_PORT" => "9292")
|
124
124
|
res.should.ok?
|
125
|
-
res["
|
125
|
+
res["x-position"].should.eq "default.org"
|
126
126
|
end
|
127
127
|
|
128
128
|
would "be nestable" do
|
@@ -130,10 +130,10 @@ describe Jellyfish::URLMap do
|
|
130
130
|
Jellyfish::URLMap.new("/bar" =>
|
131
131
|
Jellyfish::URLMap.new("/quux" => lambda { |env|
|
132
132
|
[200,
|
133
|
-
{ "
|
134
|
-
"
|
135
|
-
"
|
136
|
-
"
|
133
|
+
{ "content-type" => "text/plain",
|
134
|
+
"x-position" => "/foo/bar/quux",
|
135
|
+
"x-pathinfo" => env["PATH_INFO"],
|
136
|
+
"x-scriptname" => env["SCRIPT_NAME"],
|
137
137
|
}, [""]]}
|
138
138
|
))))
|
139
139
|
|
@@ -142,97 +142,97 @@ describe Jellyfish::URLMap do
|
|
142
142
|
|
143
143
|
res = Rack::MockRequest.new(map).get("/foo/bar/quux")
|
144
144
|
res.should.ok?
|
145
|
-
res["
|
146
|
-
res["
|
147
|
-
res["
|
145
|
+
res["x-position"].should.eq "/foo/bar/quux"
|
146
|
+
res["x-pathinfo"].should.eq ""
|
147
|
+
res["x-scriptname"].should.eq "/foo/bar/quux"
|
148
148
|
end
|
149
149
|
|
150
150
|
would "route root apps correctly" do
|
151
151
|
map = Rack::Lint.new(Jellyfish::URLMap.new("/" => lambda { |env|
|
152
152
|
[200,
|
153
|
-
{ "
|
154
|
-
"
|
155
|
-
"
|
156
|
-
"
|
153
|
+
{ "content-type" => "text/plain",
|
154
|
+
"x-position" => "root",
|
155
|
+
"x-pathinfo" => env["PATH_INFO"],
|
156
|
+
"x-scriptname" => env["SCRIPT_NAME"]
|
157
157
|
}, [""]]},
|
158
158
|
"/foo" => lambda { |env|
|
159
159
|
[200,
|
160
|
-
{ "
|
161
|
-
"
|
162
|
-
"
|
163
|
-
"
|
160
|
+
{ "content-type" => "text/plain",
|
161
|
+
"x-position" => "foo",
|
162
|
+
"x-pathinfo" => env["PATH_INFO"],
|
163
|
+
"x-scriptname" => env["SCRIPT_NAME"]
|
164
164
|
}, [""]]}
|
165
165
|
))
|
166
166
|
|
167
167
|
res = Rack::MockRequest.new(map).get("/foo/bar")
|
168
168
|
res.should.ok?
|
169
|
-
res["
|
170
|
-
res["
|
171
|
-
res["
|
169
|
+
res["x-position"].should.eq "foo"
|
170
|
+
res["x-pathinfo"].should.eq "/bar"
|
171
|
+
res["x-scriptname"].should.eq "/foo"
|
172
172
|
|
173
173
|
res = Rack::MockRequest.new(map).get("/foo")
|
174
174
|
res.should.ok?
|
175
|
-
res["
|
176
|
-
res["
|
177
|
-
res["
|
175
|
+
res["x-position"].should.eq "foo"
|
176
|
+
res["x-pathinfo"].should.eq ""
|
177
|
+
res["x-scriptname"].should.eq "/foo"
|
178
178
|
|
179
179
|
res = Rack::MockRequest.new(map).get("/bar")
|
180
180
|
res.should.ok?
|
181
|
-
res["
|
182
|
-
res["
|
183
|
-
res["
|
181
|
+
res["x-position"].should.eq "root"
|
182
|
+
res["x-pathinfo"].should.eq "/bar"
|
183
|
+
res["x-scriptname"].should.eq ""
|
184
184
|
|
185
185
|
res = Rack::MockRequest.new(map).get("")
|
186
186
|
res.should.ok?
|
187
|
-
res["
|
188
|
-
res["
|
189
|
-
res["
|
187
|
+
res["x-position"].should.eq "root"
|
188
|
+
res["x-pathinfo"].should.eq "/"
|
189
|
+
res["x-scriptname"].should.eq ""
|
190
190
|
end
|
191
191
|
|
192
192
|
would "not squeeze slashes" do
|
193
193
|
map = Rack::Lint.new(Jellyfish::URLMap.new("/" => lambda { |env|
|
194
194
|
[200,
|
195
|
-
{ "
|
196
|
-
"
|
197
|
-
"
|
198
|
-
"
|
195
|
+
{ "content-type" => "text/plain",
|
196
|
+
"x-position" => "root",
|
197
|
+
"x-pathinfo" => env["PATH_INFO"],
|
198
|
+
"x-scriptname" => env["SCRIPT_NAME"]
|
199
199
|
}, [""]]},
|
200
200
|
"/foo" => lambda { |env|
|
201
201
|
[200,
|
202
|
-
{ "
|
203
|
-
"
|
204
|
-
"
|
205
|
-
"
|
202
|
+
{ "content-type" => "text/plain",
|
203
|
+
"x-position" => "foo",
|
204
|
+
"x-pathinfo" => env["PATH_INFO"],
|
205
|
+
"x-scriptname" => env["SCRIPT_NAME"]
|
206
206
|
}, [""]]}
|
207
207
|
))
|
208
208
|
|
209
209
|
res = Rack::MockRequest.new(map).get("/http://example.org/bar")
|
210
210
|
res.should.ok?
|
211
|
-
res["
|
212
|
-
res["
|
213
|
-
res["
|
211
|
+
res["x-position"].should.eq "root"
|
212
|
+
res["x-pathinfo"].should.eq "/http://example.org/bar"
|
213
|
+
res["x-scriptname"].should.eq ""
|
214
214
|
end
|
215
215
|
|
216
216
|
would "not be case sensitive with hosts" do
|
217
217
|
map = Rack::Lint.new(Jellyfish::URLMap.new("http://example.org/" => lambda { |env|
|
218
218
|
[200,
|
219
|
-
{ "
|
220
|
-
"
|
221
|
-
"
|
222
|
-
"
|
219
|
+
{ "content-type" => "text/plain",
|
220
|
+
"x-position" => "root",
|
221
|
+
"x-pathinfo" => env["PATH_INFO"],
|
222
|
+
"x-scriptname" => env["SCRIPT_NAME"]
|
223
223
|
}, [""]]}
|
224
224
|
))
|
225
225
|
|
226
226
|
res = Rack::MockRequest.new(map).get("http://example.org/")
|
227
227
|
res.should.ok?
|
228
|
-
res["
|
229
|
-
res["
|
230
|
-
res["
|
228
|
+
res["x-position"].should.eq "root"
|
229
|
+
res["x-pathinfo"].should.eq "/"
|
230
|
+
res["x-scriptname"].should.eq ""
|
231
231
|
|
232
232
|
res = Rack::MockRequest.new(map).get("http://EXAMPLE.ORG/")
|
233
233
|
res.should.ok?
|
234
|
-
res["
|
235
|
-
res["
|
236
|
-
res["
|
234
|
+
res["x-position"].should.eq "root"
|
235
|
+
res["x-pathinfo"].should.eq "/"
|
236
|
+
res["x-scriptname"].should.eq ""
|
237
237
|
end
|
238
238
|
end
|
data/test/sinatra/test_base.rb
CHANGED
@@ -38,7 +38,7 @@ describe 'Sinatra base_test.rb' do
|
|
38
38
|
|
39
39
|
describe 'Jellyfish as a Rack middleware' do
|
40
40
|
inner_app ||= lambda{ |env|
|
41
|
-
[210, {'
|
41
|
+
[210, {'x-downstream' => 'true'}, ['Hello from downstream']]
|
42
42
|
}
|
43
43
|
|
44
44
|
app = Class.new{
|
@@ -55,7 +55,7 @@ describe 'Sinatra base_test.rb' do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
get '/explicit-forward' do
|
58
|
-
headers_merge '
|
58
|
+
headers_merge 'x-middleware' => 'true'
|
59
59
|
status, headers, _ = jellyfish.app.call(env)
|
60
60
|
self.status status
|
61
61
|
self.headers headers
|
@@ -80,14 +80,14 @@ describe 'Sinatra base_test.rb' do
|
|
80
80
|
would 'forward requests downstream when no matching route found' do
|
81
81
|
status, headers, body = get('/missing', app)
|
82
82
|
status .should.eq 210
|
83
|
-
headers['
|
83
|
+
headers['x-downstream'].should.eq 'true'
|
84
84
|
body .should.eq ['Hello from downstream']
|
85
85
|
end
|
86
86
|
|
87
87
|
would 'call the downstream app directly and return result' do
|
88
88
|
status, headers, body = get('/low-level-forward', app)
|
89
89
|
status .should.eq 210
|
90
|
-
headers['
|
90
|
+
headers['x-downstream'].should.eq 'true'
|
91
91
|
body .should.eq ['Hello from downstream']
|
92
92
|
end
|
93
93
|
|
@@ -96,8 +96,8 @@ describe 'Sinatra base_test.rb' do
|
|
96
96
|
get('/explicit-forward', Rack::ContentLength.new(app))
|
97
97
|
|
98
98
|
status .should.eq 210
|
99
|
-
headers['
|
100
|
-
headers['
|
99
|
+
headers['x-downstream'] .should.eq 'true'
|
100
|
+
headers['content-length'].should.eq '28'
|
101
101
|
body.to_a .should.eq ['Hello after explicit forward']
|
102
102
|
end
|
103
103
|
end
|
@@ -70,7 +70,7 @@ describe 'Sinatra routing_test.rb' do
|
|
70
70
|
app = Class.new{
|
71
71
|
include Jellyfish
|
72
72
|
get{
|
73
|
-
self.headers '
|
73
|
+
self.headers 'content-type' => 'text/plain'
|
74
74
|
status, headers, body = jellyfish.app.call(env)
|
75
75
|
self.status status
|
76
76
|
self.body body
|
@@ -79,7 +79,7 @@ describe 'Sinatra routing_test.rb' do
|
|
79
79
|
}.new(Class.new{
|
80
80
|
include Jellyfish
|
81
81
|
handle Jellyfish::NotFound do
|
82
|
-
headers_merge '
|
82
|
+
headers_merge 'content-type' => 'text/html'
|
83
83
|
status 404
|
84
84
|
'<h1>Not Found</h1>'
|
85
85
|
end
|
@@ -87,7 +87,7 @@ describe 'Sinatra routing_test.rb' do
|
|
87
87
|
|
88
88
|
status, headers, body = get('/foo', app)
|
89
89
|
status .should.eq 404
|
90
|
-
headers['
|
90
|
+
headers['content-type'].should.eq 'text/html'
|
91
91
|
body .should.eq ['<h1>Not Found</h1>']
|
92
92
|
end
|
93
93
|
|
data/test/test_from_readme.rb
CHANGED
@@ -30,7 +30,7 @@ describe 'from README.md' do
|
|
30
30
|
sock = nil
|
31
31
|
status, headers, body = File.open(File::NULL) do |input|
|
32
32
|
app.call(
|
33
|
-
'
|
33
|
+
'SERVER_PROTOCOL'=> 'HTTP/1.1',
|
34
34
|
'REQUEST_METHOD' => method,
|
35
35
|
'HTTP_HOST' => host,
|
36
36
|
'PATH_INFO' => pinfo,
|
data/test/test_log.rb
CHANGED
@@ -22,6 +22,7 @@ describe Jellyfish do
|
|
22
22
|
|
23
23
|
def mock_log
|
24
24
|
log = []
|
25
|
+
log.singleton_class.send(:public, :puts)
|
25
26
|
mock(log).puts(is_a(String)){ |msg| log << msg }
|
26
27
|
log
|
27
28
|
end
|
@@ -35,6 +36,6 @@ describe Jellyfish do
|
|
35
36
|
would "log_error to env['rack.errors']" do
|
36
37
|
log = mock_log
|
37
38
|
get('/log_error', app, 'rack.errors' => log)
|
38
|
-
log.should.eq ['[Name] #<RuntimeError: RuntimeError> ["backtrace"]']
|
39
|
+
log.should.eq ['[Name] #<RuntimeError: RuntimeError> for /log_error ["backtrace"]']
|
39
40
|
end
|
40
41
|
end
|
data/test/test_rewrite.rb
CHANGED
@@ -41,4 +41,18 @@ describe Jellyfish::Rewrite do
|
|
41
41
|
expect(call(app, '/top/from/inner')).eq '/top!/to/inner'
|
42
42
|
expect(call(app, '/top/from/outer')).eq '/top!/to/outer'
|
43
43
|
end
|
44
|
+
|
45
|
+
would 'map to with host and handle SCRIPT_NAME properly' do
|
46
|
+
app = Jellyfish::Builder.app do
|
47
|
+
map '/path', to: '/path', host: 'host' do
|
48
|
+
run lambda{ |env|
|
49
|
+
[200, {},
|
50
|
+
["#{env['HTTP_HOST']} #{env['SCRIPT_NAME']} #{env['PATH_INFO']}"]]
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
expect(get('/path', app, 'HTTP_HOST' => 'host').dig(-1, -1)).
|
56
|
+
eq 'host /path'
|
57
|
+
end
|
44
58
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jellyfish
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lin Jen-Shin (godfat)
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |-
|
14
14
|
Pico web framework for building API-centric web applications.
|
@@ -24,8 +24,8 @@ extensions: []
|
|
24
24
|
extra_rdoc_files: []
|
25
25
|
files:
|
26
26
|
- ".gitignore"
|
27
|
+
- ".gitlab-ci.yml"
|
27
28
|
- ".gitmodules"
|
28
|
-
- ".travis.yml"
|
29
29
|
- CHANGES.md
|
30
30
|
- Gemfile
|
31
31
|
- LICENSE
|
@@ -69,7 +69,7 @@ homepage: https://github.com/godfat/jellyfish
|
|
69
69
|
licenses:
|
70
70
|
- Apache-2.0
|
71
71
|
metadata: {}
|
72
|
-
post_install_message:
|
72
|
+
post_install_message:
|
73
73
|
rdoc_options: []
|
74
74
|
require_paths:
|
75
75
|
- lib
|
@@ -84,9 +84,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
84
|
- !ruby/object:Gem::Version
|
85
85
|
version: '0'
|
86
86
|
requirements: []
|
87
|
-
|
88
|
-
|
89
|
-
signing_key:
|
87
|
+
rubygems_version: 3.4.3
|
88
|
+
signing_key:
|
90
89
|
specification_version: 4
|
91
90
|
summary: Pico web framework for building API-centric web applications.
|
92
91
|
test_files:
|
data/.travis.yml
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
sudo: false
|
2
|
-
language: ruby
|
3
|
-
|
4
|
-
install: 'gem install bundler; bundle install --retry=3'
|
5
|
-
script: 'ruby -vr bundler/setup -S rake test'
|
6
|
-
|
7
|
-
matrix:
|
8
|
-
include:
|
9
|
-
- rvm: 2.3
|
10
|
-
- rvm: 2.4
|
11
|
-
- rvm: 2.5
|
12
|
-
- rvm: ruby-head
|
13
|
-
- rvm: jruby
|
14
|
-
env: JRUBY_OPTS=--debug
|
15
|
-
- rvm: rbx
|
16
|
-
|
17
|
-
allow_failures:
|
18
|
-
- rvm: rbx
|