rack-app 5.0.0 → 5.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: 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