jellyfish 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed0f1e851242bf9537578f804560b70c4941fd99
4
- data.tar.gz: 0d90b769bdb5fba1328d8734b5f6ac307578136c
3
+ metadata.gz: f177b766380820557e01f05b9da4efacc4895984
4
+ data.tar.gz: 800a25a7fa325e5c0c40c7604b94cbddb32c43a6
5
5
  SHA512:
6
- metadata.gz: a2168d6a1fd9beeb8486065288be32d59347d2e52d5e503efa5898e5ed6666603e8061d16fe269e25aaa831a59054e40bbcfe11adcb64dd7f24fc9201bc0b14d
7
- data.tar.gz: d74afc9d0425f7f88b193259785f81da48e990f4dbf2359fafd334cc99926e79384aa41b008e37546520bb48cf95d0b6315d034c87bbb25848583605fbca8ceb
6
+ metadata.gz: 288710b695398769a27f730e3a2d2d6fe921b140455a968f57515503628af9f7759506c89c9291b860e862b1eb6ca56d076b9ca01c2429d53626bc021d189904
7
+ data.tar.gz: 78edee35fbbac6dd332fc9eb9290b1dc26c27b74abd72c57166bb0d429ac6f3d441c3c88f56f014befdeb32825a47bf6d395dae04e21c624b6c52caa986aa589
@@ -3,6 +3,7 @@ language: ruby
3
3
  rvm:
4
4
  - 2.0
5
5
  - 2.1
6
+ - 2.2
6
7
  - rbx-2
7
8
  - jruby
8
9
 
data/CHANGES.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # CHANGES
2
2
 
