rack-app 5.10.2 → 5.11.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/.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
|