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 +4 -4
- data/README.md +7 -0
- data/VERSION +1 -1
- data/lib/rack/app/cli/fetcher/server.rb +19 -0
- data/lib/rack/app/cli/fetcher.rb +12 -13
- data/lib/rack/app/constants.rb +1 -0
- data/lib/rack/app/endpoint/properties.rb +6 -1
- data/lib/rack/app/endpoint.rb +1 -1
- data/lib/rack/app/instance_methods/streaming.rb +16 -0
- data/lib/rack/app/instance_methods.rb +2 -0
- data/lib/rack/app/middlewares/configuration.rb +4 -2
- data/lib/rack/app/middlewares/header_setter.rb +4 -10
- data/lib/rack/app/router/base.rb +8 -3
- data/lib/rack/app/router/dynamic.rb +4 -1
- data/lib/rack/app/router/static.rb +5 -1
- data/lib/rack/app/serializer.rb +1 -1
- data/lib/rack/app/streamer/scheduler/null.rb +13 -0
- data/lib/rack/app/streamer/scheduler.rb +14 -0
- data/lib/rack/app/streamer.rb +56 -0
- data/lib/rack/app/test.rb +7 -5
- data/lib/rack/app.rb +1 -0
- data/old_ruby.sh +1 -0
- data/spec_files.txt +1 -0
- data/spike/array_vs_proc.rb +20 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c43fab6a1ba24663ef2b9295f9d34a093d65f919
|
4
|
+
data.tar.gz: d9c1de6b460aaf5f2d4fde0e87d1845a41095115
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
data/lib/rack/app/cli/fetcher.rb
CHANGED
@@ -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
|
-
|
17
|
-
|
18
|
-
app = server.app
|
18
|
+
protected
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
data/lib/rack/app/constants.rb
CHANGED
@@ -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
|
data/lib/rack/app/endpoint.rb
CHANGED
@@ -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.
|
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,
|
6
|
-
@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
|
-
|
9
|
+
status, headers, body = @app.call(env)
|
10
10
|
|
11
11
|
@headers.each do |header, value|
|
12
|
-
|
12
|
+
headers[header] ||= value
|
13
13
|
end
|
14
14
|
|
15
|
-
|
15
|
+
[status, headers, body]
|
16
16
|
end
|
17
17
|
|
18
|
-
|
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
|
data/lib/rack/app/router/base.rb
CHANGED
@@ -30,22 +30,27 @@ class Rack::App::Router::Base
|
|
30
30
|
}
|
31
31
|
)
|
32
32
|
|
33
|
-
|
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(
|
49
|
+
raise(NotImplementedError)
|
45
50
|
end
|
46
51
|
|
47
52
|
def fetch_context(request_method, request_path)
|
48
|
-
raise(
|
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
|
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
|
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
|
data/lib/rack/app/serializer.rb
CHANGED
@@ -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
|
2
|
-
require
|
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
|
-
|
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
|
-
@
|
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) ? @
|
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
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.
|
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-
|
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
|