rocketio 0.0.0.pre.alpha → 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -2
- data/LICENSE.txt +22 -0
- data/README.md +5 -22
- data/Rakefile +1 -7
- data/lib/rocketio.rb +3 -131
- data/lib/rocketio/version.rb +2 -2
- data/rocketio.gemspec +17 -21
- metadata +11 -146
- data/.travis.yml +0 -3
- data/bin/console +0 -14
- data/bin/setup +0 -7
- data/lib/rocketio/application.rb +0 -31
- data/lib/rocketio/controller.rb +0 -288
- data/lib/rocketio/controller/authentication.rb +0 -141
- data/lib/rocketio/controller/authorization.rb +0 -53
- data/lib/rocketio/controller/cookies.rb +0 -59
- data/lib/rocketio/controller/error_handlers.rb +0 -89
- data/lib/rocketio/controller/filters.rb +0 -119
- data/lib/rocketio/controller/flash.rb +0 -21
- data/lib/rocketio/controller/helpers.rb +0 -438
- data/lib/rocketio/controller/middleware.rb +0 -32
- data/lib/rocketio/controller/render.rb +0 -148
- data/lib/rocketio/controller/render/engine.rb +0 -76
- data/lib/rocketio/controller/render/layout.rb +0 -27
- data/lib/rocketio/controller/render/layouts.rb +0 -85
- data/lib/rocketio/controller/render/templates.rb +0 -83
- data/lib/rocketio/controller/request.rb +0 -115
- data/lib/rocketio/controller/response.rb +0 -84
- data/lib/rocketio/controller/sessions.rb +0 -64
- data/lib/rocketio/controller/token_auth.rb +0 -118
- data/lib/rocketio/controller/websocket.rb +0 -21
- data/lib/rocketio/error_templates/404.html +0 -3
- data/lib/rocketio/error_templates/409.html +0 -7
- data/lib/rocketio/error_templates/500.html +0 -3
- data/lib/rocketio/error_templates/501.html +0 -6
- data/lib/rocketio/error_templates/layout.html +0 -1
- data/lib/rocketio/exceptions.rb +0 -4
- data/lib/rocketio/router.rb +0 -65
- data/lib/rocketio/util.rb +0 -122
- data/test/aliases_test.rb +0 -54
- data/test/authentication_test.rb +0 -307
- data/test/authorization_test.rb +0 -91
- data/test/cache_control_test.rb +0 -268
- data/test/content_type_test.rb +0 -124
- data/test/cookies_test.rb +0 -49
- data/test/error_handlers_test.rb +0 -125
- data/test/etag_test.rb +0 -445
- data/test/filters_test.rb +0 -177
- data/test/halt_test.rb +0 -73
- data/test/helpers_test.rb +0 -171
- data/test/middleware_test.rb +0 -57
- data/test/redirect_test.rb +0 -135
- data/test/render/engine_test.rb +0 -71
- data/test/render/get.erb +0 -1
- data/test/render/items.erb +0 -1
- data/test/render/layout.erb +0 -1
- data/test/render/layout_test.rb +0 -104
- data/test/render/layouts/master.erb +0 -1
- data/test/render/layouts_test.rb +0 -145
- data/test/render/master.erb +0 -1
- data/test/render/post.erb +0 -1
- data/test/render/put.erb +0 -1
- data/test/render/render_test.rb +0 -101
- data/test/render/setup.rb +0 -14
- data/test/render/templates/a/get.erb +0 -1
- data/test/render/templates/master.erb +0 -1
- data/test/render/templates_test.rb +0 -146
- data/test/request_test.rb +0 -105
- data/test/response_test.rb +0 -119
- data/test/routes_test.rb +0 -70
- data/test/sendfile_test.rb +0 -209
- data/test/sessions_test.rb +0 -176
- data/test/setup.rb +0 -59
@@ -1,115 +0,0 @@
|
|
1
|
-
# Copyright (c) 2007, 2008, 2009 Blake Mizerany
|
2
|
-
# Copyright (c) 2010, 2011, 2012, 2013, 2014 Konstantin Haase
|
3
|
-
# Copyright (c) 2015 Slee Woo
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person
|
6
|
-
# obtaining a copy of this software and associated documentation
|
7
|
-
# files (the "Software"), to deal in the Software without
|
8
|
-
# restriction, including without limitation the rights to use,
|
9
|
-
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
-
# copies of the Software, and to permit persons to whom the
|
11
|
-
# Software is furnished to do so, subject to the following
|
12
|
-
# conditions:
|
13
|
-
#
|
14
|
-
# The above copyright notice and this permission notice shall be
|
15
|
-
# included in all copies or substantial portions of the Software.
|
16
|
-
#
|
17
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
19
|
-
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
21
|
-
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
22
|
-
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
23
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
24
|
-
# OTHER DEALINGS IN THE SOFTWARE.
|
25
|
-
|
26
|
-
module RocketIO
|
27
|
-
class Request < Rack::Request
|
28
|
-
|
29
|
-
HEADER_PARAM = /\s*[\w.]+=(?:[\w.]+|"(?:[^"\\]|\\.)*")?\s*/
|
30
|
-
HEADER_VALUE_WITH_PARAMS = /(?:(?:\w+|\*)\/(?:\w+(?:\.|\-|\+)?|\*)*)\s*(?:;#{HEADER_PARAM})*/
|
31
|
-
|
32
|
-
# Returns an array of acceptable media types for the response
|
33
|
-
def accept
|
34
|
-
@__accept__ ||= begin
|
35
|
-
if env.include?(HTTP_ACCEPT) and !(accept = env[HTTP_ACCEPT].to_s).empty?
|
36
|
-
accept.scan(HEADER_VALUE_WITH_PARAMS).map! {|e| AcceptEntry.new(e)}.sort
|
37
|
-
else
|
38
|
-
[AcceptEntry.new('*/*')]
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def accept?(type)
|
44
|
-
preferred_type(type).to_s.include?(type)
|
45
|
-
end
|
46
|
-
|
47
|
-
def preferred_type(*types)
|
48
|
-
accepts = accept # just evaluate once
|
49
|
-
return accepts.first if types.empty?
|
50
|
-
types.flatten!
|
51
|
-
return types.first if accepts.empty?
|
52
|
-
accepts.detect do |pattern|
|
53
|
-
type = types.detect { |t| File.fnmatch(pattern, t) }
|
54
|
-
return type if type
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
alias secure? ssl?
|
59
|
-
|
60
|
-
def forwarded?
|
61
|
-
env.include?(HTTP_X_FORWARDED_HOST)
|
62
|
-
end
|
63
|
-
|
64
|
-
def safe?
|
65
|
-
get? or head? or options? or trace?
|
66
|
-
end
|
67
|
-
|
68
|
-
def idempotent?
|
69
|
-
safe? or put? or delete? or link? or unlink?
|
70
|
-
end
|
71
|
-
|
72
|
-
class AcceptEntry
|
73
|
-
attr_accessor :params
|
74
|
-
attr_reader :entry
|
75
|
-
|
76
|
-
def initialize(entry)
|
77
|
-
params = entry.scan(HEADER_PARAM).map! do |s|
|
78
|
-
key, value = s.strip.split('=', 2)
|
79
|
-
value = value[1..-2].gsub(/\\(.)/, '\1') if value.start_with?('"')
|
80
|
-
[key, value]
|
81
|
-
end
|
82
|
-
|
83
|
-
@entry = entry
|
84
|
-
@type = entry[/[^;]+/].delete(' ')
|
85
|
-
@params = Hash[params]
|
86
|
-
@q = @params.delete('q') { 1.0 }.to_f
|
87
|
-
end
|
88
|
-
|
89
|
-
def <=>(other)
|
90
|
-
other.priority <=> self.priority
|
91
|
-
end
|
92
|
-
|
93
|
-
def priority
|
94
|
-
# We sort in descending order; better matches should be higher.
|
95
|
-
[ @q, -@type.count('*'), @params.size ]
|
96
|
-
end
|
97
|
-
|
98
|
-
def to_str
|
99
|
-
@type
|
100
|
-
end
|
101
|
-
|
102
|
-
def to_s(full = false)
|
103
|
-
full ? entry : to_str
|
104
|
-
end
|
105
|
-
|
106
|
-
def respond_to?(*args)
|
107
|
-
super or to_str.respond_to?(*args)
|
108
|
-
end
|
109
|
-
|
110
|
-
def method_missing(*args, &block)
|
111
|
-
to_str.send(*args, &block)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
# Copyright (c) 2007, 2008, 2009 Blake Mizerany
|
2
|
-
# Copyright (c) 2010, 2011, 2012, 2013, 2014 Konstantin Haase
|
3
|
-
# Copyright (c) 2015 Slee Woo
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person
|
6
|
-
# obtaining a copy of this software and associated documentation
|
7
|
-
# files (the "Software"), to deal in the Software without
|
8
|
-
# restriction, including without limitation the rights to use,
|
9
|
-
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
-
# copies of the Software, and to permit persons to whom the
|
11
|
-
# Software is furnished to do so, subject to the following
|
12
|
-
# conditions:
|
13
|
-
#
|
14
|
-
# The above copyright notice and this permission notice shall be
|
15
|
-
# included in all copies or substantial portions of the Software.
|
16
|
-
#
|
17
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
19
|
-
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
21
|
-
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
22
|
-
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
23
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
24
|
-
# OTHER DEALINGS IN THE SOFTWARE.
|
25
|
-
|
26
|
-
module RocketIO
|
27
|
-
class Response < Rack::Response
|
28
|
-
|
29
|
-
def body= value
|
30
|
-
@body = case value
|
31
|
-
when Rack::Response
|
32
|
-
value.body
|
33
|
-
when Proc
|
34
|
-
def value.each; yield(call) end
|
35
|
-
value
|
36
|
-
when String
|
37
|
-
[value]
|
38
|
-
else
|
39
|
-
value
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def empty_body?
|
44
|
-
@body == EMPTY_ARRAY || @body.nil?
|
45
|
-
end
|
46
|
-
|
47
|
-
def each
|
48
|
-
block_given? ? super : enum_for(:each)
|
49
|
-
end
|
50
|
-
|
51
|
-
def finish
|
52
|
-
headers[CONTENT_TYPE] ||= DEFAULT_CONTENT_TYPE
|
53
|
-
|
54
|
-
if drop_content_info?
|
55
|
-
headers.delete(CONTENT_LENGTH)
|
56
|
-
headers.delete(CONTENT_TYPE)
|
57
|
-
end
|
58
|
-
|
59
|
-
if drop_body?
|
60
|
-
close
|
61
|
-
self.body = EMPTY_ARRAY
|
62
|
-
end
|
63
|
-
|
64
|
-
[status.to_i, headers, self.body]
|
65
|
-
end
|
66
|
-
|
67
|
-
def precondition_failed?
|
68
|
-
status.to_i == 412
|
69
|
-
end
|
70
|
-
|
71
|
-
def not_modified?
|
72
|
-
status.to_i == 304
|
73
|
-
end
|
74
|
-
|
75
|
-
private
|
76
|
-
def drop_content_info?
|
77
|
-
status.to_i / 100 == 1 || drop_body?
|
78
|
-
end
|
79
|
-
|
80
|
-
def drop_body?
|
81
|
-
DROP_BODY_RESPONSES[status.to_i]
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
module RocketIO
|
2
|
-
class Controller
|
3
|
-
|
4
|
-
# setup sessions.
|
5
|
-
# there are 2 setups out of the box:
|
6
|
-
# - cookies
|
7
|
-
# - memcache
|
8
|
-
# you can also use your own setup
|
9
|
-
#
|
10
|
-
# @note to disable sessions for some controller set sessions to nil or false
|
11
|
-
#
|
12
|
-
# @example keep sessions in cookies
|
13
|
-
# sessions :cookies
|
14
|
-
#
|
15
|
-
# @example keep sessions in cookies using custom options
|
16
|
-
# sessions :cookies, secret: 'someSecret', domain: 'some.domain'
|
17
|
-
#
|
18
|
-
# @example keep sessions in memcache
|
19
|
-
# sessions :memcache
|
20
|
-
#
|
21
|
-
# @example use a custom setup, i.e. github.com/migrs/rack-session-mongo
|
22
|
-
# $ gem install rack-session-mongo
|
23
|
-
#
|
24
|
-
# require 'rack/session/mongo'
|
25
|
-
#
|
26
|
-
# class Pages < RocketIO::Controller
|
27
|
-
# sessions Rack::Session::Mongo
|
28
|
-
# end
|
29
|
-
#
|
30
|
-
# @example disable sessions for current controller
|
31
|
-
# sessions nil # or false
|
32
|
-
#
|
33
|
-
# @param pool [Symbol, Class]
|
34
|
-
# @param opts [Hash]
|
35
|
-
#
|
36
|
-
def self.sessions pool = (noargs = true; nil), opts = {}
|
37
|
-
@__sessions__ = if pool.nil? || pool == false
|
38
|
-
nil
|
39
|
-
else
|
40
|
-
if pool == :cookies && opts[:secret].nil?
|
41
|
-
opts[:secret] = ::Digest::MD5.hexdigest([Time.now.to_f, rand]*'')
|
42
|
-
end
|
43
|
-
pool = case pool
|
44
|
-
when :cookies
|
45
|
-
::Rack::Session::Cookie
|
46
|
-
when :memcache
|
47
|
-
::Rack::Session::Memcache
|
48
|
-
else
|
49
|
-
pool
|
50
|
-
end
|
51
|
-
[pool, opts]
|
52
|
-
end
|
53
|
-
define_sessions_methods
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.define_sessions_methods source = self
|
57
|
-
return unless source.instance_variables.include?(:@__sessions__)
|
58
|
-
sessions = source.instance_variable_get(:@__sessions__)
|
59
|
-
define_method(:sessions) {sessions}
|
60
|
-
end
|
61
|
-
|
62
|
-
def sessions; end
|
63
|
-
end
|
64
|
-
end
|
@@ -1,118 +0,0 @@
|
|
1
|
-
# Copyright (c) 2004-2015 David Heinemeier Hansson
|
2
|
-
# Copyright (c) 2015 Slee Woo
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
-
# a copy of this software and associated documentation files (the
|
6
|
-
# "Software"), to deal in the Software without restriction, including
|
7
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
-
# the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be
|
13
|
-
# included in all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
-
|
23
|
-
module RocketIO
|
24
|
-
module TokenAuth
|
25
|
-
extend self
|
26
|
-
|
27
|
-
TOKEN_KEY = 'token='.freeze
|
28
|
-
TOKEN_REGEX = /^Token /
|
29
|
-
AUTHN_PAIR_DELIMITERS = /(?:,|;|\t+)/
|
30
|
-
|
31
|
-
HTTP_AUTHORIZATION = 'HTTP_AUTHORIZATION'.freeze
|
32
|
-
X_HTTP_AUTHORIZATION_I = 'X-HTTP_AUTHORIZATION'.freeze
|
33
|
-
X_HTTP_AUTHORIZATION_II = 'X_HTTP_AUTHORIZATION'.freeze
|
34
|
-
REDIRECT_X_HTTP_AUTHORIZATION = 'REDIRECT_X_HTTP_AUTHORIZATION'.freeze
|
35
|
-
|
36
|
-
WWW_AUTHENTICATE = 'WWW-Authenticate'.freeze
|
37
|
-
TOKEN_REALM_FORMAT = 'Token realm="%s"'.freeze
|
38
|
-
ACCESS_DENIED = "HTTP Token: Access denied.\n".freeze
|
39
|
-
|
40
|
-
# If token Authorization header is present, call the login
|
41
|
-
# procedure with the present token and options.
|
42
|
-
#
|
43
|
-
# @return the return value of given block if a token is found
|
44
|
-
# @return nil if no token is found
|
45
|
-
def authenticate env
|
46
|
-
token, options = token_and_options(env)
|
47
|
-
return if token.nil? || token.empty?
|
48
|
-
yield(token, options)
|
49
|
-
end
|
50
|
-
|
51
|
-
# Parses the token and options out of the token authorization header. If
|
52
|
-
# the header looks like this:
|
53
|
-
# Authorization: Token token="abc", nonce="def"
|
54
|
-
# Then the returned token is "abc", and the options is {nonce: "def"}
|
55
|
-
#
|
56
|
-
# @return [Array] if a token is present
|
57
|
-
# @return nil if no token is found
|
58
|
-
def token_and_options env
|
59
|
-
return unless authorization_request = authorization?(env)
|
60
|
-
return unless authorization_request[TOKEN_REGEX]
|
61
|
-
params = token_params_from(authorization_request)
|
62
|
-
[params.shift[1], RocketIO.indifferent_params(Hash[params])]
|
63
|
-
end
|
64
|
-
|
65
|
-
# Returns the authorization header regardless of whether it was specified directly or through one of the
|
66
|
-
# proxy alternatives.
|
67
|
-
def authorization? env
|
68
|
-
env[HTTP_AUTHORIZATION] ||
|
69
|
-
env[X_HTTP_AUTHORIZATION_I] ||
|
70
|
-
env[X_HTTP_AUTHORIZATION_II] ||
|
71
|
-
env[REDIRECT_X_HTTP_AUTHORIZATION]
|
72
|
-
end
|
73
|
-
|
74
|
-
def token_params_from auth
|
75
|
-
rewrite_param_values(params_array_from(raw_params(auth)))
|
76
|
-
end
|
77
|
-
|
78
|
-
# Takes raw_params and turns it into an array of parameters
|
79
|
-
#
|
80
|
-
# @param raw_params [Array]
|
81
|
-
# @return [Array]
|
82
|
-
def params_array_from raw_params
|
83
|
-
raw_params.map { |param| param.split %r/=(.+)?/ }
|
84
|
-
end
|
85
|
-
|
86
|
-
# This removes the `"` characters wrapping the value.
|
87
|
-
#
|
88
|
-
# @param array_params [Array]
|
89
|
-
def rewrite_param_values array_params
|
90
|
-
array_params.each { |param| (param[1] || "").gsub! %r/^"|"$/, '' }
|
91
|
-
end
|
92
|
-
|
93
|
-
# This method takes an authorization body and splits up the key-value
|
94
|
-
# pairs by the standardized `:`, `;`, or `\t`
|
95
|
-
#
|
96
|
-
# @param auth [String]
|
97
|
-
# @return [Array]
|
98
|
-
def raw_params auth
|
99
|
-
_raw_params = auth.sub(TOKEN_REGEX, '').split(/\s*#{AUTHN_PAIR_DELIMITERS}\s*/)
|
100
|
-
unless _raw_params.first =~ %r{\A#{TOKEN_KEY}}
|
101
|
-
_raw_params[0] = [TOKEN_KEY, _raw_params.first]*''
|
102
|
-
end
|
103
|
-
_raw_params
|
104
|
-
end
|
105
|
-
|
106
|
-
# Sets a WWW-Authenticate to let the client know a token is desired.
|
107
|
-
#
|
108
|
-
# @param realm [String]
|
109
|
-
# @return [Array]
|
110
|
-
def authentication_request realm
|
111
|
-
[
|
112
|
-
401,
|
113
|
-
{WWW_AUTHENTICATE => TOKEN_REALM_FORMAT % realm.tr('"', '')},
|
114
|
-
[ACCESS_DENIED]
|
115
|
-
]
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module RocketIO
|
2
|
-
class Controller
|
3
|
-
|
4
|
-
def websocket?
|
5
|
-
@__is_websocket__ ||= websocket_connection? && websocket_upgrade? ? 1 : 0
|
6
|
-
@__is_websocket__ == 1
|
7
|
-
end
|
8
|
-
|
9
|
-
def websocket_connection?
|
10
|
-
env[RocketIO::HTTP_CONNECTION].to_s.downcase.split(/ *, */).include?(RocketIO::UPGRADE)
|
11
|
-
end
|
12
|
-
|
13
|
-
def websocket_upgrade?
|
14
|
-
env[RocketIO::HTTP_UPGRADE].to_s.downcase == RocketIO::WEBSOCKET
|
15
|
-
end
|
16
|
-
|
17
|
-
def websocket_response
|
18
|
-
[-1, {}, []]
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1 +0,0 @@
|
|
1
|
-
{{{ yield }}}
|
data/lib/rocketio/exceptions.rb
DELETED
data/lib/rocketio/router.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
module RocketIO
|
2
|
-
class Router
|
3
|
-
ROOT_PATH_PIECES = [''.freeze].freeze
|
4
|
-
attr_reader :controllers, :routes
|
5
|
-
|
6
|
-
def initialize *controllers
|
7
|
-
@controllers = controllers.flatten.compact.uniq
|
8
|
-
@routes = build_routes
|
9
|
-
freeze!
|
10
|
-
end
|
11
|
-
|
12
|
-
def resolve_path path
|
13
|
-
controllers = @routes
|
14
|
-
pieces = path_pieces(path)
|
15
|
-
depth = -1
|
16
|
-
controller = nil
|
17
|
-
offset = 0
|
18
|
-
while controllers = controllers[pieces[depth += 1]]
|
19
|
-
next unless controllers[0]
|
20
|
-
controller = controllers[0]
|
21
|
-
offset = depth + 1
|
22
|
-
end
|
23
|
-
[controller, pieces[offset .. -1]]
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
# split given path into an array
|
28
|
-
#
|
29
|
-
# @example /a/b/c
|
30
|
-
# ["", a", "b", "c"]
|
31
|
-
#
|
32
|
-
# @param path [String]
|
33
|
-
# @return [Array]
|
34
|
-
#
|
35
|
-
def path_pieces path
|
36
|
-
return ROOT_PATH_PIECES if path == SLASH # that's root path, /
|
37
|
-
path.to_s.split(/\/+/)
|
38
|
-
end
|
39
|
-
|
40
|
-
# building a routing tree
|
41
|
-
#
|
42
|
-
# @return [Hash]
|
43
|
-
#
|
44
|
-
def build_routes
|
45
|
-
map = {}
|
46
|
-
@controllers.each do |controller|
|
47
|
-
[controller.url, *controller.aliases].each do |url|
|
48
|
-
depth = 0
|
49
|
-
pieces = path_pieces(url)
|
50
|
-
pieces.inject(map) do |map,chunk|
|
51
|
-
map[chunk] ||= {}
|
52
|
-
map[chunk][0] = controller if pieces.size == (depth += 1)
|
53
|
-
map[chunk]
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
map
|
58
|
-
end
|
59
|
-
|
60
|
-
# freezing the application cause modifying it at runtime may blow the universe
|
61
|
-
def freeze!
|
62
|
-
self.freeze
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|