rocketio 0.0.0 → 0.0.1
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/.gitignore +2 -5
- data/.pryrc +2 -0
- data/.travis.yml +3 -0
- data/README.md +22 -5
- data/Rakefile +7 -1
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/rocketio.rb +131 -3
- data/lib/rocketio/application.rb +31 -0
- data/lib/rocketio/controller.rb +288 -0
- data/lib/rocketio/controller/authentication.rb +141 -0
- data/lib/rocketio/controller/authorization.rb +53 -0
- data/lib/rocketio/controller/cookies.rb +59 -0
- data/lib/rocketio/controller/error_handlers.rb +89 -0
- data/lib/rocketio/controller/filters.rb +119 -0
- data/lib/rocketio/controller/flash.rb +21 -0
- data/lib/rocketio/controller/helpers.rb +438 -0
- data/lib/rocketio/controller/middleware.rb +32 -0
- data/lib/rocketio/controller/render.rb +148 -0
- data/lib/rocketio/controller/render/engine.rb +76 -0
- data/lib/rocketio/controller/render/layout.rb +27 -0
- data/lib/rocketio/controller/render/layouts.rb +85 -0
- data/lib/rocketio/controller/render/templates.rb +83 -0
- data/lib/rocketio/controller/request.rb +115 -0
- data/lib/rocketio/controller/response.rb +84 -0
- data/lib/rocketio/controller/sessions.rb +64 -0
- data/lib/rocketio/controller/token_auth.rb +118 -0
- data/lib/rocketio/controller/websocket.rb +21 -0
- data/lib/rocketio/error_templates/404.html +3 -0
- data/lib/rocketio/error_templates/409.html +7 -0
- data/lib/rocketio/error_templates/500.html +3 -0
- data/lib/rocketio/error_templates/501.html +6 -0
- data/lib/rocketio/error_templates/layout.html +1 -0
- data/lib/rocketio/exceptions.rb +4 -0
- data/lib/rocketio/router.rb +65 -0
- data/lib/rocketio/util.rb +122 -0
- data/lib/rocketio/version.rb +2 -2
- data/rocketio.gemspec +21 -17
- data/test/aliases_test.rb +54 -0
- data/test/authentication_test.rb +307 -0
- data/test/authorization_test.rb +91 -0
- data/test/cache_control_test.rb +268 -0
- data/test/content_type_test.rb +124 -0
- data/test/cookies_test.rb +49 -0
- data/test/error_handlers_test.rb +125 -0
- data/test/etag_test.rb +445 -0
- data/test/filters_test.rb +177 -0
- data/test/halt_test.rb +73 -0
- data/test/helpers_test.rb +171 -0
- data/test/middleware_test.rb +57 -0
- data/test/redirect_test.rb +135 -0
- data/test/render/engine_test.rb +71 -0
- data/test/render/get.erb +1 -0
- data/test/render/items.erb +1 -0
- data/test/render/layout.erb +1 -0
- data/test/render/layout_test.rb +104 -0
- data/test/render/layouts/master.erb +1 -0
- data/test/render/layouts_test.rb +145 -0
- data/test/render/master.erb +1 -0
- data/test/render/post.erb +1 -0
- data/test/render/put.erb +1 -0
- data/test/render/render_test.rb +101 -0
- data/test/render/setup.rb +14 -0
- data/test/render/templates/a/get.erb +1 -0
- data/test/render/templates/master.erb +1 -0
- data/test/render/templates_test.rb +146 -0
- data/test/request_test.rb +105 -0
- data/test/response_test.rb +119 -0
- data/test/routes_test.rb +70 -0
- data/test/sendfile_test.rb +209 -0
- data/test/sessions_test.rb +176 -0
- data/test/setup.rb +59 -0
- metadata +144 -9
- data/LICENSE.txt +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51fdeef94b06a674a04316766088ddff1366635a
|
4
|
+
data.tar.gz: 8804955067cd66dbbbe011f53481484f69d072fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 178ba8589ad57652cd19595dbddef2fe6d4b06e3aa999cc7ea170eafffbb59f9e96e385fa598b11df833ffbea49f241d5a8fe3c8f93eeb8f18d0f658b16db9c3
|
7
|
+
data.tar.gz: c86a96c3d50ba9bc0cb466958550a1b06945f3f040d29225e1e0653b45bb132d2b0fd0dd799b01c58761255a9d54a560667a74888e20383539405fb417630e7f
|
data/.gitignore
CHANGED
data/.pryrc
ADDED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,6 +1,23 @@
|
|
1
|
-
#
|
1
|
+
# RocketIO
|
2
2
|
|
3
|
-
|
3
|
+
#### Simple, Fast, Scalable Micro-Web-Framework for Ruby
|
4
|
+
|
5
|
+
Sample controller:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
class Users < RocketIO::Controller
|
9
|
+
|
10
|
+
# serving GET requests
|
11
|
+
def get
|
12
|
+
end
|
13
|
+
|
14
|
+
# serving POST requests
|
15
|
+
def post
|
16
|
+
end
|
17
|
+
|
18
|
+
# same for other request methods
|
19
|
+
end
|
20
|
+
```
|
4
21
|
|
5
22
|
## Installation
|
6
23
|
|
@@ -18,13 +35,13 @@ Or install it yourself as:
|
|
18
35
|
|
19
36
|
$ gem install rocketio
|
20
37
|
|
21
|
-
##
|
38
|
+
## Controllers
|
39
|
+
|
22
40
|
|
23
|
-
TODO: Write usage instructions here
|
24
41
|
|
25
42
|
## Contributing
|
26
43
|
|
27
|
-
1. Fork it ( https://github.com/
|
44
|
+
1. Fork it ( https://github.com/sleewoo/rocketio/fork )
|
28
45
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
46
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
47
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/Rakefile
CHANGED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "rocketio"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/lib/rocketio.rb
CHANGED
@@ -1,5 +1,133 @@
|
|
1
|
-
|
1
|
+
# core
|
2
|
+
require 'uri'
|
3
|
+
require 'stringio'
|
4
|
+
require 'json'
|
5
|
+
require 'cgi'
|
6
|
+
require 'digest'
|
7
|
+
require 'forwardable'
|
8
|
+
# gems
|
9
|
+
require 'rack'
|
10
|
+
require 'mustache'
|
11
|
+
require 'tilt'
|
2
12
|
|
3
|
-
module
|
4
|
-
|
13
|
+
module RocketIO
|
14
|
+
extend self
|
15
|
+
|
16
|
+
ENVIRONMENTS = {
|
17
|
+
'development' => :development,
|
18
|
+
'testing' => :testing,
|
19
|
+
'stage' => :stage,
|
20
|
+
'production' => :production
|
21
|
+
}.freeze
|
22
|
+
|
23
|
+
environment = ENV['APP_ENV'] || ENV['RACK_ENV'] || ENVIRONMENTS.keys[0]
|
24
|
+
unless ENVIRONMENT = ENVIRONMENTS[environment]
|
25
|
+
raise(StandardError, '%s environment not supported. Use one of %s' % [environment.inspect, ENVIRONMENTS.keys*', '])
|
26
|
+
end
|
27
|
+
|
28
|
+
def environment
|
29
|
+
ENVIRONMENT
|
30
|
+
end
|
31
|
+
|
32
|
+
ENVIRONMENTS.each_value do |env|
|
33
|
+
define_method(env.to_s + '?') {ENVIRONMENT == env}
|
34
|
+
end
|
35
|
+
|
36
|
+
GET = 'GET'.freeze
|
37
|
+
POST = 'POST'.freeze
|
38
|
+
PUT = 'PUT'.freeze
|
39
|
+
DELETE = 'DELETE'.freeze
|
40
|
+
HEAD = 'HEAD'.freeze
|
41
|
+
|
42
|
+
REQUEST_METHODS = {
|
43
|
+
GET => :get,
|
44
|
+
POST => :post,
|
45
|
+
PUT => :put,
|
46
|
+
DELETE => :delete,
|
47
|
+
HEAD => :head
|
48
|
+
}.freeze
|
49
|
+
|
50
|
+
EMPTY_STRING = ''.freeze
|
51
|
+
EMPTY_STRING_PROC = proc {RocketIO::EMPTY_STRING}
|
52
|
+
EMPTY_ARRAY = [].freeze
|
53
|
+
EMPTY_HASH = {}.freeze
|
54
|
+
|
55
|
+
SLASH = '/'.freeze
|
56
|
+
QUERY_PREFIX = '?'.freeze
|
57
|
+
|
58
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
59
|
+
DEFAULT_CONTENT_TYPE = 'text/html'.freeze
|
60
|
+
CONTENT_LENGTH = 'Content-Length'.freeze
|
61
|
+
CONTENT_DISPOSITION = 'Content-Disposition'.freeze
|
62
|
+
APPLICATION_OCTET_STREAM = 'application/octet-stream'.freeze
|
63
|
+
DEFAULT_AUTH_REALM = 'AccessRestricted'.freeze
|
64
|
+
DEFAULT_TOKEN_AUTH_REALM = 'Application'.freeze
|
65
|
+
|
66
|
+
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
|
67
|
+
PATH_INFO = 'PATH_INFO'.freeze
|
68
|
+
HTTP_ACCEPT = 'HTTP_ACCEPT'.freeze
|
69
|
+
REMOTE_USER = 'REMOTE_USER'.freeze
|
70
|
+
|
71
|
+
HTTP_CONNECTION = 'HTTP_CONNECTION'.freeze
|
72
|
+
HTTP_AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION'].map(&:freeze).freeze
|
73
|
+
HTTP_AUTHORIZATION_MOCKS = {
|
74
|
+
basic: 'Basic Og=='.freeze,
|
75
|
+
digest: 'Digest opaque="", qop="auth", uri="/"'.freeze
|
76
|
+
}.freeze
|
77
|
+
HTTP_UPGRADE = 'HTTP_UPGRADE'.freeze
|
78
|
+
UPGRADE = 'upgrade'.freeze
|
79
|
+
WEBSOCKET = 'websocket'.freeze
|
80
|
+
HTTP_1_1 = 'HTTP/1.1'.freeze
|
81
|
+
HTTP_VERSION = 'HTTP_VERSION'.freeze
|
82
|
+
HTTP_X_FORWARDED_HOST = 'HTTP_X_FORWARDED_HOST'.freeze
|
83
|
+
HTTP_IF_MATCH = 'HTTP_IF_MATCH'.freeze
|
84
|
+
HTTP_IF_NONE_MATCH = 'HTTP_IF_NONE_MATCH'.freeze
|
85
|
+
HTTP_IF_MODIFIED_SINCE = 'HTTP_IF_MODIFIED_SINCE'.freeze
|
86
|
+
HTTP_IF_UNMODIFIED_SINCE = 'HTTP_IF_UNMODIFIED_SINCE'.freeze
|
87
|
+
HTTP_X_REQUESTED_WITH = 'HTTP_X_REQUESTED_WITH'.freeze
|
88
|
+
XML_HTTP_REQUEST = 'XMLHttpRequest'.freeze
|
89
|
+
|
90
|
+
LOCATION = 'Location'.freeze
|
91
|
+
CACHE_CONTROL = 'Cache-Control'.freeze
|
92
|
+
EXPIRES = 'Expires'.freeze
|
93
|
+
LAST_MODIFIED = 'Last-Modified'.freeze
|
94
|
+
ETAG = 'ETag'.freeze
|
95
|
+
ETAG_KINDS = [:strong, :weak].freeze
|
96
|
+
|
97
|
+
DROP_BODY_RESPONSES = {204 => true, 205 => true, 304 => true}.freeze
|
98
|
+
|
99
|
+
ERROR_TEMPLATES = begin
|
100
|
+
path = File.expand_path('../rocketio/error_templates/', __FILE__)
|
101
|
+
templates = {layout: Class.new(Mustache) {self.template = File.read(path + '/layout.html').freeze}}
|
102
|
+
Dir[path + '/*.html'].each_with_object(templates) do |file,templates|
|
103
|
+
next if file =~ /layout\.html\z/
|
104
|
+
template = File.basename(file, File.extname(file)).to_i
|
105
|
+
templates[template] = Class.new(Mustache) {self.template = File.read(file).freeze}
|
106
|
+
end
|
107
|
+
end.freeze
|
108
|
+
|
109
|
+
BEFORE_FORMAT = 'before_%s'.freeze
|
110
|
+
AROUND_FORMAT = 'around_%s'.freeze
|
111
|
+
AFTER_FORMAT = 'after_%s'.freeze
|
112
|
+
ROUTE_INSPECT_FORMAT = '#<RocketIO::Route:%s>'.freeze
|
113
|
+
ENGINE_CONST_FORMAT = '%sTemplate'.freeze
|
114
|
+
TEMPLATE_PATH_FORMAT = '%s/%s.%s'.freeze
|
115
|
+
|
116
|
+
FOUND_TEMPLATES = {}
|
117
|
+
READ_TEMPLATES = {}
|
118
|
+
COMPILED_TEMPLATES = {}
|
119
|
+
|
120
|
+
DEFAULT_ENGINE = [Tilt::ERBTemplate, [].freeze].freeze
|
121
|
+
|
122
|
+
def controllers
|
123
|
+
@controllers ||= []
|
124
|
+
end
|
5
125
|
end
|
126
|
+
|
127
|
+
require 'rocketio/util'
|
128
|
+
require 'rocketio/exceptions'
|
129
|
+
require 'rocketio/controller'
|
130
|
+
require 'rocketio/router'
|
131
|
+
require 'rocketio/application'
|
132
|
+
|
133
|
+
RocketIO::Controller.map(RocketIO::SLASH)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RocketIO
|
2
|
+
class Application
|
3
|
+
|
4
|
+
def initialize *args, &block
|
5
|
+
controllers = args.empty? ? RocketIO.controllers : args.flatten
|
6
|
+
if block
|
7
|
+
controllers.each {|c| c.class_exec {define_method(:call!, block)}}
|
8
|
+
end
|
9
|
+
@router = Router.new(*controllers)
|
10
|
+
end
|
11
|
+
|
12
|
+
def call env
|
13
|
+
catch :__response__ do # catch 404 errors and potential `halt` calls from middleware
|
14
|
+
controller, path_params = @router.resolve_path(env[PATH_INFO])
|
15
|
+
|
16
|
+
unless controller
|
17
|
+
controller = RocketIO::Controller.initialize_controller
|
18
|
+
controller.env = env
|
19
|
+
controller.error(404)
|
20
|
+
end
|
21
|
+
|
22
|
+
controller = controller.initialize_controller(REQUEST_METHODS[env[REQUEST_METHOD]], path_params)
|
23
|
+
chain = controller.middleware.reverse.inject(controller) {|app,ware| ware.call(app)}
|
24
|
+
if controller.sessions
|
25
|
+
chain = controller.sessions[0].new(chain, controller.sessions[1])
|
26
|
+
end
|
27
|
+
chain.call(env)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,288 @@
|
|
1
|
+
module RocketIO
|
2
|
+
class Controller
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegators 'self.class', :url, :dirname, :parameters_policy
|
6
|
+
def_delegators :request, :session, :request_method
|
7
|
+
def_delegators RocketIO, :indifferent_params, :indifferent_hash, :mime_type, :engine_const, :engine_class
|
8
|
+
def_delegators CGI, :escape_html
|
9
|
+
|
10
|
+
# defining get, post etc. methods that will be called
|
11
|
+
# when a request matches current controller and appropriate request method used.
|
12
|
+
#
|
13
|
+
# by default all requests, except HEAD, will return a NotImplementedError.
|
14
|
+
# override the methods you need to be handled by controller.
|
15
|
+
#
|
16
|
+
RocketIO::REQUEST_METHODS.each_value do |verb|
|
17
|
+
define_method(verb) {|*| error(501)}
|
18
|
+
end
|
19
|
+
def head(*); end
|
20
|
+
|
21
|
+
# call requested method.
|
22
|
+
# also call #before, #around and #after filters.
|
23
|
+
#
|
24
|
+
# @param [Hash] env
|
25
|
+
# @return [Rack::Response]
|
26
|
+
#
|
27
|
+
def call env
|
28
|
+
catch :__response__ do
|
29
|
+
begin
|
30
|
+
self.env = env
|
31
|
+
validate_or_request_authentication_if_needed
|
32
|
+
validate_or_request_authorization_if_needed
|
33
|
+
validate_parameters
|
34
|
+
|
35
|
+
call! proc {
|
36
|
+
invoke_before_filter
|
37
|
+
invoke_around_filter proc {
|
38
|
+
response.body = public_send(requested_method, *path_params_array)
|
39
|
+
}
|
40
|
+
invoke_after_filter
|
41
|
+
}
|
42
|
+
response.body ||= RocketIO::EMPTY_ARRAY
|
43
|
+
response.body = [] if head? # dropping body on HEAD requests
|
44
|
+
response.finish
|
45
|
+
rescue Exception => e
|
46
|
+
if RocketIO.development?
|
47
|
+
puts "\e[0;31m%s\e[0m" % e.inspect
|
48
|
+
e.backtrace.each {|l| puts " \e[0;36m%s\e[0m" % l}
|
49
|
+
end
|
50
|
+
error(500, e)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def call! app
|
56
|
+
app.call
|
57
|
+
end
|
58
|
+
|
59
|
+
def env= env
|
60
|
+
@__env__ = env
|
61
|
+
end
|
62
|
+
|
63
|
+
def env
|
64
|
+
@__env__
|
65
|
+
end
|
66
|
+
|
67
|
+
def validate_parameters
|
68
|
+
# enforce policy only if a method defined for current request method
|
69
|
+
# cause stock REST methods accepting any number of arguments
|
70
|
+
return unless policy = parameters_policy[requested_method]
|
71
|
+
|
72
|
+
if path_params_array.size >= policy[:min]
|
73
|
+
return if policy[:max] == :* || path_params_array.size <= policy[:max]
|
74
|
+
end
|
75
|
+
|
76
|
+
error(409)
|
77
|
+
end
|
78
|
+
|
79
|
+
def path_params
|
80
|
+
@__path_params__ ||= begin
|
81
|
+
rangemap = self.class.path_params[requested_method] ||
|
82
|
+
raise(StandardError, 'No path_params map found for %s method' % requested_method)
|
83
|
+
indifferent_params(rangemap.each_with_object({}) {|(m,r),o|
|
84
|
+
o[m] = r.min == r.max ? path_params_array[r.min] : path_params_array[r]
|
85
|
+
}).freeze
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def path_params_array
|
90
|
+
@__path_params_array__
|
91
|
+
end
|
92
|
+
|
93
|
+
def params
|
94
|
+
@__params__ ||= indifferent_params(request.params)
|
95
|
+
end
|
96
|
+
|
97
|
+
def request
|
98
|
+
@__request__ ||= RocketIO::Request.new(env)
|
99
|
+
end
|
100
|
+
|
101
|
+
def response
|
102
|
+
@__response__ ||= RocketIO::Response.new
|
103
|
+
end
|
104
|
+
|
105
|
+
def requested_method
|
106
|
+
@__requested_method__ ||= RocketIO::REQUEST_METHODS[request_method]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class << Controller
|
111
|
+
|
112
|
+
def inherit setup, opts = {}
|
113
|
+
opts[:from] || raise(ArgumentError, ':from option is required')
|
114
|
+
__send__(:"define_#{setup}_methods", opts[:from])
|
115
|
+
end
|
116
|
+
|
117
|
+
def inherited base
|
118
|
+
# registering new controller
|
119
|
+
RocketIO.controllers.push(base)
|
120
|
+
|
121
|
+
# new controller inherits all setups from superclass
|
122
|
+
base.inherit :before, from: self
|
123
|
+
base.inherit :around, from: self
|
124
|
+
base.inherit :after, from: self
|
125
|
+
|
126
|
+
base.inherit :basic_auth, from: self
|
127
|
+
base.inherit :digest_auth, from: self
|
128
|
+
base.inherit :token_auth, from: self
|
129
|
+
|
130
|
+
base.inherit :error_handlers, from: self
|
131
|
+
base.inherit :middleware, from: self
|
132
|
+
base.inherit :sessions, from: self
|
133
|
+
|
134
|
+
base.inherit :engine, from: self
|
135
|
+
base.inherit :layout, from: self
|
136
|
+
base.inherit :layouts, from: self
|
137
|
+
base.inherit :templates, from: self
|
138
|
+
|
139
|
+
# removing superclass name from new controller name
|
140
|
+
path = RocketIO.underscore(base.name.to_s.sub(self.name.to_s + '::', '').gsub('::', '/'))
|
141
|
+
|
142
|
+
# new controller uses for URL its underscored name prefixed by superclass URL
|
143
|
+
base.map RocketIO.rootify_path(url, path)
|
144
|
+
|
145
|
+
# setting dirname for new controller
|
146
|
+
base.instance_variable_set(:@__dirname__, RocketIO.caller_to_dirname(caller).freeze)
|
147
|
+
end
|
148
|
+
|
149
|
+
# by default controllers will use underscored name for base URL.
|
150
|
+
# this method allow to set a custom base URL.
|
151
|
+
#
|
152
|
+
# @example Users::Register will listen on /users/register by default
|
153
|
+
# class Users
|
154
|
+
# class Register < RocketIO
|
155
|
+
#
|
156
|
+
# end
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# @note
|
160
|
+
#
|
161
|
+
# @example make Users::Register to listen on /users/join rather than /users/register
|
162
|
+
#
|
163
|
+
# class Users
|
164
|
+
# class Register < RocketIO
|
165
|
+
# map :join
|
166
|
+
#
|
167
|
+
# end
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# @note if given URL starts with a slash it will ignore class name and set URL as is
|
171
|
+
#
|
172
|
+
# @example make Users::Register to listen on /members/join
|
173
|
+
#
|
174
|
+
# class Users < RocketIO
|
175
|
+
# class Register < self
|
176
|
+
# map '/members/join'
|
177
|
+
#
|
178
|
+
# end
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
# @param path [String || Symbol]
|
182
|
+
#
|
183
|
+
def map path
|
184
|
+
path = path.to_s
|
185
|
+
@__url__ = if path =~ /\A\//
|
186
|
+
path
|
187
|
+
else
|
188
|
+
if superclass == Object
|
189
|
+
RocketIO.rootify_path(path)
|
190
|
+
else
|
191
|
+
RocketIO.rootify_path(superclass.url, path)
|
192
|
+
end
|
193
|
+
end.freeze
|
194
|
+
end
|
195
|
+
|
196
|
+
# allow controllers to serve multiple URLs
|
197
|
+
#
|
198
|
+
# @param path [String || Symbol]
|
199
|
+
#
|
200
|
+
def alias_url path
|
201
|
+
path = path.to_s
|
202
|
+
path = if path =~ /\A\//
|
203
|
+
path
|
204
|
+
else
|
205
|
+
if superclass == Object
|
206
|
+
RocketIO.rootify_path(path)
|
207
|
+
else
|
208
|
+
RocketIO.rootify_path(superclass.url, path)
|
209
|
+
end
|
210
|
+
end.freeze
|
211
|
+
aliases.push(path)
|
212
|
+
end
|
213
|
+
|
214
|
+
def aliases
|
215
|
+
@__aliases__ ||= []
|
216
|
+
end
|
217
|
+
|
218
|
+
# build a URL from given chunks prefixing them with actual path
|
219
|
+
#
|
220
|
+
# @param *args [Array]
|
221
|
+
# @return [String]
|
222
|
+
def url *args
|
223
|
+
return @__url__ if args.empty?
|
224
|
+
query = if args.last.is_a?(Hash)
|
225
|
+
RocketIO::QUERY_PREFIX + ::Rack::Utils.build_nested_query(args.pop)
|
226
|
+
else
|
227
|
+
RocketIO::EMPTY_STRING
|
228
|
+
end
|
229
|
+
::File.join(@__url__, args.map!(&:to_s)) + query
|
230
|
+
end
|
231
|
+
|
232
|
+
def method_added meth
|
233
|
+
parameters = instance_method(meth).parameters
|
234
|
+
path_params[meth] = RocketIO.path_params(parameters).freeze
|
235
|
+
if requested_method = RocketIO::REQUEST_METHODS.values.find {|verb| verb == meth}
|
236
|
+
# REST methods should be called with a predetermined set of parameters.
|
237
|
+
# setting an appropriate policy for just defined method based on its parameters.
|
238
|
+
parameters_policy[requested_method] = RocketIO.parameters_policy(parameters).freeze
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# initializing the controller to process a HTTP request
|
243
|
+
#
|
244
|
+
# @param path_params [Array]
|
245
|
+
# @return a RocketIO::Route instance
|
246
|
+
def initialize_controller requested_method = nil, path_params_array = nil
|
247
|
+
controller = allocate
|
248
|
+
controller.instance_variable_set(:@__requested_method__, requested_method.to_sym) if requested_method
|
249
|
+
controller.instance_variable_set(:@__path_params_array__, (path_params_array || []).freeze)
|
250
|
+
controller
|
251
|
+
end
|
252
|
+
|
253
|
+
def parameters_policy
|
254
|
+
@__parameters_policy__ ||= {}
|
255
|
+
end
|
256
|
+
|
257
|
+
def path_params
|
258
|
+
@__path_params__ ||= {}
|
259
|
+
end
|
260
|
+
|
261
|
+
def dirname *args
|
262
|
+
::File.join(@__dirname__, args.map!(&:to_s))
|
263
|
+
end
|
264
|
+
|
265
|
+
# making controller to act as a Rack application
|
266
|
+
def call env
|
267
|
+
initialize_controller.call(env)
|
268
|
+
end
|
269
|
+
|
270
|
+
def api
|
271
|
+
public_instance_methods(false)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
require 'rocketio/controller/authentication'
|
277
|
+
require 'rocketio/controller/authorization'
|
278
|
+
require 'rocketio/controller/cookies'
|
279
|
+
require 'rocketio/controller/error_handlers'
|
280
|
+
require 'rocketio/controller/filters'
|
281
|
+
require 'rocketio/controller/flash'
|
282
|
+
require 'rocketio/controller/helpers'
|
283
|
+
require 'rocketio/controller/middleware'
|
284
|
+
require 'rocketio/controller/request'
|
285
|
+
require 'rocketio/controller/response'
|
286
|
+
require 'rocketio/controller/sessions'
|
287
|
+
require 'rocketio/controller/websocket'
|
288
|
+
require 'rocketio/controller/render'
|