jellyfish 0.6.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 30753a754648b5b6d9a72d9165c763b3e4db9383
4
+ data.tar.gz: dc78ee33ce6341c19ff571bb78ab2485ef5f2fbd
5
+ SHA512:
6
+ metadata.gz: aa1d7ff64073a23ffb0b8d4d218e5e2f3ec898c102ad2ee7786c2af062792be705b2941ca98f7fc3e59b095ec88945b3788b065eb22b48e00eae041be930843e
7
+ data.tar.gz: 1f33f9aa6f449b034e81c1fb33e30e91c91a580e1310230e487649606add2afeaddf13fa10ea9a9daac1dc878797a390d6211e7486315ff9ee19b34012acb225
data/.gitignore CHANGED
@@ -1,3 +1,2 @@
1
1
  pkg
2
2
  *.rbc
3
- sinatra
data/.travis.yml CHANGED
@@ -6,5 +6,6 @@ env:
6
6
 
7
7
  rvm:
8
8
  - 1.9.3
9
+ - 2.0.0
9
10
  - rbx-head
10
11
  - jruby-head
data/CHANGES.md CHANGED
@@ -1,5 +1,76 @@
1
1
  # CHANGES
2
2
 
3
+ ## Jellyfish 0.8.0
4
+
5
+ ### Incompatible changes
6
+
7
+ * Now there's no longer Jellyfish#controller but Jellyfish.controller,
8
+ as there's no much point for making the controller per-instance.
9
+ You do this to override the controller method instead:
10
+
11
+ ``` ruby
12
+ class MyApp
13
+ include Jellyfish
14
+ def self.controller
15
+ MyController
16
+ end
17
+ class MyController < Jellyfish::Controller
18
+ def hi
19
+ 'hi'
20
+ end
21
+ end
22
+ get{ hi }
23
+ end
24
+ ```
25
+
26
+ * You can also change the controller by assigning it. The same as above:
27
+
28
+ ``` ruby
29
+ class MyApp
30
+ include Jellyfish
31
+ class MyController < Jellyfish::Controller
32
+ def hi
33
+ 'hi'
34
+ end
35
+ end
36
+ controller MyController
37
+ get{ hi }
38
+ end
39
+ ```
40
+
41
+ ### Enhancements for Jellyfish core
42
+
43
+ * Introduced Jellyfish.controller_include which makes it easy to pick
44
+ modules to be included in built-in controller.
45
+ * Introduced Controller#halt as a short hand for `throw :halt`
46
+ * Now default route is `//`. Using `get{ 'Hello, World!' }` is effectively
47
+ the same as `get(//){ 'Hello, World!' }`
48
+ * Now inheritance works.
49
+ * Now it raises TypeError if passing a route doesn't respond to :match.
50
+ * Now Jellyfish would find the most suitable error handler to handle
51
+ errors, i.e. It would find the error handler which would handle the
52
+ nearest exception class in the ancestors chain. Previously it would
53
+ only find the first one which matches, ignoring the rest. It would
54
+ also cache the result upon a lookup.
55
+
56
+ ### Enhancements for Jellyfish extension
57
+
58
+ * Added `Jellyfish::ChunkedBody` which is similar to `Sinatra::Stream`.
59
+
60
+ * Added `Jellyfish::MultiAction` which gives you some kind of ability to do
61
+ before or after filters. See README.md for usage.
62
+
63
+ * Added `Jellyfish::NormalizedParams` which gives you some kind of Sinatra
64
+ flavoured params.
65
+
66
+ * Added `Jellyfish::NormalizedPath` which would unescape incoming PATH_INFO
67
+ so you could match '/f%C3%B6%C3%B6' with '/föö'.
68
+
69
+ ### Enhancements for Jellyfish::Sinatra
70
+
71
+ * Now `Jellyfish::Sinatra` includes `Jellyfish::MultiAction`,
72
+ `Jellyfish::NormalizedParams`, and `Jellyfish::NormalizedPath`.
73
+
3
74
  ## Jellyfish 0.6.0 -- 2012-11-02
4
75
 
5
76
  ### Enhancements for Jellyfish core
