rack-app 5.0.0 → 5.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: 85eef183f233ed422353b4658cc710fcddd6f3fa
4
- data.tar.gz: c64e1dea7180304029ce7515fdf96fdfa2339d60
3
+ metadata.gz: c43fab6a1ba24663ef2b9295f9d34a093d65f919
4
+ data.tar.gz: d9c1de6b460aaf5f2d4fde0e87d1845a41095115
5
5
  SHA512:
6
- metadata.gz: c63f77fa26cf15b1a5312afdb6b199fd51d3d5fc79cc5f3bdd85728ce45002a5c8eee7de6ebe110506cf3941c0f7c6573485ef22e10a3d8b550cd31a193391ae
7
- data.tar.gz: 282c092d984e8202bf4ce0d3cc81202033fa732822032ff804d8ef6241bc01acbfba817ecdb4358ff4210fbc101a8a478b7838fe30eff9e39de00ace2f7340a6
6
+ metadata.gz: e96d27d2479d291d4d79dcd14e09d9b764bd2c942b9ba747ea0fe18677123243cc67de07fa39c8bbfdb7de27b45adbb05e86a7bbe98f1fed0f7143040f790fee
7
+ data.tar.gz: ed4bdf700375dd5dc3e4f915af56d0531ae20772a9110e61b80323f116191f2f2a03ffe1155957cfc9ed188b0e694042c44b5b1d1955fabb52ab7ece3ff29f9b
data/README.md CHANGED
@@ -69,6 +69,7 @@ Yes, in fact it's already powering heroku hosted micro-services.
69
69
  * namespaces for endpoint request path declarations so it can be dry and unified
70
70
  * no Class method bloat, so you can enjoy pure ruby without any surprises
71
71
  * App mounting so you can crete separated controllers for different task
72
+ * Streaming
72
73
  * Null time look up routing
73
74
  * allows as many endpoint registration to you as you want, without impact on route look up speed
74
75
  * only basic sets for instance method lvl for the must need tools, such as params, payload
@@ -164,6 +165,12 @@ class App < Rack::App
164
165
 
165
166
  root '/hello'
166
167
 
168
+ get '/stream' do
169
+ stream do |out|
170
+ out << 'data row'
171
+ end
172
+ end
173
+
167
174
  end
168
175
 