3
+ ## Jellyfish 1.1.0 -- 2015-09-25
4
+
5
+ ### Incompatible changes
6
+
7
+ * `Jellyfish::Sinatra`, `Jellyfish::MultiActions`, and `Jellyfish::Swagger`
8
+ were extracted to
9
+ [jellyfish-contrib](https://github.com/godfat/jellyfish-contrib)
10
+
11
+ ### Other enhancements
12
+
13
+ * Added `Jellyfish::Builder` and `Jellyfish::URLMap` which is 36 times faster
14
+ than `Rack::Builder` and `Rack::URLMap` given an application with
15
+ 1000 routes.
16
+
3
17
  ## Jellyfish 1.0.2 -- 2014-12-09
4
18
 
5
19
  * `Jellyfish::NewRelic` is fixed. Thanks Jason R. Clark (@jasonrclark)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Jellyfish [![Build Status](https://secure.travis-ci.org/godfat/jellyfish.png?branch=master)](http://travis-ci.org/godfat/jellyfish) [![Coverage Status](https://coveralls.io/repos/godfat/jellyfish/badge.png)](https://coveralls.io/r/godfat/jellyfish)
1
+ # Jellyfish [![Build Status](https://secure.travis-ci.org/godfat/jellyfish.png?branch=master)](http://travis-ci.org/godfat/jellyfish) [![Coverage Status](https://coveralls.io/repos/godfat/jellyfish/badge.png)](https://coveralls.io/r/godfat/jellyfish) [![Join the chat at https://gitter.im/godfat/jellyfish](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/godfat/jellyfish)
2
2
 
3
3
  by Lin Jen-Shin ([godfat](http://godfat.org))
4
4
 
@@ -13,7 +13,11 @@ 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. Around 250 lines of code.
16
+ For Rack applications or Rack middleware. Around 250 lines of code.
17
+
18
+ Check [jellyfish-contrib][] for extra extensions.
19
+
20
+ [jellyfish-contrib]: https://github.com/godfat/jellyfish-contrib
17
21
 
18
22
  ## DESIGN:
19
23
 
@@ -43,7 +47,7 @@ For Rack applications or Rack middlewares. Around 250 lines of code.
43
47
  * String routes, e.g. `get '/'`
44
48
  * Custom routes, e.g. `get Matcher.new`
45
49
  * Build for either Rack applications or Rack middleware
46
- * Include extensions for more features (There's a Sinatra extension)
50
+ * Include extensions for more features (checkout [jellyfish-contrib][])
47
51
 
48
52
  ## WHY?
49
53
 
@@ -59,9 +63,7 @@ Because Sinatra is too complex and inconsistent for me.
59
63
 
60
64
  ## SYNOPSIS:
61
65
 
62
- You could also take a look at [config.ru](config.ru) as an example, which
63
- also uses [Swagger](https://helloreverb.com/developers/swagger) to generate
64
- API documentation.
66
+ You could also take a look at [config.ru](config.ru) as an example.
65
67
 
66
68
  ### Hello Jellyfish, your lovely config.ru
67
69
 
@@ -439,33 +441,148 @@ GET /123
439
441
  ["Jelly jumps.\n"]]
440
442
  -->
441
443
 
442
- ### Extension: MultiActions (Filters)
444
+ ### Extension: Jellyfish::Builder, a faster Rack::Builder and Rack::URLMap
445
+
446
+ Default `Rack::Builder` and `Rack::URLMap` is routing via linear search,
447
+ which could be very slow with a large number of routes. We could use
448
+ `Jellyfish::Builder` in this case because it would compile the routes
449
+ into a regular expression, it would be matching much faster than
450
+ linear search.
451
+
452
+ Note that `Jellyfish::Builder` is not a complete compatible implementation.
453
+ The followings are intentional:
454
+
455
+ * There's no `Jellyfish::Builder.call` because it doesn't make sense in my
456
+ opinion. Always use `Jellyfish::Builder.app` instead.
457
+
458
+ * There's no `Jellyfish::Builder.parse_file` and
459
+ `Jellyfish::Builder.new_from_string` because Rack servers are not
460
+ going to use `Jellyfish::Builder` to parse `config.ru` at this point.
461
+ We could provide this if there's a need.
462
+
463
+ * `Jellyfish::URLMap` does not modify `env`, and it would call the app with
464
+ another instance of Hash. Mutating data is a bad idea.
465
+
466
+ * `Jellyfish::URLMap` does not try to match on host because I am not sure
467
+ if there's anyone would need this feature?
468
+
469
+ * All other tests passed the same test suites for `Rack::Builder`.
443
470
 
444
471
  ``` ruby
445
472
  require 'jellyfish'
446
- class Tank
447
- include Jellyfish
448
- controller_include Jellyfish::MultiActions
449
473
 
450
- get do # wildcard before filter
451
- @state = 'jumps'
474
+ run Jellyfish::Builder.app{
475
+ map '/a' do; run lambda{ |_| [200, {}, ["a\n"] ] }; end
476
+ map '/b' do; run lambda{ |_| [200, {}, ["b\n"] ] }; end
477
+ map '/c' do; run lambda{ |_| [200, {}, ["c\n"] ] }; end
478
+ map '/d' do; run lambda{ |_| [200, {}, ["d\n"] ] }; end
479
+ map '/e' do
480
+ map '/f' do; run lambda{ |_| [200, {}, ["e/f\n"]] }; end
481
+ map '/g' do; run lambda{ |_| [200, {}, ["e/g\n"]] }; end
482
+ map '/h' do; run lambda{ |_| [200, {}, ["e/h\n"]] }; end
483
+ map '/i' do; run lambda{ |_| [200, {}, ["e/i\n"]] }; end
484
+ map '/' do; run lambda{ |_| [200, {}, ["e\n"]] }; end
452
485
  end
453
- get do
454
- "Jelly #{@state}.\n"
486
+ map '/j' do; run lambda{ |_| [200, {}, ["j\n"] ] }; end
487
+ map '/k' do; run lambda{ |_| [200, {}, ["k\n"] ] }; end
488
+ map '/l' do; run lambda{ |_| [200, {}, ["l\n"] ] }; end
489
+ map '/m' do
490
+ map '/g' do; run lambda{ |_| [200, {}, ["m/g\n"]] }; end
491
+ run lambda{ |_| [200, {}, ["m\n"] ] }
455
492
  end
456
- end
457
- use Rack::ContentLength
458
- use Rack::ContentType, 'text/plain'
459
- run Tank.new
493
+
494
+ use Rack::ContentLength
495
+ run lambda{ |_| [200, {}, ["/\n"]] }
496
+ }
460
497
  ```
461
498
 
462
499
  <!---
463
- GET /123
464
- [200,
465
- {'Content-Length' => '13', 'Content-Type' => 'text/plain'},
466
- ["Jelly jumps.\n"]]
500
+ GET /a
501
+ [200, {}, ["a\n"]]
502
+
503
+ GET /a/x
504
+ [200, {}, ["a\n"]]
505
+
506
+ GET /b
507
+ [200, {}, ["b\n"]]
508
+
509
+ GET /c
510
+ [200, {}, ["c\n"]]
511
+
512
+ GET /d
513
+ [200, {}, ["d\n"]]
514
+
515
+ GET /e/f
516
+ [200, {}, ["e/f\n"]]
517
+
518
+ GET /e/g
519
+ [200, {}, ["e/g\n"]]
520
+
521
+ GET /e/h
522
+ [200, {}, ["e/h\n"]]
523
+
524
+ GET /e/i
525
+ [200, {}, ["e/i\n"]]
526
+
527
+ GET /e/
528
+ [200, {}, ["e\n"]]
529
+
530
+ GET /e
531
+ [200, {}, ["e\n"]]
532
+
533
+ GET /e/x
534
+ [200, {}, ["e\n"]]
535
+
536
+ GET /j
537
+ [200, {}, ["j\n"]]
538
+
539
+ GET /k
540
+ [200, {}, ["k\n"]]
541
+
542
+ GET /l
543
+ [200, {}, ["l\n"]]
544
+
545
+ GET /m/g
546
+ [200, {}, ["m/g\n"]]
547
+
548
+ GET /m
549
+ [200, {}, ["m\n"]]
550
+
551
+ GET /m/
552
+ [200, {}, ["m\n"]]
553
+
554
+ GET /m/x
555
+ [200, {}, ["m\n"]]
556
+
557
+ GET /
558
+ [200, {'Content-Length' => '2'}, ["/\n"]]
559
+
560
+ GET /x
561
+ [200, {'Content-Length' => '2'}, ["/\n"]]
562
+
563
+ GET /ab
564
+ [200, {'Content-Length' => '2'}, ["/\n"]]
467
565
  -->
468
566
 
567
+ You could try a stupid benchmark yourself:
568
+
569
+ ruby -Ilib bench/bench_builder.rb
570
+
571
+ For a 1000 routes app, here's my result:
572
+
573
+ ```
574
+ Calculating -------------------------------------
575
+ Jellyfish::URLMap 5.726k i/100ms
576
+ Rack::URLMap 167.000 i/100ms
577
+ -------------------------------------------------
578
+ Jellyfish::URLMap 62.397k (± 1.2%) i/s - 314.930k
579
+ Rack::URLMap 1.702k (± 1.5%) i/s - 8.517k
580
+
581
+ Comparison:
582
+ Jellyfish::URLMap: 62397.3 i/s
583
+ Rack::URLMap: 1702.0 i/s - 36.66x slower
584
+ ```
585
+
469
586
  ### Extension: NormalizedParams (with force_encoding)
470
587
 
471
588
  ``` ruby
@@ -514,39 +631,6 @@ GET /%E5%9B%A7
514
631
  ["/%E5%9B%A7=/\u{56e7}\n"]]
515
632
  -->
516
633
 
517
- ### Extension: Sinatra flavoured controller
518
-
519
- It's an extension collection contains:
520
-
521
- * MultiActions
522
- * NormalizedParams
523
- * NormalizedPath
524
-
525
- ``` ruby
526
- require 'jellyfish'
527
- class Tank
528
- include Jellyfish
529
- controller_include Jellyfish::Sinatra
530
-
531
- get do # wildcard before filter
532
- @state = 'jumps'
533
- end
534
- get %r{^/(?<id>\d+)$} do
535
- "Jelly ##{params[:id]} #{@state}.\n"
536
- end
537
- end
538
- use Rack::ContentLength
539
- use Rack::ContentType, 'text/plain'
540
- run Tank.new
541
- ```
542
-
543
- <!---
544
- GET /123
545
- [200,
546
- {'Content-Length' => '18', 'Content-Type' => 'text/plain'},
547
- ["Jelly #123 jumps.\n"]]
548
- -->
549
-
550
634
  ### Extension: NewRelic
551
635
 
552
636
  ``` ruby
@@ -577,7 +661,6 @@ GET /
577
661
 
578
662
  ### Extension: Using multiple extensions with custom controller
579
663
 
580
- This is effectively the same as using Jellyfish::Sinatra extension.
581
664
  Note that the controller should be assigned lastly in order to include
582
665
  modules remembered in controller_include.
583
666
 
@@ -586,16 +669,13 @@ require 'jellyfish'
586
669
  class Tank
587
670
  include Jellyfish
588
671
  class MyController < Jellyfish::Controller
589
- include Jellyfish::MultiActions
672
+ include Jellyfish::WebSocket
590
673
  end
591
674
  controller_include NormalizedParams, NormalizedPath
592
675
  controller MyController
593
676
 
594
- get do # wildcard before filter
595
- @state = 'jumps'
596
- end
597
677
  get %r{^/(?<id>\d+)$} do
598
- "Jelly ##{params[:id]} #{@state}.\n"
678
+ "Jelly ##{params[:id]} jumps.\n"
599
679
  end
600
680
  end
601
681
  use Rack::ContentLength
@@ -761,35 +841,6 @@ GET /status
761
841
  ["30\u{2103}\n"]]
762
842
  -->
763
843
 
764
- ### Halt in before action
765
-
766
- ``` ruby
767
- require 'jellyfish'
768
- class Tank
769
- include Jellyfish
770
- controller_include Jellyfish::MultiActions
771
-
772
- get do # wildcard before filter
773
- body "Done!\n"
774
- halt
775
- end
776
- get '/' do
777
- "Never reach.\n"
778
- end
779
- end
780
-
781
- use Rack::ContentLength
782
- use Rack::ContentType, 'text/plain'
783
- run Tank.new
784
- ```
785
-
786
- <!---
787
- GET /status
788
- [200,
789
- {'Content-Length' => '6', 'Content-Type' => 'text/plain'},
790
- ["Done!\n"]]
791
- -->
792
-
793
844
  ### One huge tank
794
845
 
795
846
  ``` ruby
@@ -912,6 +963,57 @@ GET /chunked
912
963
  "2\r\n3\n\r\n", "2\r\n4\n\r\n", "0\r\n\r\n"]]
913
964
  -->
914
965
 
966
+ ### Server Sent Event (SSE)
967
+
968
+ ``` ruby
969
+ class Tank
970
+ include Jellyfish
971
+ class Body
972
+ def each
973
+ (0..4).each{ |i| yield "data: #{i}\n\n" }
974
+ end
975
+ end
976
+ get '/sse' do
977
+ headers_merge('Content-Type' => 'text/event-stream')
978
+ Body.new
979
+ end
980
+ end
981
+ run Tank.new
982
+ ```
983
+
984
+ <!---
985
+ GET /sse
986
+ [200,
987
+ {'Content-Type' => 'text/event-stream'},
988
+ ["data: 0\n\n", "data: 1\n\n", "data: 2\n\n", "data: 3\n\n", "data: 4\n\n"]]
989
+ -->
990
+
991
+ ### Server Sent Event (SSE) with Rack Hijacking
992
+
993
+ ``` ruby
994
+ class Tank
995
+ include Jellyfish
996
+ get '/sse' do
997
+ headers_merge(
998
+ 'Content-Type' => 'text/event-stream',
999
+ 'rack.hijack' => lambda do |sock|
1000
+ (0..4).each do |i|
1001
+ sock.write("data: #{i}\n\n")
1002
+ end
1003
+ sock.close
1004
+ end)
1005
+ end
1006
+ end
1007
+ run Tank.new
1008
+ ```
1009
+
1010
+ <!---
1011
+ GET /sse
1012
+ [200,
1013
+ {'Content-Type' => 'text/event-stream'},
1014
+ ["data: 0\n\n", "data: 1\n\n", "data: 2\n\n", "data: 3\n\n", "data: 4\n\n"]]
1015
+ -->
1016
+
915
1017
  ### Using WebSocket
916
1018
 
917
1019
  Note that this only works for Rack servers which support [hijack][].
@@ -956,36 +1058,9 @@ HTTP
956
1058
  [200, {}, ['']]
957
1059
  -->
958
1060
 
959
- ### Use Swagger to generate API documentation
960
-
961
- For a complete example, checkout [config.ru](config.ru).
962
-
963
- ``` ruby
964
- require 'jellyfish'
965
- class Tank
966
- include Jellyfish
967
- get %r{^/(?<id>\d+)$}, :notes => 'This is an API note' do |match|
968
- "Jelly ##{match[:id]}\n"
969
- end
970
- end
971
- use Rack::ContentLength
972
- use Rack::ContentType, 'text/plain'
973
- map '/swagger' do
974
- run Jellyfish::Swagger.new('', Tank)
975
- end
976
- run Tank.new
977
- ```
978
-
979
- <!---
980
- GET /swagger
981
- [200,
982
- {'Content-Type' => 'application/json; charset=utf-8',
983
- 'Content-Length' => '81'},
984
- ['{"swaggerVersion":"1.2","info":{},"apiVersion":"0.1.0","apis":[{"path":"/{id}"}]}']]
985
- -->
986
-
987
1061
  ## CONTRIBUTORS:
988
1062
 
1063
+ * Fumin (@fumin)
989
1064
  * Jason R. Clark (@jasonrclark)
990
1065
  * Lin Jen-Shin (@godfat)
991
1066
 
@@ -993,7 +1068,7 @@ GET /swagger
993
1068
 
994
1069
  Apache License 2.0
995
1070
 
996
- Copyright (c) 2012-2014, Lin Jen-Shin (godfat)
1071
+ Copyright (c) 2012-2015, Lin Jen-Shin (godfat)
997
1072
 
998
1073
  Licensed under the Apache License, Version 2.0 (the "License");
999
1074
  you may not use this file except in compliance with the License.
@@ -0,0 +1,44 @@
1
+
2
+ # Calculating -------------------------------------
3
+ # Jellyfish::URLMap 5.726k i/100ms
4
+ # Rack::URLMap 167.000 i/100ms
5
+ # -------------------------------------------------
6
+ # Jellyfish::URLMap 62.397k (± 1.2%) i/s - 314.930k
7
+ # Rack::URLMap 1.702k (± 1.5%) i/s - 8.517k
8
+
9
+ # Comparison:
10
+ # Jellyfish::URLMap: 62397.3 i/s
11
+ # Rack::URLMap: 1702.0 i/s - 36.66x slower
12
+
13
+ require 'jellyfish'
14
+ require 'rack'
15
+
16
+ require 'benchmark/ips'
17
+
18
+ num = 1000
19
+ app = lambda do |_|
20
+ ok = [200, {}, []]
21
+ rn = lambda{ |_| ok }
22
+
23
+ (0...num).each do |i|
24
+ map "/#{i}" do
25
+ run rn
26
+ end
27
+ end
28
+ end
29
+
30
+ jelly = Jellyfish::Builder.app(&app)
31
+ rack = Rack::Builder.app(&app)
32
+ path_info = 'PATH_INFO'
33
+
34
+ Benchmark.ips do |x|
35
+ x.report(jelly.class) do
36
+ jelly.call(path_info => rand(num).to_s)
37
+ end
38
+
39
+ x.report(rack.class) do
40
+ rack.call(path_info => rand(num).to_s)
41
+ end
42
+
43
+ x.compare!
44
+ end