data/README.md CHANGED
@@ -13,7 +13,7 @@ by Lin Jen-Shin ([godfat](http://godfat.org))
13
13
  ## DESCRIPTION:
14
14
 
15
15
  Pico web framework for building API-centric web applications.
16
- For Rack applications or Rack middlewares. Under 200 lines of code.
16
+ For Rack applications or Rack middlewares. Around 200 lines of code.
17
17
 
18
18
  ## DESIGN:
19
19
 
@@ -23,18 +23,21 @@ For Rack applications or Rack middlewares. Under 200 lines of code.
23
23
  * Embrace simplicity over convenience
24
24
  * Don't make things complicated only for _some_ convenience, but
25
25
  _great_ convenience, or simply stay simple for simplicity.
26
+ * More features are added as extensions
26
27
 
27
28
  ## FEATURES:
28
29
 
29
30
  * Minimal
30
31
  * Simple
31
- * No templates
32
+ * Modular
33
+ * No templates (You could use [tilt](https://github.com/rtomayko/tilt))
32
34
  * No ORM
33
35
  * No `dup` in `call`
34
36
  * Regular expression routes, e.g. `get %r{^/(?<id>\d+)$}`
35
37
  * String routes, e.g. `get '/'`
36
38
  * Custom routes, e.g. `get Matcher.new`
37
- * Build for either Rack applications or Rack middlewares
39
+ * Build for either Rack applications or Rack middleware
40
+ * Include extensions for more features (There's a Sinatra extension)
38
41
 
39
42
  ## WHY?
40
43
 
@@ -65,6 +68,13 @@ use Rack::ContentType, 'text/plain'
65
68
  run Tank.new
66
69
  ```
67
70
 
71
+ <!---
72
+ GET /
73
+ [200,
74
+ {'Content-Length' => '12', 'Content-Type' => 'text/plain'},
75
+ ["Jelly Kelly\n"]]
76
+ -->
77
+
68
78
  ### Regular expression routes
69
79
 
70
80
  ``` ruby
@@ -80,6 +90,13 @@ use Rack::ContentType, 'text/plain'
80
90
  run Tank.new
81
91
  ```
82
92
 
93
+ <!---
94
+ GET /123
95
+ [200,
96
+ {'Content-Length' => '11', 'Content-Type' => 'text/plain'},
97
+ ["Jelly #123\n"]]
98
+ -->
99
+
83
100
  ### Custom matcher routes
84
101
 
85
102
  ``` ruby
@@ -100,6 +117,13 @@ use Rack::ContentType, 'text/plain'
100
117
  run Tank.new
101
118
  ```
102
119
 
120
+ <!---
121
+ GET /hctam
122
+ [200,
123
+ {'Content-Length' => '5', 'Content-Type' => 'text/plain'},
124
+ ["true\n"]]
125
+ -->
126
+
103
127
  ### Different HTTP status and custom headers
104
128
 
105
129
  ``` ruby
@@ -119,6 +143,14 @@ use Rack::ContentType, 'text/plain'
119
143
  run Tank.new
120
144
  ```
121
145
 
146
+ <!---
147
+ POST /
148
+ [201,
149
+ {'Content-Length' => '18', 'Content-Type' => 'text/plain',
150
+ 'X-Jellyfish-Life' => '100', 'X-Jellyfish-Mana' => '200'},
151
+ ["Jellyfish 100/200\n"]]
152
+ -->
153
+
122
154
  ### Redirect helper
123
155
 
124
156
  ``` ruby
@@ -134,6 +166,17 @@ use Rack::ContentType, 'text/plain'
134
166
  run Tank.new
135
167
  ```
136
168
 
169
+ <!---
170
+ GET /lookup
171
+ body = File.read("#{File.dirname(
172
+ File.expand_path(__FILE__))}/../lib/jellyfish/public/302.html").
173
+ gsub('VAR_URL', ':///')
174
+ [302,
175
+ {'Content-Length' => body.bytesize.to_s, 'Content-Type' => 'text/html',
176
+ 'Location' => ':///'},
177
+ [body]]
178
+ -->
179
+
137
180
  ### Crash-proof
138
181
 
139
182
  ``` ruby
@@ -149,6 +192,15 @@ use Rack::ContentType, 'text/plain'
149
192
  run Tank.new
150
193
  ```
151
194
 
195
+ <!---
196
+ GET /crash
197
+ body = File.read("#{File.dirname(
198
+ File.expand_path(__FILE__))}/../lib/jellyfish/public/500.html")
199
+ [500,
200
+ {'Content-Length' => body.bytesize.to_s, 'Content-Type' => 'text/html'},
201
+ [body]]
202
+ -->
203
+
152
204
  ### Custom error handler
153
205
 
154
206
  ``` ruby
@@ -168,7 +220,74 @@ use Rack::ContentType, 'text/plain'
168
220
  run Tank.new
169
221
  ```
170
222
 
171
- ### Custom controller
223
+ <!---
224
+ GET /yell
225
+ body = case RUBY_ENGINE
226
+ when 'jruby'
227
+ "No one hears you: (eval):9:in `Tank'\n"
228
+ when 'rbx'
229
+ "No one hears you: kernel/delta/kernel.rb:81:in `yell (method_missing)'\n"
230
+ else
231
+ "No one hears you: (eval):9:in `block in <class:Tank>'\n"
232
+ end
233
+ [403,
234
+ {'Content-Length' => body.bytesize.to_s, 'Content-Type' => 'text/plain'},
235
+ [body]]
236
+ -->
237
+
238
+ ### Access Rack::Request and params
239
+
240
+ ``` ruby
241
+ require 'jellyfish'
242
+ class Tank
243
+ include Jellyfish
244
+ get '/report' do
245
+ "Your name is #{request.params['name']}\n"
246
+ end
247
+ end
248
+ use Rack::ContentLength
249
+ use Rack::ContentType, 'text/plain'
250
+ run Tank.new
251
+ ```
252
+
253
+ <!---
254
+ GET /report?name=godfat
255
+ [200,
256
+ {'Content-Length' => '20', 'Content-Type' => 'text/plain'},
257
+ ["Your name is godfat\n"]]
258
+ -->
259
+
260
+ ### Re-dispatch the request with modified env
261
+
262
+ ``` ruby
263
+ require 'jellyfish'
264
+ class Tank
265
+ include Jellyfish
266
+ get '/report' do
267
+ status, headers, body = jellyfish.call(env.merge('PATH_INFO' => '/info'))
268
+ self.status status
269
+ self.headers headers
270
+ self.body body
271
+ end
272
+ get('/info'){ "OK\n" }
273
+ end
274
+ use Rack::ContentLength
275
+ use Rack::ContentType, 'text/plain'
276
+ run Tank.new
277
+ ```
278
+
279
+ <!---
280
+ GET /report
281
+ [200,
282
+ {'Content-Length' => '3', 'Content-Type' => 'text/plain'},
283
+ ["OK\n"]]
284
+ -->
285
+
286
+ ### Include custom helper in built-in controller
287
+
288
+ Basically it's the same as defining a custom controller and then
289
+ include the helper. This is merely a short hand. See next section
290
+ for defining a custom controller.
172
291
 
173
292
  ``` ruby
174
293
  require 'jellyfish'
@@ -178,33 +297,92 @@ class Heater
178
297
  temperature
179
298
  end
180
299
 
181
- def controller; Controller; end
182
- class Controller < Jellyfish::Controller
300
+ module Helper
183
301
  def temperature
184
302
  "30\u{2103}\n"
185
303
  end
186
304
  end
305
+ controller_include Helper
187
306
  end
188
307
  use Rack::ContentLength
189
308
  use Rack::ContentType, 'text/plain'
190
309
  run Heater.new
191
310
  ```
192
311
 
193
- ### Sinatra flavored controller
312
+ <!---
313
+ GET /status
314
+ [200,
315
+ {'Content-Length' => '6', 'Content-Type' => 'text/plain'},
316
+ ["30\u{2103}\n"]]
317
+ -->
318
+
319
+ ### Define custom controller manually
320
+
321
+ This is effectively the same as defining a helper module as above and
322
+ include it, but more flexible and extensible.
323
+
324
+ ``` ruby
325
+ require 'jellyfish'
326
+ class Heater
327
+ include Jellyfish
328
+ get '/status' do
329
+ temperature
330
+ end
331
+
332
+ class Controller < Jellyfish::Controller
333
+ def temperature
334
+ "30\u{2103}\n"
335
+ end
336
+ end
337
+ controller Controller
338
+ end
339
+ use Rack::ContentLength
340
+ use Rack::ContentType, 'text/plain'
341
+ run Heater.new
342
+ ```
194
343
 
195
- Currently support:
344
+ <!---
345
+ GET /status
346
+ [200,
347
+ {'Content-Length' => '6', 'Content-Type' => 'text/plain'},
348
+ ["30\u{2103}\n"]]
349
+ -->
196
350
 
197
- * Indifferent params
198
- * Force params encoding to Encoding.default_external
351
+ ### Extension: MultiActions (Filters)
199
352
 
200
353
  ``` ruby
201
354
  require 'jellyfish'
202
355
  class Tank
203
356
  include Jellyfish
204
- class MyController < Jellyfish::Controller
205
- include Jellyfish::Sinatra
357
+ controller_include Jellyfish::MultiActions
358
+
359
+ get do # wildcard before filter
360
+ @state = 'jumps'
206
361
  end
207
- def controller; MyController; end
362
+ get do
363
+ "Jelly #{@state}.\n"
364
+ end
365
+ end
366
+ use Rack::ContentLength
367
+ use Rack::ContentType, 'text/plain'
368
+ run Tank.new
369
+ ```
370
+
371
+ <!---
372
+ GET /123
373
+ [200,
374
+ {'Content-Length' => '13', 'Content-Type' => 'text/plain'},
375
+ ["Jelly jumps.\n"]]
376
+ -->
377
+
378
+ ### Extension: NormalizedParams (with force_encoding)
379
+
380
+ ``` ruby
381
+ require 'jellyfish'
382
+ class Tank
383
+ include Jellyfish
384
+ controller_include Jellyfish::NormalizedParams
385
+
208
386
  get %r{^/(?<id>\d+)$} do
209
387
  "Jelly ##{params[:id]}\n"
210
388
  end
@@ -214,16 +392,78 @@ use Rack::ContentType, 'text/plain'
214
392
  run Tank.new
215
393
  ```
216
394
 
217
- ### Using NewRelic?
395
+ <!---
396
+ GET /123
397
+ [200,
398
+ {'Content-Length' => '11', 'Content-Type' => 'text/plain'},
399
+ ["Jelly #123\n"]]
400
+ -->
401
+
402
+ ### Extension: NormalizedPath (with unescaping)
218
403
 
219
404
  ``` ruby
220
405
  require 'jellyfish'
221
406
  class Tank
222
407
  include Jellyfish
223
- class MyController < Jellyfish::Controller
224
- include Jellyfish::NewRelic
408
+ controller_include Jellyfish::NormalizedPath
409
+
410
+ get "/\u{56e7}" do
411
+ "#{env['PATH_INFO']}=#{path_info}\n"
412
+ end
413
+ end
414
+ use Rack::ContentLength
415
+ use Rack::ContentType, 'text/plain'
416
+ run Tank.new
417
+ ```
418
+
419
+ <!---
420
+ GET /%E5%9B%A7
421
+ [200,
422
+ {'Content-Length' => '16', 'Content-Type' => 'text/plain'},
423
+ ["/%E5%9B%A7=/\u{56e7}\n"]]
424
+ -->
425
+
426
+ ### Extension: Sinatra flavoured controller
427
+
428
+ It's an extension collection contains:
429
+
430
+ * MultiActions
431
+ * NormalizedParams
432
+ * NormalizedPath
433
+
434
+ ``` ruby
435
+ require 'jellyfish'
436
+ class Tank
437
+ include Jellyfish
438
+ controller_include Jellyfish::Sinatra
439
+
440
+ get do # wildcard before filter
441
+ @state = 'jumps'
442
+ end
443
+ get %r{^/(?<id>\d+)$} do
444
+ "Jelly ##{params[:id]} #{@state}.\n"
225
445
  end
226
- def controller; MyController; end
446
+ end
447
+ use Rack::ContentLength
448
+ use Rack::ContentType, 'text/plain'
449
+ run Tank.new
450
+ ```
451
+
452
+ <!---
453
+ GET /123
454
+ [200,
455
+ {'Content-Length' => '18', 'Content-Type' => 'text/plain'},
456
+ ["Jelly #123 jumps.\n"]]
457
+ -->
458
+
459
+ ### Extension: NewRelic
460
+
461
+ ``` ruby
462
+ require 'jellyfish'
463
+ class Tank
464
+ include Jellyfish
465
+ controller_include Jellyfish::NewRelic
466
+
227
467
  get '/' do
228
468
  "OK\n"
229
469
  end
@@ -237,6 +477,48 @@ run Tank.new
237
477
  NewRelic::Agent.manual_start(:developer_mode => true)
238
478
  ```
239
479
 
480
+ <!---
481
+ GET /
482
+ [200,
483
+ {'Content-Length' => '3', 'Content-Type' => 'text/plain'},
484
+ ["OK\n"]]
485
+ -->
486
+
487
+ ### Extension: Using multiple extensions with custom controller
488
+
489
+ This is effectively the same as using Jellyfish::Sinatra extension.
490
+ Note that the controller should be assigned lastly in order to include
491
+ modules remembered in controller_include.
492
+
493
+ ``` ruby
494
+ require 'jellyfish'
495
+ class Tank
496
+ include Jellyfish
497
+ class MyController < Jellyfish::Controller
498
+ include Jellyfish::MultiActions
499
+ end
500
+ controller_include NormalizedParams, NormalizedPath
501
+ controller MyController
502
+
503
+ get do # wildcard before filter
504
+ @state = 'jumps'
505
+ end
506
+ get %r{^/(?<id>\d+)$} do
507
+ "Jelly ##{params[:id]} #{@state}.\n"
508
+ end
509
+ end
510
+ use Rack::ContentLength
511
+ use Rack::ContentType, 'text/plain'
512
+ run Tank.new
513
+ ```
514
+
515
+ <!---
516
+ GET /123
517
+ [200,
518
+ {'Content-Length' => '18', 'Content-Type' => 'text/plain'},
519
+ ["Jelly #123 jumps.\n"]]
520
+ -->
521
+
240
522
  ### Jellyfish as a middleware
241
523
 
242
524
  ``` ruby
@@ -261,6 +543,146 @@ use Heater
261
543
  run Tank.new
262
544
  ```
263
545
 
546
+ <!---
547
+ GET /
548
+ [200,
549
+ {'Content-Length' => '12', 'Content-Type' => 'text/plain'},
550
+ ["Jelly Kelly\n"]]
551
+ -->
552
+
553
+ ### Modify response as a middleware
554
+
555
+ ``` ruby
556
+ require 'jellyfish'
557
+ class Heater
558
+ include Jellyfish
559
+ get '/status' do
560
+ status, headers, body = jellyfish.app.call(env)
561
+ self.status status
562
+ self.headers headers
563
+ self.body body
564
+ headers_merge('X-Temperature' => "30\u{2103}")
565
+ end
566
+ end
567
+
568
+ class Tank
569
+ include Jellyfish
570
+ get '/status' do
571
+ "See header X-Temperature\n"
572
+ end
573
+ end
574
+
575
+ use Rack::ContentLength
576
+ use Rack::ContentType, 'text/plain'
577
+ use Heater
578
+ run Tank.new
579
+ ```
580
+
581
+ <!---
582
+ GET /status
583
+ [200,
584
+ {'Content-Length' => '25', 'Content-Type' => 'text/plain',
585
+ 'X-Temperature' => "30\u{2103}"},
586
+ ["See header X-Temperature\n"]]
587
+ -->
588
+
589
+ ### Default headers as a middleware
590
+
591
+ ``` ruby
592
+ require 'jellyfish'
593
+ class Heater
594
+ include Jellyfish
595
+ get '/status' do
596
+ status, headers, body = jellyfish.app.call(env)
597
+ self.status status
598
+ self.headers({'X-Temperature' => "30\u{2103}"}.merge(headers))
599
+ self.body body
600
+ end
601
+ end
602
+
603
+ class Tank
604
+ include Jellyfish
605
+ get '/status' do
606
+ headers_merge('X-Temperature' => "35\u{2103}")
607
+ "\n"
608
+ end
609
+ end
610
+
611
+ use Rack::ContentLength
612
+ use Rack::ContentType, 'text/plain'
613
+ use Heater
614
+ run Tank.new
615
+ ```
616
+
617
+ <!---
618
+ GET /status
619
+ [200,
620
+ {'Content-Length' => '1', 'Content-Type' => 'text/plain',
621
+ 'X-Temperature' => "35\u{2103}"},
622
+ ["\n"]]
623
+ -->
624
+
625
+ ### Simple before action as a middleware
626
+
627
+ ``` ruby
628
+ require 'jellyfish'
629
+ class Heater
630
+ include Jellyfish
631
+ get '/status' do
632
+ env['temperature'] = 30
633
+ forward
634
+ end
635
+ end
636
+
637
+ class Tank
638
+ include Jellyfish
639
+ get '/status' do
640
+ "#{env['temperature']}\u{2103}\n"
641
+ end
642
+ end
643
+
644
+ use Rack::ContentLength
645
+ use Rack::ContentType, 'text/plain'
646
+ use Heater
647
+ run Tank.new
648
+ ```
649
+
650
+ <!---
651
+ GET /status
652
+ [200,
653
+ {'Content-Length' => '6', 'Content-Type' => 'text/plain'},
654
+ ["30\u{2103}\n"]]
655
+ -->
656
+
657
+ ### Halt in before action
658
+
659
+ ``` ruby
660
+ require 'jellyfish'
661
+ class Tank
662
+ include Jellyfish
663
+ controller_include Jellyfish::MultiActions
664
+
665
+ get do # wildcard before filter
666
+ body "Done!\n"
667
+ halt
668
+ end
669
+ get '/' do
670
+ "Never reach.\n"
671
+ end
672
+ end
673
+
674
+ use Rack::ContentLength
675
+ use Rack::ContentType, 'text/plain'
676
+ run Tank.new
677
+ ```
678
+
679
+ <!---
680
+ GET /status
681
+ [200,
682
+ {'Content-Length' => '6', 'Content-Type' => 'text/plain'},
683
+ ["Done!\n"]]
684
+ -->
685
+
264
686
  ### One huge tank
265
687
 
266
688
  ``` ruby
@@ -289,6 +711,13 @@ end
289
711
  run HugeTank
290
712
  ```
291
713
 
714
+ <!---
715
+ GET /status
716
+ [200,
717
+ {'Content-Length' => '6', 'Content-Type' => 'text/plain'},
718
+ ["30\u{2103}\n"]]
719
+ -->
720
+
292
721
  ### Raise exceptions
293
722
 
294
723
  ``` ruby
@@ -315,17 +744,48 @@ use Protector
315
744
  run Tank.new
316
745
  ```
317
746
 
318
- ### Chunked transfer encoding (streaming)
747
+ <!---
748
+ GET /
749
+ [200,
750
+ {'Content-Length' => '29', 'Content-Type' => 'text/plain'},
751
+ ["Protected: Oops, tank broken\n"]]
752
+ -->
753
+
754
+ ### Chunked transfer encoding (streaming) with Jellyfish::ChunkedBody
319
755
 
320
756
  You would need a proper server setup.
321
757
  Here's an example with Rainbows and fibers:
322
758
 
759
+ ``` ruby
760
+ class Tank
761
+ include Jellyfish
762
+ get '/chunked' do
763
+ ChunkedBody.new{ |out|
764
+ (0..4).each{ |i| out.call("#{i}\n") }
765
+ }
766
+ end
767
+ end
768
+ use Rack::Chunked
769
+ use Rack::ContentType, 'text/plain'
770
+ run Tank.new
771
+ ```
772
+
773
+ <!---
774
+ GET /chunked
775
+ [200,
776
+ {'Content-Type' => 'text/plain', 'Transfer-Encoding' => 'chunked'},
777
+ ["2\r\n0\n\r\n", "2\r\n1\n\r\n", "2\r\n2\n\r\n",
778
+ "2\r\n3\n\r\n", "2\r\n4\n\r\n", "0\r\n\r\n"]]
779
+ -->
780
+
781
+ ### Chunked transfer encoding (streaming) with custom body
782
+
323
783
  ``` ruby
324
784
  class Tank
325
785
  include Jellyfish
326
786
  class Body
327
787
  def each
328
- (0..4).each{ |i| yield "#{i}\n"; Rainbows.sleep(0.1) }
788
+ (0..4).each{ |i| yield "#{i}\n" }
329
789
  end
330
790
  end
331
791
  get '/chunked' do
@@ -337,6 +797,14 @@ use Rack::ContentType, 'text/plain'
337
797
  run Tank.new
338
798
  ```
339
799
 
800
+ <!---
801
+ GET /chunked
802
+ [200,
803
+ {'Content-Type' => 'text/plain', 'Transfer-Encoding' => 'chunked'},
804
+ ["2\r\n0\n\r\n", "2\r\n1\n\r\n", "2\r\n2\n\r\n",
805
+ "2\r\n3\n\r\n", "2\r\n4\n\r\n", "0\r\n\r\n"]]
806
+ -->
807
+
340
808
  ## CONTRIBUTORS:
341
809
 
342
810
  * Lin Jen-Shin (@godfat)
@@ -345,7 +813,7 @@ run Tank.new
345
813
 
346
814
  Apache License 2.0
347
815
 
348
- Copyright (c) 2012, Lin Jen-Shin (godfat)
816
+ Copyright (c) 2012-2013, Lin Jen-Shin (godfat)
349
817
 
350
818
  Licensed under the Apache License, Version 2.0 (the "License");
351
819
  you may not use this file except in compliance with the License.