rage-rb 0.3.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -5
- data/Gemfile +3 -0
- data/README.md +14 -12
- data/lib/rage/all.rb +27 -0
- data/lib/rage/application.rb +35 -6
- data/lib/rage/cli.rb +43 -44
- data/lib/rage/configuration.rb +22 -6
- data/lib/rage/controller/api.rb +52 -4
- data/lib/rage/errors.rb +4 -0
- data/lib/rage/fiber.rb +58 -10
- data/lib/rage/fiber_scheduler.rb +59 -32
- data/lib/rage/logger/logger.rb +164 -0
- data/lib/rage/logger/text_formatter.rb +46 -0
- data/lib/rage/params_parser.rb +45 -0
- data/lib/rage/request.rb +44 -0
- data/lib/rage/router/backend.rb +37 -4
- data/lib/rage/router/dsl.rb +236 -6
- data/lib/rage/router/handler_storage.rb +8 -5
- data/lib/rage/sidekiq_session.rb +72 -0
- data/lib/rage/templates/Gemfile +5 -1
- data/lib/rage/templates/Rakefile +1 -0
- data/lib/rage/templates/config-application.rb +6 -1
- data/lib/rage/templates/config-environments-development.rb +6 -3
- data/lib/rage/templates/config-environments-production.rb +7 -3
- data/lib/rage/templates/config-environments-test.rb +6 -3
- data/lib/rage/uploaded_file.rb +70 -0
- data/lib/rage/version.rb +1 -1
- data/lib/rage-rb.rb +7 -16
- data/rage.gemspec +1 -1
- metadata +13 -4
data/lib/rage/router/dsl.rb
CHANGED
@@ -9,14 +9,54 @@ class Rage::Router::DSL
|
|
9
9
|
Handler.new(@router).instance_eval(&block)
|
10
10
|
end
|
11
11
|
|
12
|
+
##
|
13
|
+
# This class implements routing logic for your application, providing API similar to Rails.
|
14
|
+
#
|
15
|
+
# Compared to the Rails router, the most notable difference is that a wildcard segment can only be in the last section of the path and cannot be named.
|
16
|
+
# Example:
|
17
|
+
# ```ruby
|
18
|
+
# get "/photos/*"
|
19
|
+
# ```
|
20
|
+
#
|
21
|
+
# Also, as this is an API-only framework, route helpers, like `photos_path` or `photos_url` are not being generated.
|
22
|
+
#
|
23
|
+
# #### Constraints
|
24
|
+
#
|
25
|
+
# Currently, the only constraint supported is the `host` constraint. The constraint value can be either string or a regular expression.
|
26
|
+
# Example:
|
27
|
+
# ```ruby
|
28
|
+
# get "/photos", to: "photos#index", constraints: { host: "myhost.com" }
|
29
|
+
# ```
|
30
|
+
#
|
31
|
+
# Parameter constraints are likely to be added in the future versions. Custom/lambda constraints are unlikely to be ever added.
|
32
|
+
#
|
33
|
+
# @example Set up a root handler
|
34
|
+
# root to: "pages#main"
|
35
|
+
# @example Set up multiple resources
|
36
|
+
# resources :magazines do
|
37
|
+
# resources :ads
|
38
|
+
# end
|
39
|
+
# @example Scope a set of routes to the given default options.
|
40
|
+
# scope path: ":account_id" do
|
41
|
+
# resources :projects
|
42
|
+
# end
|
43
|
+
# @example Scope routes to a specific namespace.
|
44
|
+
# namespace :admin do
|
45
|
+
# resources :posts
|
46
|
+
# end
|
12
47
|
class Handler
|
13
48
|
# @private
|
14
49
|
def initialize(router)
|
15
50
|
@router = router
|
16
51
|
|
52
|
+
@default_actions = %i(index create show update destroy)
|
53
|
+
@default_match_methods = %i(get post put patch delete head)
|
54
|
+
@scope_opts = %i(module path controller)
|
55
|
+
|
17
56
|
@path_prefixes = []
|
18
57
|
@module_prefixes = []
|
19
58
|
@defaults = []
|
59
|
+
@controllers = []
|
20
60
|
end
|
21
61
|
|
22
62
|
# Register a new GET route.
|
@@ -29,7 +69,7 @@ class Rage::Router::DSL
|
|
29
69
|
# get "/photos/:id", to: "photos#show", constraints: { host: /myhost/ }
|
30
70
|
# @example
|
31
71
|
# get "/photos(/:id)", to: "photos#show", defaults: { id: "-1" }
|
32
|
-
def get(path, to
|
72
|
+
def get(path, to: nil, constraints: nil, defaults: nil)
|
33
73
|
__on("GET", path, to, constraints, defaults)
|
34
74
|
end
|
35
75
|
|
@@ -43,7 +83,7 @@ class Rage::Router::DSL
|
|
43
83
|
# post "/photos", to: "photos#create", constraints: { host: /myhost/ }
|
44
84
|
# @example
|
45
85
|
# post "/photos", to: "photos#create", defaults: { format: "jpg" }
|
46
|
-
def post(path, to
|
86
|
+
def post(path, to: nil, constraints: nil, defaults: nil)
|
47
87
|
__on("POST", path, to, constraints, defaults)
|
48
88
|
end
|
49
89
|
|
@@ -57,7 +97,7 @@ class Rage::Router::DSL
|
|
57
97
|
# put "/photos/:id", to: "photos#update", constraints: { host: /myhost/ }
|
58
98
|
# @example
|
59
99
|
# put "/photos(/:id)", to: "photos#update", defaults: { id: "-1" }
|
60
|
-
def put(path, to
|
100
|
+
def put(path, to: nil, constraints: nil, defaults: nil)
|
61
101
|
__on("PUT", path, to, constraints, defaults)
|
62
102
|
end
|
63
103
|
|
@@ -71,7 +111,7 @@ class Rage::Router::DSL
|
|
71
111
|
# patch "/photos/:id", to: "photos#update", constraints: { host: /myhost/ }
|
72
112
|
# @example
|
73
113
|
# patch "/photos(/:id)", to: "photos#update", defaults: { id: "-1" }
|
74
|
-
def patch(path, to
|
114
|
+
def patch(path, to: nil, constraints: nil, defaults: nil)
|
75
115
|
__on("PATCH", path, to, constraints, defaults)
|
76
116
|
end
|
77
117
|
|
@@ -85,7 +125,7 @@ class Rage::Router::DSL
|
|
85
125
|
# delete "/photos/:id", to: "photos#destroy", constraints: { host: /myhost/ }
|
86
126
|
# @example
|
87
127
|
# delete "/photos(/:id)", to: "photos#destroy", defaults: { id: "-1" }
|
88
|
-
def delete(path, to
|
128
|
+
def delete(path, to: nil, constraints: nil, defaults: nil)
|
89
129
|
__on("DELETE", path, to, constraints, defaults)
|
90
130
|
end
|
91
131
|
|
@@ -98,6 +138,70 @@ class Rage::Router::DSL
|
|
98
138
|
__on("GET", "/", to, nil, nil)
|
99
139
|
end
|
100
140
|
|
141
|
+
# Match a URL pattern to one or more routes.
|
142
|
+
#
|
143
|
+
# @param path [String] the path for the route handler
|
144
|
+
# @param to [String, #call] the route handler in the format of "controller#action" or a callable
|
145
|
+
# @param constraints [Hash] a hash of constraints for the route
|
146
|
+
# @param defaults [Hash] a hash of default parameters for the route
|
147
|
+
# @param via [Symbol, Array<Symbol>] an array of HTTP methods to accept
|
148
|
+
# @example
|
149
|
+
# match "/photos/:id", to: "photos#show", via: [:get, :post]
|
150
|
+
# @example
|
151
|
+
# match "/photos/:id", to: "photos#show", via: :all
|
152
|
+
# @example
|
153
|
+
# match "/health", to: -> (env) { [200, {}, ["healthy"]] }
|
154
|
+
def match(path, to:, constraints: {}, defaults: nil, via: :all)
|
155
|
+
# via is either nil, or an array of symbols or its :all
|
156
|
+
http_methods = via
|
157
|
+
# if its :all or nil, then we use the default HTTP methods
|
158
|
+
if via == :all || via.nil?
|
159
|
+
http_methods = @default_match_methods
|
160
|
+
else
|
161
|
+
# if its an array of symbols, then we use the symbols as HTTP methods
|
162
|
+
http_methods = Array(via)
|
163
|
+
# then we check if the HTTP methods are valid
|
164
|
+
http_methods.each do |method|
|
165
|
+
raise ArgumentError, "Invalid HTTP method: #{method}" unless @default_match_methods.include?(method)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
http_methods.each do |method|
|
170
|
+
__on(method.to_s.upcase, path, to, constraints, defaults)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Register a new namespace.
|
175
|
+
#
|
176
|
+
# @param path [String] the path for the namespace
|
177
|
+
# @param options [Hash] a hash of options for the namespace
|
178
|
+
# @option options [String] :module the module name for the namespace
|
179
|
+
# @option options [String] :path the path for the namespace
|
180
|
+
# @example
|
181
|
+
# namespace :admin do
|
182
|
+
# get "/photos", to: "photos#index"
|
183
|
+
# end
|
184
|
+
# @example
|
185
|
+
# namespace :admin, path: "panel" do
|
186
|
+
# get "/photos", to: "photos#index"
|
187
|
+
# end
|
188
|
+
# @example
|
189
|
+
# namespace :admin, module: "admin" do
|
190
|
+
# get "/photos", to: "photos#index"
|
191
|
+
# end
|
192
|
+
def namespace(path, **options, &block)
|
193
|
+
path_prefix = options[:path] || path
|
194
|
+
module_prefix = options[:module] || path
|
195
|
+
|
196
|
+
@path_prefixes << path_prefix
|
197
|
+
@module_prefixes << module_prefix
|
198
|
+
|
199
|
+
instance_eval &block
|
200
|
+
|
201
|
+
@path_prefixes.pop
|
202
|
+
@module_prefixes.pop
|
203
|
+
end
|
204
|
+
|
101
205
|
# Scopes a set of routes to the given default options.
|
102
206
|
#
|
103
207
|
# @param [Hash] opts scope options.
|
@@ -120,15 +224,17 @@ class Rage::Router::DSL
|
|
120
224
|
# end
|
121
225
|
# end
|
122
226
|
def scope(opts, &block)
|
123
|
-
raise ArgumentError, "only
|
227
|
+
raise ArgumentError, "only :module, :path, and :controller options are accepted" if (opts.keys - @scope_opts).any?
|
124
228
|
|
125
229
|
@path_prefixes << opts[:path].delete_prefix("/").delete_suffix("/") if opts[:path]
|
126
230
|
@module_prefixes << opts[:module] if opts[:module]
|
231
|
+
@controllers << opts[:controller] if opts[:controller]
|
127
232
|
|
128
233
|
instance_eval &block
|
129
234
|
|
130
235
|
@path_prefixes.pop if opts[:path]
|
131
236
|
@module_prefixes.pop if opts[:module]
|
237
|
+
@controllers.pop if opts[:controller]
|
132
238
|
end
|
133
239
|
|
134
240
|
# Specify default parameters for a set of routes.
|
@@ -144,14 +250,120 @@ class Rage::Router::DSL
|
|
144
250
|
@defaults.pop
|
145
251
|
end
|
146
252
|
|
253
|
+
# Add a route to the collection.
|
254
|
+
#
|
255
|
+
# @example Add a `photos/search` path instead of `photos/:photo_id/search`
|
256
|
+
# resources :photos do
|
257
|
+
# collection do
|
258
|
+
# get "search"
|
259
|
+
# end
|
260
|
+
# end
|
261
|
+
def collection(&block)
|
262
|
+
orig_path_prefixes = @path_prefixes
|
263
|
+
@path_prefixes = @path_prefixes[0...-1] if @path_prefixes.last&.start_with?(":")
|
264
|
+
instance_eval &block
|
265
|
+
@path_prefixes = orig_path_prefixes
|
266
|
+
end
|
267
|
+
|
268
|
+
# Automatically create REST routes for a resource.
|
269
|
+
#
|
270
|
+
# @example Create five REST routes, all mapping to the `Photos` controller:
|
271
|
+
# resources :photos
|
272
|
+
# # GET /photos => photos#index
|
273
|
+
# # POST /photos => photos#create
|
274
|
+
# # GET /photos/:id => photos#show
|
275
|
+
# # PATCH/PUT /photos/:id => photos#update
|
276
|
+
# # DELETE /photos/:id => photos#destroy
|
277
|
+
# @note This helper doesn't generate the `new` and `edit` routes.
|
278
|
+
def resources(*_resources, **opts, &block)
|
279
|
+
# support calls with multiple resources, e.g. `resources :albums, :photos`
|
280
|
+
if _resources.length > 1
|
281
|
+
_resources.each { |_resource| resources(_resource, **opts, &block) }
|
282
|
+
return
|
283
|
+
end
|
284
|
+
|
285
|
+
_module, _path, _only, _except, _param = opts.values_at(:module, :path, :only, :except, :param)
|
286
|
+
raise ":param option can't contain colons" if _param&.include?(":")
|
287
|
+
|
288
|
+
_only = Array(_only) if _only
|
289
|
+
_except = Array(_except) if _except
|
290
|
+
actions = @default_actions.select do |action|
|
291
|
+
(_only.nil? || _only.include?(action)) && (_except.nil? || !_except.include?(action))
|
292
|
+
end
|
293
|
+
|
294
|
+
resource = _resources[0].to_s
|
295
|
+
_path ||= resource
|
296
|
+
_param ||= "id"
|
297
|
+
|
298
|
+
scope_opts = { path: _path }
|
299
|
+
scope_opts[:module] = _module if _module
|
300
|
+
|
301
|
+
scope(scope_opts) do
|
302
|
+
get("/", to: "#{resource}#index") if actions.include?(:index)
|
303
|
+
post("/", to: "#{resource}#create") if actions.include?(:create)
|
304
|
+
get("/:#{_param}", to: "#{resource}#show") if actions.include?(:show)
|
305
|
+
patch("/:#{_param}", to: "#{resource}#update") if actions.include?(:update)
|
306
|
+
put("/:#{_param}", to: "#{resource}#update") if actions.include?(:update)
|
307
|
+
delete("/:#{_param}", to: "#{resource}#destroy") if actions.include?(:destroy)
|
308
|
+
|
309
|
+
scope(path: ":#{to_singular(resource)}_#{_param}", controller: resource, &block) if block
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# Mount a Rack-based application to be used within the application.
|
314
|
+
#
|
315
|
+
# @example
|
316
|
+
# mount Sidekiq::Web => "/sidekiq"
|
317
|
+
# @example
|
318
|
+
# mount Sidekiq::Web, at: "/sidekiq", via: :get
|
319
|
+
def mount(*args)
|
320
|
+
if args.first.is_a?(Hash)
|
321
|
+
app = args.first.keys.first
|
322
|
+
at = args.first.values.first
|
323
|
+
via = args[0][:via]
|
324
|
+
else
|
325
|
+
app = args.first
|
326
|
+
at = args[1][:at]
|
327
|
+
via = args[1][:via]
|
328
|
+
end
|
329
|
+
|
330
|
+
at = "/#{at}" unless at.start_with?("/")
|
331
|
+
at = at.delete_suffix("/") if at.end_with?("/")
|
332
|
+
|
333
|
+
http_methods = if via == :all || via.nil?
|
334
|
+
@default_match_methods.map { |method| method.to_s.upcase! }
|
335
|
+
else
|
336
|
+
Array(via).map! do |method|
|
337
|
+
raise ArgumentError, "Invalid HTTP method: #{method}" unless @default_match_methods.include?(method)
|
338
|
+
method.to_s.upcase!
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
@router.mount(at, app, http_methods)
|
343
|
+
end
|
344
|
+
|
147
345
|
private
|
148
346
|
|
149
347
|
def __on(method, path, to, constraints, defaults)
|
348
|
+
# handle calls without controller inside resources:
|
349
|
+
# resources :comments do
|
350
|
+
# post :like
|
351
|
+
# end
|
352
|
+
if !to
|
353
|
+
if @controllers.any?
|
354
|
+
to = "#{@controllers.last}##{path}"
|
355
|
+
else
|
356
|
+
raise "Missing :to key on routes definition, please check your routes."
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
# process path to ensure it starts with "/" and doesn't end with "/"
|
150
361
|
if path != "/"
|
151
362
|
path = "/#{path}" unless path.start_with?("/")
|
152
363
|
path = path.delete_suffix("/") if path.end_with?("/")
|
153
364
|
end
|
154
365
|
|
366
|
+
# correctly process root helpers inside `scope` calls
|
155
367
|
if path == "/" && @path_prefixes.any?
|
156
368
|
path = ""
|
157
369
|
end
|
@@ -166,5 +378,23 @@ class Rage::Router::DSL
|
|
166
378
|
@router.on(method, "#{path_prefix}#{path}", to, constraints: constraints || {}, defaults: defaults)
|
167
379
|
end
|
168
380
|
end
|
381
|
+
|
382
|
+
def to_singular(str)
|
383
|
+
@active_support_loaded ||= str.respond_to?(:singularize) || :false
|
384
|
+
return str.singularize if @active_support_loaded != :false
|
385
|
+
|
386
|
+
@endings ||= {
|
387
|
+
"ves" => "fe",
|
388
|
+
"ies" => "y",
|
389
|
+
"i" => "us",
|
390
|
+
"zes" => "ze",
|
391
|
+
"ses" => "s",
|
392
|
+
"es" => "",
|
393
|
+
"s" => ""
|
394
|
+
}
|
395
|
+
@regexp ||= Regexp.new("(#{@endings.keys.join("|")})$")
|
396
|
+
|
397
|
+
str.sub(@regexp, @endings)
|
398
|
+
end
|
169
399
|
end
|
170
400
|
end
|
@@ -22,7 +22,7 @@ class Rage::Router::HandlerStorage
|
|
22
22
|
params: params,
|
23
23
|
constraints: constraints,
|
24
24
|
handler: route[:handler],
|
25
|
-
create_params_object: compile_create_params_object(params, route[:defaults])
|
25
|
+
create_params_object: compile_create_params_object(params, route[:defaults], route[:meta])
|
26
26
|
}
|
27
27
|
|
28
28
|
constraints_keys = constraints.keys
|
@@ -47,16 +47,19 @@ class Rage::Router::HandlerStorage
|
|
47
47
|
|
48
48
|
private
|
49
49
|
|
50
|
-
def compile_create_params_object(param_keys, defaults)
|
51
|
-
lines = [
|
50
|
+
def compile_create_params_object(param_keys, defaults, meta)
|
51
|
+
lines = [
|
52
|
+
":controller => '#{meta[:controller]}'.freeze",
|
53
|
+
":action => '#{meta[:action]}'.freeze"
|
54
|
+
]
|
52
55
|
|
53
56
|
param_keys.each_with_index do |key, i|
|
54
|
-
lines << "
|
57
|
+
lines << ":#{key} => param_values[#{i}]"
|
55
58
|
end
|
56
59
|
|
57
60
|
if defaults
|
58
61
|
defaults.except(*param_keys.map(&:to_sym)).each do |key, value|
|
59
|
-
lines << "
|
62
|
+
lines << ":#{key} => '#{value}'.freeze"
|
60
63
|
end
|
61
64
|
end
|
62
65
|
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "digest"
|
4
|
+
require "base64"
|
5
|
+
|
6
|
+
##
|
7
|
+
# Used **specifically** for compatibility with Sidekiq's Web interface.
|
8
|
+
# Remove once we have real sessions or once Sidekiq's author decides they
|
9
|
+
# don't need cookie sessions to protect against CSRF.
|
10
|
+
#
|
11
|
+
class Rage::SidekiqSession
|
12
|
+
KEY = Digest::SHA2.hexdigest(ENV["SECRET_KEY_BASE"] || File.read("Gemfile.lock") + File.read("config/routes.rb"))
|
13
|
+
SESSION_KEY = "rage.sidekiq.session"
|
14
|
+
|
15
|
+
def self.with_session(env)
|
16
|
+
env["rack.session"] = session = self.new(env)
|
17
|
+
response = yield
|
18
|
+
|
19
|
+
if session.changed
|
20
|
+
Rack::Utils.set_cookie_header!(
|
21
|
+
response[1],
|
22
|
+
SESSION_KEY,
|
23
|
+
{ path: env["SCRIPT_NAME"], httponly: true, same_site: true, value: session.dump }
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
response
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :changed
|
31
|
+
|
32
|
+
def initialize(env)
|
33
|
+
@env = env
|
34
|
+
session = Rack::Utils.parse_cookies(@env)[SESSION_KEY]
|
35
|
+
@data = decode_session(session)
|
36
|
+
end
|
37
|
+
|
38
|
+
def [](key)
|
39
|
+
@data[key]
|
40
|
+
end
|
41
|
+
|
42
|
+
def[]=(key, value)
|
43
|
+
@changed = true
|
44
|
+
@data[key] = value
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_hash
|
48
|
+
@data
|
49
|
+
end
|
50
|
+
|
51
|
+
def dump
|
52
|
+
encoded_data = Marshal.dump(@data)
|
53
|
+
signature = OpenSSL::HMAC.hexdigest("SHA256", KEY, encoded_data)
|
54
|
+
|
55
|
+
Base64.urlsafe_encode64("#{encoded_data}--#{signature}")
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def decode_session(session)
|
61
|
+
return {} unless session
|
62
|
+
|
63
|
+
encoded_data, signature = Base64.urlsafe_decode64(session).split("--")
|
64
|
+
ref_signature = OpenSSL::HMAC.hexdigest("SHA256", KEY, encoded_data)
|
65
|
+
|
66
|
+
if Rack::Utils.secure_compare(signature, ref_signature)
|
67
|
+
Marshal.load(encoded_data)
|
68
|
+
else
|
69
|
+
{}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/rage/templates/Gemfile
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
|
-
gem "rage-rb"
|
3
|
+
gem "rage-rb", "<%= Rage::VERSION %>"
|
4
4
|
|
5
5
|
# Build JSON APIs with ease
|
6
6
|
# gem "alba"
|
7
|
+
|
8
|
+
# Get 50% to 150% boost when parsing JSON.
|
9
|
+
# Rage will automatically use FastJsonparser if it is available.
|
10
|
+
# gem "fast_jsonparser"
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative "config/application"
|
@@ -1,7 +1,10 @@
|
|
1
|
-
Rage.configure do
|
1
|
+
Rage.configure do
|
2
2
|
# Specify the number of server processes to run. Defaults to number of CPU cores.
|
3
|
-
config.workers_count = 1
|
3
|
+
config.server.workers_count = 1
|
4
4
|
|
5
5
|
# Specify the port the server will listen on.
|
6
|
-
config.port = 3000
|
6
|
+
config.server.port = 3000
|
7
|
+
|
8
|
+
# Specify the logger
|
9
|
+
config.logger = Rage::Logger.new(STDOUT)
|
7
10
|
end
|
@@ -1,7 +1,11 @@
|
|
1
|
-
Rage.configure do
|
1
|
+
Rage.configure do
|
2
2
|
# Specify the number of server processes to run. Defaults to number of CPU cores.
|
3
|
-
# config.workers_count = ENV.fetch("WEB_CONCURRENCY", 1)
|
3
|
+
# config.server.workers_count = ENV.fetch("WEB_CONCURRENCY", 1)
|
4
4
|
|
5
5
|
# Specify the port the server will listen on.
|
6
|
-
config.port = 3000
|
6
|
+
config.server.port = 3000
|
7
|
+
|
8
|
+
# Specify the logger
|
9
|
+
config.logger = Rage::Logger.new("log/production.log")
|
10
|
+
config.log_level = Logger::INFO
|
7
11
|
end
|
@@ -1,7 +1,10 @@
|
|
1
|
-
Rage.configure do
|
1
|
+
Rage.configure do
|
2
2
|
# Specify the number of server processes to run. Defaults to number of CPU cores.
|
3
|
-
config.workers_count = 1
|
3
|
+
config.server.workers_count = 1
|
4
4
|
|
5
5
|
# Specify the port the server will listen on.
|
6
|
-
config.port = 3000
|
6
|
+
config.server.port = 3000
|
7
|
+
|
8
|
+
# Specify the logger
|
9
|
+
config.logger = Rage::Logger.new("log/test.log")
|
7
10
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# Models uploaded files.
|
5
|
+
#
|
6
|
+
# The actual file is accessible via the `file` accessor, though some
|
7
|
+
# of its interface is available directly for convenience.
|
8
|
+
#
|
9
|
+
# Rage will automatically unlink the files, so there is no need to clean them with a separate maintenance task.
|
10
|
+
class Rage::UploadedFile
|
11
|
+
# The basename of the file in the client.
|
12
|
+
attr_reader :original_filename
|
13
|
+
|
14
|
+
# A string with the MIME type of the file.
|
15
|
+
attr_reader :content_type
|
16
|
+
|
17
|
+
# A `File` object with the actual uploaded file. Note that some of its interface is available directly.
|
18
|
+
attr_reader :file
|
19
|
+
alias_method :tempfile, :file
|
20
|
+
|
21
|
+
def initialize(file, original_filename, content_type)
|
22
|
+
@file = file
|
23
|
+
@original_filename = original_filename
|
24
|
+
@content_type = content_type
|
25
|
+
end
|
26
|
+
|
27
|
+
# Shortcut for `file.read`.
|
28
|
+
def read(length = nil, buffer = nil)
|
29
|
+
@file.read(length, buffer)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Shortcut for `file.open`.
|
33
|
+
def open
|
34
|
+
@file.open
|
35
|
+
end
|
36
|
+
|
37
|
+
# Shortcut for `file.close`.
|
38
|
+
def close(unlink_now = false)
|
39
|
+
@file.close(unlink_now)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Shortcut for `file.path`.
|
43
|
+
def path
|
44
|
+
@file.path
|
45
|
+
end
|
46
|
+
|
47
|
+
# Shortcut for `file.to_path`.
|
48
|
+
def to_path
|
49
|
+
@file.to_path
|
50
|
+
end
|
51
|
+
|
52
|
+
# Shortcut for `file.rewind`.
|
53
|
+
def rewind
|
54
|
+
@file.rewind
|
55
|
+
end
|
56
|
+
|
57
|
+
# Shortcut for `file.size`.
|
58
|
+
def size
|
59
|
+
@file.size
|
60
|
+
end
|
61
|
+
|
62
|
+
# Shortcut for `file.eof?`.
|
63
|
+
def eof?
|
64
|
+
@file.eof?
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_io
|
68
|
+
@file.to_io
|
69
|
+
end
|
70
|
+
end
|
data/lib/rage/version.rb
CHANGED
data/lib/rage-rb.rb
CHANGED
@@ -22,8 +22,9 @@ module Rage
|
|
22
22
|
@config ||= Rage::Configuration.new
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.configure
|
26
|
-
|
25
|
+
def self.configure(&)
|
26
|
+
config.instance_eval(&)
|
27
|
+
config.__finalize
|
27
28
|
end
|
28
29
|
|
29
30
|
def self.env
|
@@ -38,6 +39,10 @@ module Rage
|
|
38
39
|
@root ||= Pathname.new(".").expand_path
|
39
40
|
end
|
40
41
|
|
42
|
+
def self.logger
|
43
|
+
@logger ||= config.logger
|
44
|
+
end
|
45
|
+
|
41
46
|
module Router
|
42
47
|
module Strategies
|
43
48
|
end
|
@@ -46,17 +51,3 @@ end
|
|
46
51
|
|
47
52
|
module RageController
|
48
53
|
end
|
49
|
-
|
50
|
-
require_relative "rage/application"
|
51
|
-
require_relative "rage/fiber"
|
52
|
-
require_relative "rage/fiber_scheduler"
|
53
|
-
require_relative "rage/configuration"
|
54
|
-
|
55
|
-
require_relative "rage/router/strategies/host"
|
56
|
-
require_relative "rage/router/backend"
|
57
|
-
require_relative "rage/router/constrainer"
|
58
|
-
require_relative "rage/router/dsl"
|
59
|
-
require_relative "rage/router/handler_storage"
|
60
|
-
require_relative "rage/router/node"
|
61
|
-
|
62
|
-
require_relative "rage/controller/api"
|
data/rage.gemspec
CHANGED