rocketio 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|