169
176
  ```
data/VERSION CHANGED
@@ -1 +1 @@
1
- 5.0.0
1
+ 5.1.0
@@ -1,5 +1,24 @@
1
1
  class Rack::App::CLI::Fetcher::Server < Rack::Server
2
2
 
3
+ def get_rack_app
4
+ app_class = self.app
5
+ last_app = nil
6
+ until app_class.is_a?(Class) && app_class <= Rack::App
7
+ raise if app_class.__id__ == last_app.__id__
8
+
9
+ app_class.instance_variables.each do |ivar|
10
+ value = app_class.instance_variable_get(ivar)
11
+ if value.respond_to?(:call) and not [Method, Proc, UnboundMethod].include?(value.class)
12
+ app_class = value
13
+ end
14
+ end
15
+
16
+ last_app = app_class
17
+ end
18
+ app_class
19
+ rescue
20
+ end
21
+
3
22
  Abort = Class.new(StandardError)
4
23
 
5
24
  def app
@@ -12,22 +12,21 @@ module Rack::App::CLI::Fetcher
12
12
  end
13
13
 
14
14
  def rack_app
15
+ @rack_app ||= (server_based_lookup || rack_app_with_most_endpoints)
16
+ end
15
17
 
16
- server = Rack::App::CLI::Fetcher::Server.new(:config => 'config.ru')
17
-
18
- app = server.app
18
+ protected
19
19
 
20
- until app.is_a?(Class) && app <= Rack::App
21
- app.instance_variables.each do |ivar|
22
- value = app.instance_variable_get(ivar)
23
- if value.respond_to?(:call) and not [Method, Proc, UnboundMethod].include?(value.class)
24
- app = value
25
- end
26
- end
27
- end
28
-
29
- app
20
+ def server_based_lookup
21
+ Rack::App::CLI::Fetcher::Server.new(:config => 'config.ru').get_rack_app
22
+ end
30
23
 
24
+ def rack_app_with_most_endpoints
25
+ ObjectSpace.each_object(Class).select{|klass|
26
+ klass < Rack::App
27
+ }.uniq.sort_by{ |rack_app|
28
+ rack_app.router.endpoints.length
29
+ }.last
31
30
  end
32
31
 
33
32
  end
@@ -22,6 +22,7 @@ module Rack::App::Constants
22
22
 
23
23
  module ENV
24
24
  REQUEST_HANDLER = 'rack-app.handler'
25
+ SERIALIZER = 'rack-app.serializer'
25
26
  PARSED_PARAMS = 'rack-app.parsed_params'
26
27
  VALIDATED_PARAMS = 'rack-app.validated_params'
27
28
  ORIGINAL_PATH_INFO = 'rack-app.original_path_info'.freeze
@@ -1,7 +1,12 @@
1
1
  class Rack::App::Endpoint::Properties
2
2
 
3
3
  def to_hash
4
- @raw
4
+ app_class
5
+ serializer
6
+ error_handler
7
+ middleware_builders_blocks
8
+ endpoint_method_name
9
+ return @raw
5
10
  end
6
11
 
7
12
  def app_class
@@ -29,7 +29,7 @@ class Rack::App::Endpoint
29
29
  builder_blocks.each do |builder_block|
30
30
  builder_block.call(builder)
31
31
  end
32
- builder.use(Rack::App::Middlewares::Configuration, @properties.app_class)
32
+ builder.use(Rack::App::Middlewares::Configuration, @properties.to_hash)
33
33
  apply_hook_middlewares(builder)
34
34
  end
35
35
 
@@ -0,0 +1,16 @@
1
+ module Rack::App::InstanceMethods::Streaming
2
+ #
3
+ # Copyright (c) 2007, 2008, 2009 Blake Mizerany
4
+ # Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Konstantin Haase
5
+ #
6
+ # Allows to start sending data to the client even though later parts of
7
+ # the response body have not yet been generated.
8
+ #
9
+ # The close parameter specifies whether Stream#close should be called
10
+ # after the block has been executed. This is only relevant for evented
11
+ # servers like Thin or Rainbows.
12
+ def stream(keep_open = false, &back)
13
+ response.body = Rack::App::Streamer.new(request.env, :keep_open => keep_open, &back)
14
+ finish_response
15
+ end
16
+ end
@@ -4,10 +4,12 @@ module Rack::App::InstanceMethods
4
4
  require 'rack/app/instance_methods/http_control'
5
5
  require 'rack/app/instance_methods/payload'
6
6
  require 'rack/app/instance_methods/serve_file'
7
+ require 'rack/app/instance_methods/streaming'
7
8
 
8
9
  include Rack::App::InstanceMethods::Core
9
10
  include Rack::App::InstanceMethods::HttpControl
10
11
  include Rack::App::InstanceMethods::Payload
11
12
  include Rack::App::InstanceMethods::ServeFile
13
+ include Rack::App::InstanceMethods::Streaming
12
14
 
13
15
  end
@@ -2,12 +2,14 @@ require "rack/request"
2
2
  require "rack/response"
3
3
  class Rack::App::Middlewares::Configuration
4
4
 
5
- def initialize(app, handler_class)
6
- @handler_class = handler_class
5
+ def initialize(app, options={})
6
+ @handler_class = options[:app_class] || raise
7
+ @serializer = options[:serializer] || raise
7
8
  @app = app
8
9
  end
9
10
 
10
11
  def call(env)
12
+ env[Rack::App::Constants::ENV::SERIALIZER]= @serializer
11
13
  env[Rack::App::Constants::ENV::REQUEST_HANDLER]= handler(env)
12
14
  @app.call(env)
13
15
  end
@@ -6,19 +6,13 @@ class Rack::App::Middlewares::HeaderSetter
6
6
  end
7
7
 
8
8
  def call(env)
9
- response = rack_response(@app.call(env))
9
+ status, headers, body = @app.call(env)
10
10
 
11
11
  @headers.each do |header, value|
12
- response.headers[header] ||= value
12
+ headers[header] ||= value
13
13
  end
14
14
 
15
- response.finish
15
+ [status, headers, body]
16
16
  end
17
17
 
18
- protected
19
-
20
- def rack_response(raw_response)
21
- Rack::Response.new(raw_response[2], raw_response[0], raw_response[1])
22
- end
23
-
24
- end
18
+ end
@@ -30,22 +30,27 @@ class Rack::App::Router::Base
30
30
  }
31
31
  )
32
32
 
33
- compile_registered_endpoints!
33
+ reset
34
34
  return endpoint
35
35
  end
36
36
 
37
37
  def reset
38
+ clean_routes!
38
39
  compile_registered_endpoints!
39
40
  end
40
41
 
41
42
  protected
42
43
 
44
+ def clean_routes!
45
+ raise(NotImplementedError)
46
+ end
47
+
43
48
  def compile_registered_endpoints!
44
- raise('IMPLEMENTATION MISSING ERROR')
49
+ raise(NotImplementedError)
45
50
  end
46
51
 
47
52
  def fetch_context(request_method, request_path)
48
- raise('IMPLEMENTATION MISSING ERROR')
53
+ raise(NotImplementedError)
49
54
  end
50
55
 
51
56
  def as_app(endpoint_or_app)
@@ -33,8 +33,11 @@ class Rack::App::Router::Dynamic < Rack::App::Router::Base
33
33
  path_part == Rack::App::Constants::RACK_BASED_APPLICATION
34
34
  end
35
35
 
36
- def compile_registered_endpoints!
36
+ def clean_routes!
37
37
  @http_method_cluster.clear
38
+ end
39
+
40
+ def compile_registered_endpoints!
38
41
  endpoints.each do |endpoint_prop|
39
42
  compile_endpoint(endpoint_prop[:request_method], endpoint_prop[:request_path], endpoint_prop[:endpoint])
40
43
  end
@@ -11,11 +11,15 @@ class Rack::App::Router::Static < Rack::App::Router::Base
11
11
  @mapped_endpoint_routes ||= {}
12
12
  end
13
13
 
14
- def compile_registered_endpoints!
14
+ def clean_routes!
15
15
  mapped_endpoint_routes.clear
16
+ end
17
+
18
+ def compile_registered_endpoints!
16
19
  endpoints.each do |endpoint|
17
20
  app = as_app(endpoint[:endpoint])
18
21
  mapped_endpoint_routes[[endpoint[:request_method].to_s.upcase, endpoint[:request_path]]]= app
19
22
  end
20
23
  end
24
+
21
25
  end
@@ -11,7 +11,7 @@ class Rack::App::Serializer
11
11
  end
12
12
 
13
13
  def serialize(object)
14
- @logic.call(object)
14
+ String(@logic.call(object))
15
15
  end
16
16
 
17
17
  end
@@ -0,0 +1,13 @@
1
+ module Rack::App::Streamer::Scheduler::Null
2
+
3
+ extend(self)
4
+
5
+ def schedule(*)
6
+ yield
7
+ end
8
+
9
+ def defer(*)
10
+ yield
11
+ end
12
+
13
+ end
@@ -0,0 +1,14 @@
1
+ module Rack::App::Streamer::Scheduler
2
+ require "rack/app/streamer/scheduler/null"
3
+
4
+ extend(self)
5
+
6
+ def by_env(env)
7
+ if env['async.callback'] && defined?(::EventMachine)
8
+ ::EventMachine
9
+ else
10
+ ::Rack::App::Streamer::Scheduler::Null
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,56 @@
1
+ # Copyright (c) 2007, 2008, 2009 Blake Mizerany
2
+ # Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Konstantin Haase
3
+ #
4
+ # Class of the response body in case you use #stream.
5
+ #
6
+ # Three things really matter: The front and back block (back being the
7
+ # block generating content, front the one sending it to the client) and
8
+ # the scheduler, integrating with whatever concurrency feature the Rack
9
+ # handler is using.
10
+ #
11
+ # Scheduler has to respond to defer and schedule.
12
+ class Rack::App::Streamer
13
+ require "rack/app/streamer/scheduler"
14
+
15
+ def initialize(env, options={}, &back)
16
+ @serializer = env[Rack::App::Constants::ENV::SERIALIZER]
17
+ @scheduler = options[:scheduler] || Rack::App::Streamer::Scheduler.by_env(env)
18
+ @keep_open = options[:keep_open] || false
19
+ @back = back.to_proc
20
+ @callbacks, @closed = [], false
21
+ end
22
+
23
+ def close
24
+ return if closed?
25
+ @closed = true
26
+ @scheduler.schedule { @callbacks.each { |c| c.call }}
27
+ end
28
+
29
+ def each(&front)
30
+ @front = front
31
+ @scheduler.defer do
32
+ begin
33
+ @back.call(self)
34
+ rescue Exception => ex
35
+ @scheduler.schedule { raise(ex) }
36
+ end
37
+ close unless @keep_open
38
+ end
39
+ end
40
+
41
+ def <<(data)
42
+ @scheduler.schedule { @front.call(@serializer.serialize(data)) }
43
+ self
44
+ end
45
+
46
+ def callback(&block)
47
+ return yield if closed?
48
+ @callbacks << block
49
+ end
50
+
51
+ alias errback callback
52
+
53
+ def closed?
54
+ @closed
55
+ end
56
+ end
data/lib/rack/app/test.rb CHANGED
@@ -1,5 +1,6 @@
1
- require 'uri'
2
- require 'rack/app'
1
+ require "uri"
2
+ require "rack/app"
3
+ require "rack/mock"
3
4
  module Rack::App::Test
4
5
 
5
6
  require 'rack/app/test/utils'
@@ -11,7 +12,8 @@ module Rack::App::Test
11
12
 
12
13
  attr_reader :last_response
13
14
 
14
- [:get, :post, :put, :delete, :options, :patch, :head].each do |request_method|
15
+ Rack::App::Constants::HTTP::METHODS.each do |request_method_type|
16
+ request_method = request_method_type.to_s.downcase
15
17
  define_method(request_method) do |*args|
16
18
 
17
19
  properties = args.select { |e| e.is_a?(Hash) }.reduce({}, &:merge!)
@@ -25,7 +27,7 @@ module Rack::App::Test
25
27
 
26
28
  def rack_app(&block)
27
29
 
28
- @app ||= lambda do
30
+ @rack_app ||= lambda do
29
31
  app_class = defined?(__rack_app_class__) ? __rack_app_class__ : nil
30
32
  constructors = []
31
33
  if defined?(__rack_app_constructor__) and __rack_app_constructor__.is_a?(Proc)
@@ -34,7 +36,7 @@ module Rack::App::Test
34
36
  Rack::App::Test::Utils.rack_app_by(app_class, constructors)
35
37
  end.call
36
38
 
37
- block.is_a?(Proc) ? @app.instance_exec(&block) : @app
39
+ block.is_a?(Proc) ? @rack_app.instance_exec(&block) : @rack_app
38
40
 
39
41
  end
40
42
 
data/lib/rack/app.rb CHANGED
@@ -13,6 +13,7 @@ class Rack::App
13
13
  require 'rack/app/params'
14
14
  require 'rack/app/router'
15
15
  require 'rack/app/endpoint'
16
+ require 'rack/app/streamer'
16
17
  require 'rack/app/extension'
17
18
  require 'rack/app/serializer'
18
19
  require 'rack/app/middlewares'
data/old_ruby.sh ADDED
@@ -0,0 +1 @@
1
+ rbenv shell 1.8.7-p375
data/spec_files.txt ADDED
@@ -0,0 +1 @@
1
+ ./spec/benchmark_spec.rb ./spec/rack/app/alias_endpoint_spec.rb ./spec/rack/app/bundled_extensions/logger_spec.rb ./spec/rack/app/cli_spec.rb ./spec/rack/app/endpoint_spec.rb ./spec/rack/app/extension_spec.rb ./spec/rack/app/file_server_spec.rb ./spec/rack/app/hooks_spec.rb ./spec/rack/app/inheritance_spec.rb ./spec/rack/app/instance_methods_spec.rb ./spec/rack/app/middlewares/header_setter_spec.rb ./spec/rack/app/mounting_spec.rb ./spec/rack/app/not_found_spec.rb ./spec/rack/app/only_next_endpoint_middlewares_spec.rb ./spec/rack/app/params_validation_spec/with_real_class_spec.rb ./spec/rack/app/params_validation_spec.rb ./spec/rack/app/redirect_spec.rb ./spec/rack/app/request_configurator_spec.rb ./spec/rack/app/router/dynamic_spec.rb ./spec/rack/app/router/static_spec.rb ./spec/rack/app/router_spec.rb ./spec/rack/app/streaming_spec.rb ./spec/rack/app/test_spec.rb ./spec/rack/app/utils/deep_dup_spec.rb ./spec/rack/app/utils/parser_spec.rb ./spec/rack/app/utils_spec.rb ./spec/rack/app_spec.rb
@@ -0,0 +1,20 @@
1
+ require 'benchmark'
2
+
3
+ TEST_AMOUNT = 1_000_000
4
+ Benchmark.bm(15) do |x|
5
+
6
+ x.report('empty_array') do
7
+ empty_array = []
8
+ TEST_AMOUNT.times do
9
+ empty_array.each{|e|}
10
+ end
11
+ end
12
+
13
+ x.report('proc call') do
14
+ block = proc {}
15
+ TEST_AMOUNT.times do
16
+ block.call
17
+ end
18
+ end
19
+
20
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-app
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Luzsi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-18 00:00:00.000000000 Z
11
+ date: 2016-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -116,6 +116,7 @@ files:
116
116
  - lib/rack/app/instance_methods/http_control.rb
117
117
  - lib/rack/app/instance_methods/payload.rb
118
118
  - lib/rack/app/instance_methods/serve_file.rb
119
+ - lib/rack/app/instance_methods/streaming.rb
119
120
  - lib/rack/app/middlewares.rb
120
121
  - lib/rack/app/middlewares/configuration.rb
121
122
  - lib/rack/app/middlewares/header_setter.rb
@@ -148,6 +149,9 @@ files:
148
149
  - lib/rack/app/singleton_methods/rack_interface.rb
149
150
  - lib/rack/app/singleton_methods/route_handling.rb
150
151
  - lib/rack/app/singleton_methods/settings.rb
152
+ - lib/rack/app/streamer.rb
153
+ - lib/rack/app/streamer/scheduler.rb
154
+ - lib/rack/app/streamer/scheduler/null.rb
151
155
  - lib/rack/app/test.rb
152
156
  - lib/rack/app/test/singleton_methods.rb
153
157
  - lib/rack/app/test/utils.rb
@@ -164,7 +168,10 @@ files:
164
168
  - lib/rack/app/utils/parser/string.rb
165
169
  - lib/rack/app/utils/parser/time.rb
166
170
  - lib/rack/app/version.rb
171
+ - old_ruby.sh
167
172
  - rack-app.gemspec
173
+ - spec_files.txt
174
+ - spike/array_vs_proc.rb
168
175
  - spike/method_vs_instance_exec.rb
169
176
  - spike/return_vs_throw.rb
170
177
  - src/Net__HTTP Cheat Sheet.pdf