rack-app 5.10.2 → 5.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/VERSION +1 -1
- data/lib/rack/app/constants.rb +2 -1
- data/lib/rack/app/endpoint.rb +1 -5
- data/lib/rack/app/endpoint/config.rb +21 -8
- data/lib/rack/app/middlewares/configuration.rb +3 -5
- data/lib/rack/app/params.rb +1 -26
- data/lib/rack/app/router.rb +44 -38
- data/lib/rack/app/router/tree.rb +40 -0
- data/lib/rack/app/router/tree/env.rb +13 -0
- data/lib/rack/app/router/tree/leaf.rb +34 -0
- data/lib/rack/app/router/tree/leaf/vein.rb +31 -0
- data/lib/rack/app/router/tree/mounted.rb +16 -0
- data/lib/rack/app/router/tree/mounted/application.rb +20 -0
- data/lib/rack/app/router/tree/node.rb +104 -0
- data/lib/rack/app/singleton_methods/mounting.rb +7 -21
- data/lib/rack/app/singleton_methods/route_handling.rb +1 -1
- data/lib/rack/app/utils.rb +4 -0
- data/spike/tree.rb +76 -0
- metadata +10 -7
- data/lib/rack/app/middlewares/configuration/path_params_matcher.rb +0 -14
- data/lib/rack/app/router/dynamic.rb +0 -170
- data/lib/rack/app/router/dynamic/request_path_part_placeholder.rb +0 -13
- data/lib/rack/app/router/not_found.rb +0 -19
- data/lib/rack/app/router/static.rb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 070c847ed07e3494ed51e88ebf084c6eb661a30f
|
4
|
+
data.tar.gz: 4b836fb0a7d4c38491b4d2774b85289d528c1c56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 566de7abd739139b8ac5980bcad9079995892d36c1f7213cadedd2451d62ce6ee7f41a2c23327c7174e0576b20ab1b7d71cbfab0b01a79424bb77ae63e35ade3
|
7
|
+
data.tar.gz: 91ac3f3615722f31dc483aa4cd4845902d8270655cb1a2e96c2fa72d78add151692ed0cc5a6304c6a5ad6f10a06d40e66c589ceb604b188b944d0fda8d18fb38
|
data/.rspec
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
5.
|
1
|
+
5.11.0
|
data/lib/rack/app/constants.rb
CHANGED
@@ -51,8 +51,9 @@ module Rack::App::Constants
|
|
51
51
|
PAYLOAD_GETTER = 'rack-app.payload.getter'.freeze
|
52
52
|
PARSED_PAYLOAD = 'rack-app.payload.parsed'.freeze
|
53
53
|
|
54
|
+
PATH_PARAMS = 'rack-app.path_params'.freeze
|
54
55
|
ORIGINAL_PATH_INFO = 'rack-app.original_path_info'.freeze
|
55
|
-
|
56
|
+
FORMATTED_PATH_INFO = 'rack-app.formatted_path_info'.freeze
|
56
57
|
METHODOVERRIDE_ORIGINAL_METHOD = 'rack-app.methodoverride.original_method'.freeze
|
57
58
|
|
58
59
|
end
|
data/lib/rack/app/endpoint.rb
CHANGED
@@ -2,7 +2,7 @@ class Rack::App::Endpoint
|
|
2
2
|
|
3
3
|
require "forwardable"
|
4
4
|
extend Forwardable
|
5
|
-
def_delegators :@config, :
|
5
|
+
def_delegators :@config, :request_methods, :request_path, :description
|
6
6
|
|
7
7
|
require "rack/app/endpoint/config"
|
8
8
|
require "rack/app/endpoint/builder"
|
@@ -26,10 +26,6 @@ class Rack::App::Endpoint
|
|
26
26
|
to_app.call(env)
|
27
27
|
end
|
28
28
|
|
29
|
-
def supported_extnames
|
30
|
-
@config.serializer.extnames
|
31
|
-
end
|
32
|
-
|
33
29
|
def to_app
|
34
30
|
@config.application || self.class::Builder.new(@config).build
|
35
31
|
end
|
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
class Rack::App::Endpoint::Config
|
2
|
-
|
3
3
|
def to_hash
|
4
4
|
error_handler
|
5
5
|
middleware_builders_blocks
|
6
6
|
request_path
|
7
|
-
|
8
|
-
|
7
|
+
request_methods
|
8
|
+
defined_request_path
|
9
|
+
@raw
|
9
10
|
end
|
10
11
|
|
11
12
|
def payload_builder
|
@@ -48,16 +49,29 @@ class Rack::App::Endpoint::Config
|
|
48
49
|
@raw[:method_name] ||= register_method_to_app_class
|
49
50
|
end
|
50
51
|
|
51
|
-
def
|
52
|
-
|
52
|
+
def request_methods
|
53
|
+
case @raw[:request_methods] || raise('missing config: request_methods')
|
54
|
+
when Rack::App::Constants::HTTP::METHOD::ANY
|
55
|
+
Rack::App::Constants::HTTP::METHODS
|
56
|
+
when ::Array
|
57
|
+
@raw[:request_methods].map(&:to_sym)
|
58
|
+
else
|
59
|
+
[@raw[:request_methods]].flatten.map(&:to_sym)
|
60
|
+
end
|
53
61
|
end
|
54
62
|
|
55
63
|
def request_path
|
56
64
|
Rack::App::Utils.normalize_path(@raw[:request_path] || raise('missing request_path!'))
|
57
65
|
end
|
58
66
|
|
67
|
+
def defined_request_path
|
68
|
+
Rack::App::Utils.normalize_path(@raw[:defined_request_path] ||= request_path)
|
69
|
+
end
|
70
|
+
|
59
71
|
def description
|
60
|
-
@raw[:route][:description] || @raw[:route][:desc]
|
72
|
+
@raw[:route][:description] || @raw[:route][:desc]
|
73
|
+
rescue
|
74
|
+
nil
|
61
75
|
end
|
62
76
|
|
63
77
|
protected
|
@@ -69,11 +83,10 @@ class Rack::App::Endpoint::Config
|
|
69
83
|
def register_method_to_app_class
|
70
84
|
method_name = '__' + ::Rack::App::Utils.uuid
|
71
85
|
app_class.__send__(:define_method, method_name, &logic_block)
|
72
|
-
|
86
|
+
method_name
|
73
87
|
end
|
74
88
|
|
75
89
|
def logic_block
|
76
90
|
@raw[:user_defined_logic]
|
77
91
|
end
|
78
|
-
|
79
92
|
end
|
@@ -3,8 +3,6 @@ require "rack/request"
|
|
3
3
|
require "rack/response"
|
4
4
|
class Rack::App::Middlewares::Configuration
|
5
5
|
|
6
|
-
require "rack/app/middlewares/configuration/path_params_matcher"
|
7
|
-
|
8
6
|
def initialize(app, config)
|
9
7
|
@app = app || raise
|
10
8
|
@serializer = config.serializer || raise
|
@@ -13,12 +11,12 @@ class Rack::App::Middlewares::Configuration
|
|
13
11
|
end
|
14
12
|
|
15
13
|
def call(env)
|
16
|
-
env[Rack::App::Constants::ENV::REQUEST_HANDLER]= handler(env)
|
14
|
+
env[::Rack::App::Constants::ENV::REQUEST_HANDLER]= handler(env)
|
17
15
|
env[::Rack::App::Constants::ENV::SERIALIZER]= @serializer
|
18
16
|
env[::Rack::App::Constants::ENV::PAYLOAD_PARSER]= @payload_parser
|
19
17
|
env[::Rack::App::Constants::ENV::PAYLOAD_GETTER]= lambda do
|
20
|
-
|
21
|
-
|
18
|
+
env[::Rack::App::Constants::ENV::PARSED_PAYLOAD] ||= env[::Rack::App::Constants::ENV::PAYLOAD_PARSER].parse_env(env)
|
19
|
+
end
|
22
20
|
@app.call(env)
|
23
21
|
end
|
24
22
|
|
data/lib/rack/app/params.rb
CHANGED
@@ -38,32 +38,7 @@ class Rack::App::Params
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def request_path_params
|
41
|
-
|
42
|
-
path_params.merge!(extract_path_params) unless path_params_matcher.empty?
|
43
|
-
path_params
|
44
|
-
end
|
45
|
-
|
46
|
-
def extract_path_params
|
47
|
-
last_index = request_path_parts.length - 1
|
48
|
-
request_path_parts.each.with_index.reduce({}) do |params_col, (path_part, index)|
|
49
|
-
if path_params_matcher[index]
|
50
|
-
if index == last_index && @env[::Rack::App::Constants::ENV::EXTNAME]
|
51
|
-
matcher = Regexp.escape(@env[::Rack::App::Constants::ENV::EXTNAME])
|
52
|
-
path_part = path_part.sub(/#{matcher}$/,'')
|
53
|
-
end
|
54
|
-
params_col[path_params_matcher[index]]= path_part
|
55
|
-
end
|
56
|
-
|
57
|
-
params_col
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def request_path_parts
|
62
|
-
@env[::Rack::App::Constants::ENV::PATH_INFO].split('/')
|
63
|
-
end
|
64
|
-
|
65
|
-
def path_params_matcher
|
66
|
-
@env[::Rack::App::Constants::ENV::PATH_PARAMS_MATCHER] || {}
|
41
|
+
@env[::Rack::App::Constants::ENV::PATH_PARAMS]
|
67
42
|
end
|
68
43
|
|
69
44
|
end
|
data/lib/rack/app/router.rb
CHANGED
@@ -1,42 +1,35 @@
|
|
1
1
|
class Rack::App::Router
|
2
2
|
|
3
|
-
require 'rack/app/router/
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
require 'rack/app/router/tree'
|
4
|
+
|
5
|
+
NOT_FOUND_APP = lambda do |env|
|
6
|
+
rack_response = Rack::Response.new
|
7
|
+
rack_response.status = 404
|
8
|
+
rack_response.write('404 Not Found')
|
9
|
+
rack_response.finish
|
10
|
+
end
|
7
11
|
|
8
12
|
def call(env)
|
9
|
-
|
10
|
-
@static.call(env) or @dynamic.call(env) or @not_found.call(env)
|
13
|
+
@tree.call(env) || NOT_FOUND_APP.call(env)
|
11
14
|
end
|
12
15
|
|
13
16
|
def endpoints
|
14
|
-
|
17
|
+
@endpoints ||= []
|
15
18
|
end
|
16
19
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
wd0 = endpoints.map { |endpoint| endpoint.request_method.to_s.length }.max
|
22
|
-
wd1 = endpoints.map { |endpoint| endpoint.request_path.to_s.length }.max
|
23
|
-
wd2 = endpoints.map { |endpoint| endpoint.description.to_s.length }.max
|
24
|
-
|
25
|
-
return endpoints.sort_by { |endpoint| [endpoint.request_method, endpoint.request_path] }.map do |endpoint|
|
26
|
-
[
|
27
|
-
endpoint.request_method.to_s.ljust(wd0),
|
28
|
-
endpoint.request_path.to_s.ljust(wd1),
|
29
|
-
endpoint.description.to_s.ljust(wd2)
|
30
|
-
].join(' ')
|
31
|
-
end
|
32
|
-
|
20
|
+
def register_endpoint!(endpoint)
|
21
|
+
endpoints.push(endpoint)
|
22
|
+
compile_endpoint!(endpoint)
|
23
|
+
return endpoint
|
33
24
|
end
|
34
25
|
|
35
|
-
|
36
|
-
|
37
|
-
|
26
|
+
# add ! to method name
|
27
|
+
def reset
|
28
|
+
@tree = Rack::App::Router::Tree.new
|
29
|
+
compile_registered_endpoints!
|
38
30
|
end
|
39
31
|
|
32
|
+
# rename to merge!
|
40
33
|
def merge_router!(router, prop={})
|
41
34
|
raise(ArgumentError, 'invalid router object, must implement :endpoints interface') unless router.respond_to?(:endpoints)
|
42
35
|
router.endpoints.each do |endpoint|
|
@@ -47,27 +40,40 @@ class Rack::App::Router
|
|
47
40
|
nil
|
48
41
|
end
|
49
42
|
|
50
|
-
|
51
|
-
|
43
|
+
|
44
|
+
def show_endpoints
|
45
|
+
|
46
|
+
endpoints = self.endpoints
|
47
|
+
|
48
|
+
wd0 = endpoints.map { |endpoint| endpoint.request_methods.first.to_s.length }.max
|
49
|
+
wd1 = endpoints.map { |endpoint| endpoint.request_path.to_s.length }.max
|
50
|
+
wd2 = endpoints.map { |endpoint| endpoint.description.to_s.length }.max
|
51
|
+
|
52
|
+
return endpoints.sort_by { |endpoint| [endpoint.request_methods.first, endpoint.request_path] }.map do |endpoint|
|
53
|
+
[
|
54
|
+
endpoint.request_methods.first.to_s.ljust(wd0),
|
55
|
+
endpoint.request_path.to_s.ljust(wd1),
|
56
|
+
endpoint.description.to_s.ljust(wd2)
|
57
|
+
].join(' ')
|
58
|
+
end
|
59
|
+
|
52
60
|
end
|
53
61
|
|
54
62
|
protected
|
55
63
|
|
64
|
+
|
56
65
|
def initialize
|
57
|
-
|
58
|
-
@dynamic = Rack::App::Router::Dynamic.new
|
59
|
-
@not_found = Rack::App::Router::NotFound.new
|
66
|
+
reset
|
60
67
|
end
|
61
68
|
|
62
|
-
def
|
63
|
-
|
69
|
+
def compile_registered_endpoints!
|
70
|
+
endpoints.each do |endpoint|
|
71
|
+
compile_endpoint!(endpoint)
|
72
|
+
end
|
64
73
|
end
|
65
74
|
|
66
|
-
def
|
67
|
-
|
68
|
-
!!(path_str.to_s =~ /\/:\w+/i) or
|
69
|
-
!!(path_str.to_s =~ /\/\*/i) or
|
70
|
-
path_str.include?(Rack::App::Constants::RACK_BASED_APPLICATION)
|
75
|
+
def compile_endpoint!(endpoint)
|
76
|
+
@tree.add(endpoint)
|
71
77
|
end
|
72
78
|
|
73
79
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Rack::App::Router::Tree
|
3
|
+
|
4
|
+
require 'rack/app/router/tree/env'
|
5
|
+
require 'rack/app/router/tree/node'
|
6
|
+
require 'rack/app/router/tree/leaf'
|
7
|
+
require 'rack/app/router/tree/mounted'
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@root = self.class::Node.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def add(endpoint)
|
14
|
+
@root.set(endpoint, *path_info_parts_by(endpoint.request_path))
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
self.class::Env.configure(env)
|
19
|
+
@root.get(env, *path_info_parts_by(env[Rack::App::Constants::ENV::FORMATTED_PATH_INFO]))
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def request_methods(endpoint)
|
25
|
+
case endpoint.request_method
|
26
|
+
when ::Rack::App::Constants::HTTP::METHOD::ANY
|
27
|
+
::Rack::App::Constants::HTTP::METHODS.each{|m| yield(m) }
|
28
|
+
else
|
29
|
+
yield(endpoint.request_method)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def cluster(request_method)
|
34
|
+
@methods[request_method.to_s.upcase] ||= Rack::App::Router::Tree::Node.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def path_info_parts_by(path_info)
|
38
|
+
Rack::App::Utils.split_path_info(Rack::App::Utils.normalize_path(path_info))
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Rack::App::Router::Tree::Env
|
3
|
+
extend(self)
|
4
|
+
|
5
|
+
E = Rack::App::Constants::ENV
|
6
|
+
|
7
|
+
def configure(env)
|
8
|
+
env[E::PATH_PARAMS] ||= {}
|
9
|
+
env[E::FORMATTED_PATH_INFO] = Rack::App::Utils.normalize_path(env[E::PATH_INFO])
|
10
|
+
env[E::EXTNAME] = File.extname(Rack::App::Utils.split_path_info(env[E::FORMATTED_PATH_INFO]).last)
|
11
|
+
env[E::FORMATTED_PATH_INFO].slice!(/#{Regexp.escape(env[E::EXTNAME])}$/)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Rack::App::Router::Tree::Leaf < ::Hash
|
3
|
+
require 'rack/app/router/tree/leaf/vein'
|
4
|
+
|
5
|
+
def get(env)
|
6
|
+
vein = vein_by(env)
|
7
|
+
vein && vein.get(env)
|
8
|
+
end
|
9
|
+
|
10
|
+
def set(endpoint)
|
11
|
+
endpoint.request_methods.each do |request_method|
|
12
|
+
vein_for(request_method).set(endpoint)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def struct
|
17
|
+
hash = {}
|
18
|
+
self.each do |request_method, vein|
|
19
|
+
hash[request_method] = vein.struct
|
20
|
+
end
|
21
|
+
hash
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def vein_by(env)
|
27
|
+
self[env[Rack::App::Constants::ENV::REQUEST_METHOD].to_sym]
|
28
|
+
end
|
29
|
+
|
30
|
+
def vein_for(request_method)
|
31
|
+
self[request_method] ||= Rack::App::Router::Tree::Leaf::Vein.new
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Rack::App::Router::Tree::Leaf::Vein < ::Hash
|
3
|
+
|
4
|
+
E = Rack::App::Constants::ENV
|
5
|
+
|
6
|
+
def set(endpoint)
|
7
|
+
app = endpoint.to_app
|
8
|
+
endpoint.config.serializer.extnames.each do |extname|
|
9
|
+
self[extname] = app
|
10
|
+
end
|
11
|
+
self[extname_for(endpoint)] = app
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(env)
|
15
|
+
app = self[env[E::EXTNAME]]
|
16
|
+
app && app.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
def struct
|
20
|
+
self.reduce({}) do |hash, (extname, app)|
|
21
|
+
hash[extname]= :app
|
22
|
+
hash
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def extname_for(endpoint)
|
29
|
+
File.extname(Rack::App::Utils.split_path_info(endpoint.request_path).last)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Rack::App::Router::Tree::Mounted
|
3
|
+
|
4
|
+
require 'rack/app/router/tree/mounted/application'
|
5
|
+
|
6
|
+
def get(env)
|
7
|
+
@app.call(env)
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def initialize(endpoint)
|
13
|
+
@app = endpoint.to_app
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Rack::App::Router::Tree::Mounted::Application < Rack::App::Router::Tree::Mounted
|
3
|
+
protected
|
4
|
+
|
5
|
+
def initialize(endpoint)
|
6
|
+
@app = build(endpoint)
|
7
|
+
end
|
8
|
+
|
9
|
+
def build(endpoint)
|
10
|
+
builder = Rack::Builder.new
|
11
|
+
builder.use(Rack::App::Middlewares::PathInfoCutter, mount_path(endpoint))
|
12
|
+
builder.run(endpoint.to_app)
|
13
|
+
builder.to_app
|
14
|
+
end
|
15
|
+
|
16
|
+
def mount_path(endpoint)
|
17
|
+
mount_path_parts = (endpoint.request_path.split('/') - [Rack::App::Constants::RACK_BASED_APPLICATION, ''])
|
18
|
+
mount_path_parts.empty? ? '' : Rack::App::Utils.join(mount_path_parts)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Rack::App::Router::Tree::Node < ::Hash
|
3
|
+
|
4
|
+
PARAM = :PARAM
|
5
|
+
|
6
|
+
def set(endpoint, current=nil, *path_info_parts)
|
7
|
+
case type(current)
|
8
|
+
when :NODE
|
9
|
+
node_for(save_key(current)).set(endpoint, *path_info_parts)
|
10
|
+
when :LEAF
|
11
|
+
save_to_leaf(endpoint)
|
12
|
+
when :RACK_BASED_APPLICATION
|
13
|
+
attach(:RACK_BASED_APPLICATION, Rack::App::Router::Tree::Mounted::Application.new(endpoint))
|
14
|
+
when :MOUNTED
|
15
|
+
attach(:MOUNT, Rack::App::Router::Tree::Mounted.new(endpoint))
|
16
|
+
else
|
17
|
+
raise('UNKNOWN')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(env, current=nil, *path_info_parts)
|
22
|
+
return app_for(env) if current.nil?
|
23
|
+
node = next_node(env, current)
|
24
|
+
(node && node.get(env, *path_info_parts)) || mounted(env)
|
25
|
+
end
|
26
|
+
|
27
|
+
def struct
|
28
|
+
self.reduce({}) do |hash, (k,v)|
|
29
|
+
if k == PARAM
|
30
|
+
hash[k] = v
|
31
|
+
else
|
32
|
+
hash[k] = v.struct
|
33
|
+
end
|
34
|
+
hash
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def app_for(env)
|
41
|
+
app = self[:LEAF] || mounted_app
|
42
|
+
app && app.get(env)
|
43
|
+
end
|
44
|
+
|
45
|
+
def mounted(env)
|
46
|
+
mounted_app && mounted_app.get(env)
|
47
|
+
end
|
48
|
+
|
49
|
+
def mounted_app
|
50
|
+
self[:MOUNT] || self[:RACK_BASED_APPLICATION]
|
51
|
+
end
|
52
|
+
|
53
|
+
def attach(key, app_or_endpoint)
|
54
|
+
self[key.to_sym] = app_or_endpoint
|
55
|
+
end
|
56
|
+
|
57
|
+
def save_to_leaf(endpoint)
|
58
|
+
self[:LEAF] ||= Rack::App::Router::Tree::Leaf.new
|
59
|
+
self[:LEAF].set(endpoint)
|
60
|
+
end
|
61
|
+
|
62
|
+
def next_node(env, current)
|
63
|
+
self[current] || any_path(env, current)
|
64
|
+
end
|
65
|
+
|
66
|
+
def any_path(env, current)
|
67
|
+
if self[:ANY]
|
68
|
+
env[Rack::App::Constants::ENV::PATH_PARAMS][self[PARAM]] = current
|
69
|
+
self[:ANY]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def node_for(key)
|
74
|
+
self[key] ||= self.class.new
|
75
|
+
end
|
76
|
+
|
77
|
+
def type(current)
|
78
|
+
case current
|
79
|
+
when Rack::App::Constants::RACK_BASED_APPLICATION
|
80
|
+
:RACK_BASED_APPLICATION
|
81
|
+
when '**','*'
|
82
|
+
:MOUNTED
|
83
|
+
when NilClass
|
84
|
+
:LEAF
|
85
|
+
else
|
86
|
+
:NODE
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def save_key(path)
|
91
|
+
case path
|
92
|
+
when /^:\w+$/i
|
93
|
+
self[PARAM] = path.sub(/^:/, '')
|
94
|
+
:ANY
|
95
|
+
else
|
96
|
+
extnameless(path)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def extnameless(path)
|
101
|
+
path.sub(/\.\w+$/,'')
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -54,7 +54,10 @@ module Rack::App::SingletonMethods::Mounting
|
|
54
54
|
|
55
55
|
endpoint = Rack::App::Endpoint.new(
|
56
56
|
route_registration_properties.merge(
|
57
|
-
:
|
57
|
+
:request_methods => [
|
58
|
+
Rack::App::Constants::HTTP::METHOD::GET,
|
59
|
+
Rack::App::Constants::HTTP::METHOD::OPTIONS
|
60
|
+
],
|
58
61
|
:request_path => request_path,
|
59
62
|
:application => file_server
|
60
63
|
)
|
@@ -66,34 +69,17 @@ module Rack::App::SingletonMethods::Mounting
|
|
66
69
|
end
|
67
70
|
|
68
71
|
def mount_rack_interface_compatible_application(rack_based_app, options={})
|
69
|
-
|
70
|
-
|
71
|
-
route_registration_properties.merge(
|
72
|
-
:request_method => ::Rack::App::Constants::HTTP::METHOD::ANY,
|
72
|
+
properties = route_registration_properties.merge(
|
73
|
+
:request_methods => ::Rack::App::Constants::HTTP::METHOD::ANY,
|
73
74
|
:request_path => Rack::App::Utils.join(
|
74
75
|
@namespaces,
|
75
76
|
options[:to],
|
76
77
|
::Rack::App::Constants::RACK_BASED_APPLICATION
|
77
78
|
),
|
78
79
|
:application => rack_based_app
|
79
|
-
)
|
80
|
-
)
|
81
80
|
)
|
82
|
-
end
|
83
|
-
|
84
|
-
alias mount_rack_based_application mount_rack_interface_compatible_application
|
85
|
-
Rack::App::Utils.deprecate(self,:mount_rack_based_application, "mount or mount_rack_interface_compatible_application", 2016,9)
|
86
|
-
alias mount_app mount_rack_interface_compatible_application
|
87
|
-
Rack::App::Utils.deprecate(self,:mount_app, "mount or mount_rack_interface_compatible_application", 2016,9)
|
88
81
|
|
89
|
-
|
90
|
-
|
91
|
-
def on_mounted(&block)
|
92
|
-
@on_mounted ||= []
|
93
|
-
@on_mounted << block unless block.nil?
|
94
|
-
@on_mounted
|
82
|
+
router.register_endpoint!(Rack::App::Endpoint.new(properties))
|
95
83
|
end
|
96
84
|
|
97
|
-
alias while_being_mounted on_mounted
|
98
|
-
|
99
85
|
end
|
@@ -28,7 +28,7 @@ module Rack::App::SingletonMethods::RouteHandling
|
|
28
28
|
:payload => payload,
|
29
29
|
:error_handler => error,
|
30
30
|
:user_defined_logic => block,
|
31
|
-
:
|
31
|
+
:request_methods => [request_method],
|
32
32
|
:route => route_registration_properties.dup,
|
33
33
|
:middleware_builders_blocks => next_endpoint_middlewares.dup,
|
34
34
|
:request_path => ::Rack::App::Utils.join(@namespaces, request_path)
|
data/lib/rack/app/utils.rb
CHANGED
@@ -22,6 +22,10 @@ module Rack::App::Utils
|
|
22
22
|
path
|
23
23
|
end
|
24
24
|
|
25
|
+
def split_path_info(path_info)
|
26
|
+
path_info.to_s.split('/').tap { |a| a.empty? && a.push('') }
|
27
|
+
end
|
28
|
+
|
25
29
|
def snake_case(camel_cased_word)
|
26
30
|
word = camel_cased_word.to_s.gsub('::', '/')
|
27
31
|
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
data/spike/tree.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
rack_api_lib_folder = File.join(File.dirname(__FILE__), '..', 'lib')
|
5
|
+
$LOAD_PATH.unshift(rack_api_lib_folder)
|
6
|
+
require 'rack/app'
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
tree = Rack::App::Router::Tree.new
|
10
|
+
|
11
|
+
APP = Class.new(Rack::App)
|
12
|
+
|
13
|
+
payload = Rack::App::Payload::Builder.new
|
14
|
+
|
15
|
+
payload.parser_builder do
|
16
|
+
accept :json
|
17
|
+
end
|
18
|
+
|
19
|
+
serializer = Rack::App::Serializer::FormatsBuilder.new
|
20
|
+
serializer.instance_exec do
|
21
|
+
on '.json', 'application/json' do |obj|
|
22
|
+
JSON.dump(obj)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
endpoint = Rack::App::Endpoint.new(
|
27
|
+
:route => {},
|
28
|
+
:app_class => APP,
|
29
|
+
:request_methods => ["GET"],
|
30
|
+
:request_path => '/hello/world/:id',
|
31
|
+
:middleware_builders_blocks => [],
|
32
|
+
:user_defined_logic => proc{ "hy" },
|
33
|
+
:serializer_builder => serializer,
|
34
|
+
:payload => payload,
|
35
|
+
:error_handler => Rack::App::ErrorHandler.new,
|
36
|
+
)
|
37
|
+
|
38
|
+
|
39
|
+
properties = {
|
40
|
+
:request_methods => ::Rack::App::Constants::HTTP::METHODS,
|
41
|
+
:request_path => Rack::App::Utils.join("hello", ::Rack::App::Constants::RACK_BASED_APPLICATION),
|
42
|
+
:application => proc{|env| Rack::Response.new.finish }
|
43
|
+
}
|
44
|
+
|
45
|
+
tree.add(Rack::App::Endpoint.new(properties))
|
46
|
+
|
47
|
+
endpoint = Rack::App::Endpoint.new(
|
48
|
+
:route => {},
|
49
|
+
:app_class => APP,
|
50
|
+
:request_methods => ["GET"],
|
51
|
+
:request_path => '/hello/world/:id',
|
52
|
+
:middleware_builders_blocks => [],
|
53
|
+
:user_defined_logic => proc{ "hy" },
|
54
|
+
:serializer_builder => serializer,
|
55
|
+
:payload => payload,
|
56
|
+
:error_handler => Rack::App::ErrorHandler.new,
|
57
|
+
)
|
58
|
+
|
59
|
+
tree.add(endpoint)
|
60
|
+
pp tree
|
61
|
+
|
62
|
+
require 'rack'
|
63
|
+
puts
|
64
|
+
|
65
|
+
[
|
66
|
+
"/hello/world/123.json",
|
67
|
+
"/hello/world/123",
|
68
|
+
"/hello/world",
|
69
|
+
].each do |path_info|
|
70
|
+
env = Rack::MockRequest.env_for(path_info, :method => 'GET')
|
71
|
+
resp = tree.call(env)
|
72
|
+
|
73
|
+
puts(path_info)
|
74
|
+
p resp.is_a?(Array) && resp.length == 3
|
75
|
+
puts
|
76
|
+
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.11.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: 2017-01-
|
11
|
+
date: 2017-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -124,7 +124,6 @@ files:
|
|
124
124
|
- lib/rack/app/logger.rb
|
125
125
|
- lib/rack/app/middlewares.rb
|
126
126
|
- lib/rack/app/middlewares/configuration.rb
|
127
|
-
- lib/rack/app/middlewares/configuration/path_params_matcher.rb
|
128
127
|
- lib/rack/app/middlewares/header_setter.rb
|
129
128
|
- lib/rack/app/middlewares/hooks.rb
|
130
129
|
- lib/rack/app/middlewares/hooks/after.rb
|
@@ -149,10 +148,13 @@ files:
|
|
149
148
|
- lib/rack/app/request_stream.rb
|
150
149
|
- lib/rack/app/router.rb
|
151
150
|
- lib/rack/app/router/base.rb
|
152
|
-
- lib/rack/app/router/
|
153
|
-
- lib/rack/app/router/
|
154
|
-
- lib/rack/app/router/
|
155
|
-
- lib/rack/app/router/
|
151
|
+
- lib/rack/app/router/tree.rb
|
152
|
+
- lib/rack/app/router/tree/env.rb
|
153
|
+
- lib/rack/app/router/tree/leaf.rb
|
154
|
+
- lib/rack/app/router/tree/leaf/vein.rb
|
155
|
+
- lib/rack/app/router/tree/mounted.rb
|
156
|
+
- lib/rack/app/router/tree/mounted/application.rb
|
157
|
+
- lib/rack/app/router/tree/node.rb
|
156
158
|
- lib/rack/app/serializer.rb
|
157
159
|
- lib/rack/app/serializer/formats_builder.rb
|
158
160
|
- lib/rack/app/singleton_methods.rb
|
@@ -197,6 +199,7 @@ files:
|
|
197
199
|
- spike/method_vs_instance_exec.rb
|
198
200
|
- spike/return_vs_throw.rb
|
199
201
|
- spike/slice_vs_sub.rb
|
202
|
+
- spike/tree.rb
|
200
203
|
- spike/validator_with_minitest.rb
|
201
204
|
- spike/xml.rb
|
202
205
|
- src/Net__HTTP Cheat Sheet.pdf
|
@@ -1,14 +0,0 @@
|
|
1
|
-
class Rack::App::Middlewares::Configuration::PathParamsMatcher
|
2
|
-
|
3
|
-
def initialize(app, path_params)
|
4
|
-
@path_params = path_params
|
5
|
-
@app = app
|
6
|
-
end
|
7
|
-
|
8
|
-
def call(env)
|
9
|
-
env[::Rack::App::Constants::ENV::PATH_PARAMS_MATCHER]= @path_params.dup
|
10
|
-
|
11
|
-
@app.call(env)
|
12
|
-
end
|
13
|
-
|
14
|
-
end
|
@@ -1,170 +0,0 @@
|
|
1
|
-
class Rack::App::Router::Dynamic < Rack::App::Router::Base
|
2
|
-
|
3
|
-
require 'rack/app/router/dynamic/request_path_part_placeholder'
|
4
|
-
DYNAMIC_REQUEST_PATH_PART = RequestPathPartPlaceholder.new('DYNAMIC_REQUEST_PATH_PART')
|
5
|
-
MOUNTED_DIRECTORY = RequestPathPartPlaceholder.new('MOUNTED_DIRECTORY')
|
6
|
-
MOUNTED_APPLICATION = RequestPathPartPlaceholder.new('MOUNTED_APPLICATION')
|
7
|
-
|
8
|
-
protected
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
@http_method_cluster = {}
|
12
|
-
end
|
13
|
-
|
14
|
-
def path_part_is_dynamic?(path_part_str)
|
15
|
-
!!(path_part_str.to_s =~ /^:\w+$/i)
|
16
|
-
end
|
17
|
-
|
18
|
-
def deep_merge!(hash, other_hash)
|
19
|
-
Rack::App::Utils.deep_merge(hash, other_hash)
|
20
|
-
end
|
21
|
-
|
22
|
-
def main_cluster(request_method)
|
23
|
-
(@http_method_cluster[request_method.to_s.upcase] ||= {})
|
24
|
-
end
|
25
|
-
|
26
|
-
def path_part_is_a_mounted_directory?(path_part)
|
27
|
-
path_part == Rack::App::Constants::MOUNTED_DIRECTORY
|
28
|
-
|
29
|
-
(path_part == '**' or path_part == '*')
|
30
|
-
end
|
31
|
-
|
32
|
-
def path_part_is_a_mounted_rack_based_application?(path_part)
|
33
|
-
path_part == Rack::App::Constants::RACK_BASED_APPLICATION
|
34
|
-
end
|
35
|
-
|
36
|
-
def clean_routes!
|
37
|
-
@http_method_cluster.clear
|
38
|
-
end
|
39
|
-
|
40
|
-
def compile_registered_endpoints!
|
41
|
-
endpoints.each do |endpoint|
|
42
|
-
compile_endpoint!(endpoint)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def compile_endpoint!(endpoint)
|
47
|
-
request_method = endpoint.request_method
|
48
|
-
request_path = endpoint.request_path
|
49
|
-
|
50
|
-
clusters_for(request_method) do |current_cluster|
|
51
|
-
|
52
|
-
break_build = false
|
53
|
-
path_params = {}
|
54
|
-
options = {}
|
55
|
-
|
56
|
-
builder = Rack::Builder.new
|
57
|
-
builder.use(Rack::App::Middlewares::Configuration::PathParamsMatcher, path_params)
|
58
|
-
|
59
|
-
request_path_parts = request_path.split('/')
|
60
|
-
request_path_parts.each.with_index do |path_part, index|
|
61
|
-
|
62
|
-
new_cluster_name = if path_part_is_dynamic?(path_part)
|
63
|
-
path_params[index]= path_part.sub(/^:/, '')
|
64
|
-
DYNAMIC_REQUEST_PATH_PART
|
65
|
-
|
66
|
-
elsif path_part_is_a_mounted_directory?(path_part)
|
67
|
-
break_build = true
|
68
|
-
MOUNTED_DIRECTORY
|
69
|
-
|
70
|
-
elsif path_part_is_a_mounted_rack_based_application?(path_part)
|
71
|
-
break_build = true
|
72
|
-
builder.use(
|
73
|
-
Rack::App::Middlewares::PathInfoCutter,
|
74
|
-
calculate_mount_path(request_path_parts)
|
75
|
-
)
|
76
|
-
MOUNTED_APPLICATION
|
77
|
-
|
78
|
-
else
|
79
|
-
path_part
|
80
|
-
end
|
81
|
-
|
82
|
-
current_cluster = (current_cluster[new_cluster_name] ||= {})
|
83
|
-
break if break_build
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
|
-
|
88
|
-
builder.run(as_app(endpoint))
|
89
|
-
current_cluster[:app]= builder.to_app
|
90
|
-
|
91
|
-
current_cluster[:endpoint]= endpoint
|
92
|
-
if current_cluster[:endpoint].respond_to?(:register_path_params_matcher)
|
93
|
-
current_cluster[:endpoint].register_path_params_matcher(path_params)
|
94
|
-
end
|
95
|
-
|
96
|
-
current_cluster[:options]= options
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def calculate_mount_path(request_path_parts)
|
101
|
-
mount_path_parts = (request_path_parts - [Rack::App::Constants::RACK_BASED_APPLICATION, ''])
|
102
|
-
mount_path_parts.empty? ? '' : Rack::App::Utils.join(mount_path_parts)
|
103
|
-
end
|
104
|
-
|
105
|
-
def clusters_for(request_method)
|
106
|
-
if ::Rack::App::Constants::HTTP::METHOD::ANY == request_method
|
107
|
-
supported_http_protocols.each do |cluster_type|
|
108
|
-
yield(main_cluster(cluster_type))
|
109
|
-
end
|
110
|
-
else
|
111
|
-
yield(main_cluster(request_method))
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def supported_http_protocols
|
116
|
-
::Rack::App::Constants::HTTP::METHODS
|
117
|
-
end
|
118
|
-
|
119
|
-
def get_app(env)
|
120
|
-
find_by_path_infos(env) do |path_info|
|
121
|
-
fetch_context(get_request_method(env), path_info)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def fetch_context(request_method, path_info)
|
126
|
-
current_cluster = main_cluster(request_method)
|
127
|
-
|
128
|
-
last_mounted_app = nil
|
129
|
-
last_mounted_directory = nil
|
130
|
-
|
131
|
-
path_parts = path_info.split('/')
|
132
|
-
path_parts << '' if path_parts.empty?
|
133
|
-
path_parts.each do |path_part|
|
134
|
-
|
135
|
-
last_mounted_directory = current_cluster[MOUNTED_DIRECTORY] || last_mounted_directory
|
136
|
-
last_mounted_app = current_cluster[MOUNTED_APPLICATION] || last_mounted_app
|
137
|
-
|
138
|
-
current_cluster = current_cluster[path_part] || current_cluster[DYNAMIC_REQUEST_PATH_PART]
|
139
|
-
|
140
|
-
last_mounted_directory = (current_cluster || {})[MOUNTED_DIRECTORY] || last_mounted_directory
|
141
|
-
last_mounted_app = (current_cluster || {})[MOUNTED_APPLICATION] || last_mounted_app
|
142
|
-
|
143
|
-
if current_cluster.nil?
|
144
|
-
|
145
|
-
|
146
|
-
if last_mounted_directory
|
147
|
-
current_cluster = last_mounted_directory
|
148
|
-
break
|
149
|
-
|
150
|
-
elsif last_mounted_app
|
151
|
-
current_cluster = last_mounted_app
|
152
|
-
break
|
153
|
-
|
154
|
-
else
|
155
|
-
return nil
|
156
|
-
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
end
|
161
|
-
|
162
|
-
return extract_app(current_cluster) || extract_app(last_mounted_app) || extract_app(last_mounted_directory)
|
163
|
-
|
164
|
-
end
|
165
|
-
|
166
|
-
def extract_app(hash)
|
167
|
-
hash.is_a?(Hash) ? hash[:app] : nil
|
168
|
-
end
|
169
|
-
|
170
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
require "rack/response"
|
2
|
-
class Rack::App::Router::NotFound < Rack::App::Router::Base
|
3
|
-
|
4
|
-
protected
|
5
|
-
|
6
|
-
NOT_FOUND_APP = lambda do |env|
|
7
|
-
rack_response = Rack::Response.new
|
8
|
-
rack_response.status = 404
|
9
|
-
rack_response.write('404 Not Found')
|
10
|
-
rack_response.finish
|
11
|
-
end
|
12
|
-
|
13
|
-
def get_app(env)
|
14
|
-
NOT_FOUND_APP
|
15
|
-
end
|
16
|
-
|
17
|
-
def compile_registered_endpoints!
|
18
|
-
end
|
19
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
class Rack::App::Router::Static < Rack::App::Router::Base
|
2
|
-
|
3
|
-
protected
|
4
|
-
|
5
|
-
def get_app(env)
|
6
|
-
request_method= get_request_method(env)
|
7
|
-
find_by_path_infos(env) do |request_path|
|
8
|
-
mapped_endpoint_routes[[request_method, request_path]]
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def mapped_endpoint_routes
|
13
|
-
@mapped_endpoint_routes ||= {}
|
14
|
-
end
|
15
|
-
|
16
|
-
def clean_routes!
|
17
|
-
mapped_endpoint_routes.clear
|
18
|
-
end
|
19
|
-
|
20
|
-
def compile_endpoint!(endpoint)
|
21
|
-
routing_key = [endpoint.request_method, endpoint.request_path]
|
22
|
-
|
23
|
-
mapped_endpoint_routes[routing_key]= as_app(endpoint)
|
24
|
-
end
|
25
|
-
|
26
|
-
def compile_registered_endpoints!
|
27
|
-
endpoints.each do |endpoint|
|
28
|
-
compile_endpoint!(endpoint)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|