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 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