rage-rb 0.5.2 → 0.7.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/CHANGELOG.md +19 -0
- data/CODE_OF_CONDUCT.md +1 -1
- data/README.md +12 -11
- data/lib/rage/all.rb +7 -1
- data/lib/rage/application.rb +21 -3
- data/lib/rage/cli.rb +32 -8
- data/lib/rage/code_loader.rb +48 -0
- data/lib/rage/configuration.rb +122 -5
- data/lib/rage/controller/api.rb +178 -32
- data/lib/rage/errors.rb +3 -0
- data/lib/rage/fiber.rb +8 -0
- data/lib/rage/fiber_scheduler.rb +2 -2
- data/lib/rage/logger/json_formatter.rb +44 -0
- data/lib/rage/logger/logger.rb +4 -4
- data/lib/rage/logger/text_formatter.rb +8 -10
- data/lib/rage/middleware/cors.rb +139 -0
- data/lib/rage/{fiber_wrapper.rb → middleware/fiber_wrapper.rb} +4 -2
- data/lib/rage/middleware/reloader.rb +16 -0
- data/lib/rage/rails.rb +62 -0
- data/lib/rage/request.rb +51 -0
- data/lib/rage/response.rb +21 -0
- data/lib/rage/router/backend.rb +9 -1
- data/lib/rage/router/dsl.rb +3 -1
- data/lib/rage/setup.rb +4 -16
- data/lib/rage/templates/config-environments-development.rb +2 -0
- data/lib/rage/templates/config-initializers-.keep +0 -0
- data/lib/rage/version.rb +1 -1
- data/lib/rage-rb.rb +23 -1
- data/rage.gemspec +1 -0
- metadata +24 -3
data/lib/rage/rails.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
if Gem::Version.new(Rails.version) < Gem::Version.new(6)
|
2
|
+
fail "Rage is only compatible with Rails 6+. Detected Rails version: #{Rails.version}."
|
3
|
+
end
|
4
|
+
|
5
|
+
# load the framework
|
6
|
+
require "rage/all"
|
7
|
+
|
8
|
+
# patch Rack
|
9
|
+
Iodine.patch_rack
|
10
|
+
|
11
|
+
# configure the framework
|
12
|
+
Rage.config.internal.rails_mode = true
|
13
|
+
|
14
|
+
# make sure log formatter is not used in console
|
15
|
+
Rails.application.console do
|
16
|
+
Rage.config.internal.rails_console = true
|
17
|
+
Rage.logger.level = Rage.logger.level if Rage.logger # trigger redefining log methods
|
18
|
+
end
|
19
|
+
|
20
|
+
# patch ActiveRecord's connection pool
|
21
|
+
if defined?(ActiveRecord)
|
22
|
+
Rails.configuration.after_initialize do
|
23
|
+
module ActiveRecord::ConnectionAdapters
|
24
|
+
class ConnectionPool
|
25
|
+
def connection_cache_key(_)
|
26
|
+
Fiber.current
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# plug into Rails' Zeitwerk instance to reload the code
|
34
|
+
Rails.autoloaders.main.on_setup do
|
35
|
+
if Iodine.running?
|
36
|
+
Rage.code_loader.rails_mode_reload
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# patch `ActionDispatch::Reloader` to synchronize `reload!` calls
|
41
|
+
Rails.configuration.after_initialize do
|
42
|
+
conditional_mutex = Module.new do
|
43
|
+
def call(env)
|
44
|
+
@mutex ||= Mutex.new
|
45
|
+
if Rails.application.reloader.check!
|
46
|
+
@mutex.synchronize { super }
|
47
|
+
else
|
48
|
+
super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
ActionDispatch::Reloader.prepend(conditional_mutex)
|
54
|
+
end
|
55
|
+
|
56
|
+
# clone Rails logger
|
57
|
+
Rails.configuration.after_initialize do
|
58
|
+
if Rails.logger && !Rage.logger
|
59
|
+
rails_logdev = Rails.logger.instance_variable_get(:@logdev)
|
60
|
+
Rage.config.logger = Rage::Logger.new(rails_logdev) if rails_logdev.is_a?(Logger::LogDevice)
|
61
|
+
end
|
62
|
+
end
|
data/lib/rage/request.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "time"
|
4
|
+
|
3
5
|
class Rage::Request
|
4
6
|
# @private
|
5
7
|
def initialize(env)
|
@@ -14,6 +16,55 @@ class Rage::Request
|
|
14
16
|
@headers ||= Headers.new(@env)
|
15
17
|
end
|
16
18
|
|
19
|
+
# Check if the request is fresh.
|
20
|
+
# @param etag [String] The etag of the requested resource.
|
21
|
+
# @param last_modified [Time] The last modified time of the requested resource.
|
22
|
+
# @return [Boolean] True if the request is fresh, false otherwise.
|
23
|
+
# @example
|
24
|
+
# request.fresh?(etag: "123", last_modified: Time.utc(2023, 12, 15))
|
25
|
+
# request.fresh?(last_modified: Time.utc(2023, 12, 15))
|
26
|
+
# request.fresh?(etag: "123")
|
27
|
+
def fresh?(etag:, last_modified:)
|
28
|
+
# Always render response when no freshness information
|
29
|
+
# is provided in the request.
|
30
|
+
return false unless if_none_match || if_not_modified_since
|
31
|
+
|
32
|
+
etag_matches?(
|
33
|
+
requested_etags: if_none_match, response_etag: etag
|
34
|
+
) && not_modified?(
|
35
|
+
request_not_modified_since: if_not_modified_since,
|
36
|
+
response_last_modified: last_modified
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def if_none_match
|
43
|
+
headers["HTTP_IF_NONE_MATCH"]
|
44
|
+
end
|
45
|
+
|
46
|
+
def if_not_modified_since
|
47
|
+
headers["HTTP_IF_MODIFIED_SINCE"] ? Time.httpdate(headers["HTTP_IF_MODIFIED_SINCE"]) : nil
|
48
|
+
rescue ArgumentError
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def etag_matches?(requested_etags:, response_etag:)
|
53
|
+
requested_etags = requested_etags ? requested_etags.split(",").each(&:strip!) : []
|
54
|
+
|
55
|
+
return true if requested_etags.empty?
|
56
|
+
return false if response_etag.nil?
|
57
|
+
|
58
|
+
requested_etags.include?(response_etag) || requested_etags.include?("*")
|
59
|
+
end
|
60
|
+
|
61
|
+
def not_modified?(request_not_modified_since:, response_last_modified:)
|
62
|
+
return true if request_not_modified_since.nil?
|
63
|
+
return false if response_last_modified.nil?
|
64
|
+
|
65
|
+
request_not_modified_since >= response_last_modified
|
66
|
+
end
|
67
|
+
|
17
68
|
# @private
|
18
69
|
class Headers
|
19
70
|
HTTP = "HTTP_"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Rage::Response
|
4
|
+
# @private
|
5
|
+
def initialize(headers, body)
|
6
|
+
@headers = headers
|
7
|
+
@body = body
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns the content of the response as a string. This contains the contents of any calls to `render`.
|
11
|
+
# @return [String]
|
12
|
+
def body
|
13
|
+
@body[0]
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the headers for the response.
|
17
|
+
# @return [Hash]
|
18
|
+
def headers
|
19
|
+
@headers
|
20
|
+
end
|
21
|
+
end
|
data/lib/rage/router/backend.rb
CHANGED
@@ -14,6 +14,11 @@ class Rage::Router::Backend
|
|
14
14
|
@constrainer = Rage::Router::Constrainer.new({})
|
15
15
|
end
|
16
16
|
|
17
|
+
def reset_routes
|
18
|
+
@routes = []
|
19
|
+
@trees = {}
|
20
|
+
end
|
21
|
+
|
17
22
|
def mount(path, handler, methods)
|
18
23
|
raise "Mount handler should respond to `call`" unless handler.respond_to?(:call)
|
19
24
|
|
@@ -79,6 +84,9 @@ class Rage::Router::Backend
|
|
79
84
|
end
|
80
85
|
|
81
86
|
__on(method, path, handler, constraints, defaults, meta)
|
87
|
+
|
88
|
+
rescue Rage::Errors::RouterError => e
|
89
|
+
raise e unless Rage.code_loader.reloading?
|
82
90
|
end
|
83
91
|
|
84
92
|
def lookup(env)
|
@@ -280,7 +288,7 @@ class Rage::Router::Backend
|
|
280
288
|
if Object.const_defined?(klass)
|
281
289
|
Object.const_get(klass)
|
282
290
|
else
|
283
|
-
raise "Routing error: could not find the #{klass} class"
|
291
|
+
raise Rage::Errors::RouterError, "Routing error: could not find the #{klass} class"
|
284
292
|
end
|
285
293
|
end
|
286
294
|
end
|
data/lib/rage/router/dsl.rb
CHANGED
@@ -7,6 +7,8 @@ class Rage::Router::DSL
|
|
7
7
|
|
8
8
|
def draw(&block)
|
9
9
|
Handler.new(@router).instance_eval(&block)
|
10
|
+
# propagate route definitions to Rails for `rails routes` to work
|
11
|
+
Rails.application.routes.draw(&block) if Rage.config.internal.rails_mode
|
10
12
|
end
|
11
13
|
|
12
14
|
##
|
@@ -283,7 +285,7 @@ class Rage::Router::DSL
|
|
283
285
|
end
|
284
286
|
|
285
287
|
_module, _path, _only, _except, _param = opts.values_at(:module, :path, :only, :except, :param)
|
286
|
-
raise ":param option can't contain colons" if _param
|
288
|
+
raise ":param option can't contain colons" if _param.to_s.include?(":")
|
287
289
|
|
288
290
|
_only = Array(_only) if _only
|
289
291
|
_except = Array(_except) if _except
|
data/lib/rage/setup.rb
CHANGED
@@ -2,22 +2,10 @@ Iodine.patch_rack
|
|
2
2
|
|
3
3
|
require_relative "#{Rage.root}/config/environments/#{Rage.env}"
|
4
4
|
|
5
|
+
# Run application initializers
|
6
|
+
Dir["#{Rage.root}/config/initializers/**/*.rb"].each { |initializer| load(initializer) }
|
5
7
|
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
loop do
|
10
|
-
path = app.shift
|
11
|
-
break if path.nil?
|
12
|
-
|
13
|
-
require_relative path
|
14
|
-
|
15
|
-
# push the file to the end of the list in case it depends on another file that has not yet been required;
|
16
|
-
# re-raise if only errored out files are left
|
17
|
-
rescue NameError
|
18
|
-
raise if (app - bad).empty?
|
19
|
-
app << path
|
20
|
-
bad << path
|
21
|
-
end
|
8
|
+
# Load application classes
|
9
|
+
Rage.code_loader.setup
|
22
10
|
|
23
11
|
require_relative "#{Rage.root}/config/routes"
|
File without changes
|
data/lib/rage/version.rb
CHANGED
data/lib/rage-rb.rb
CHANGED
@@ -28,7 +28,7 @@ module Rage
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.env
|
31
|
-
@__env ||= Rage::Env.new(ENV["RAGE_ENV"]
|
31
|
+
@__env ||= Rage::Env.new(ENV["RAGE_ENV"])
|
32
32
|
end
|
33
33
|
|
34
34
|
def self.groups
|
@@ -45,10 +45,32 @@ module Rage
|
|
45
45
|
|
46
46
|
def self.load_middlewares(rack_builder)
|
47
47
|
config.middleware.middlewares.each do |middleware, args, block|
|
48
|
+
# in Rails compatibility mode we first check if the middleware is a part of the Rails middleware stack;
|
49
|
+
# if it is - it is expected to be built using `ActionDispatch::MiddlewareStack::Middleware#build`, but Rack
|
50
|
+
# expects the middleware to respond to `#new`, so we wrap the middleware into a helper module
|
51
|
+
if Rage.config.internal.rails_mode
|
52
|
+
rails_middleware = Rails.application.config.middleware.middlewares.find { |m| m.name == middleware.name }
|
53
|
+
if rails_middleware
|
54
|
+
wrapper = Module.new do
|
55
|
+
extend self
|
56
|
+
attr_accessor :middleware
|
57
|
+
def new(app, *, &)
|
58
|
+
middleware.build(app)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
wrapper.middleware = rails_middleware
|
62
|
+
middleware = wrapper
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
48
66
|
rack_builder.use(middleware, *args, &block)
|
49
67
|
end
|
50
68
|
end
|
51
69
|
|
70
|
+
def self.code_loader
|
71
|
+
@code_loader ||= Rage::CodeLoader.new
|
72
|
+
end
|
73
|
+
|
52
74
|
module Router
|
53
75
|
module Strategies
|
54
76
|
end
|
data/rage.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rage-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roman Samoilov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: zeitwerk
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.6'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.6'
|
55
69
|
description:
|
56
70
|
email:
|
57
71
|
- rsamoi@icloud.com
|
@@ -74,17 +88,23 @@ files:
|
|
74
88
|
- lib/rage/all.rb
|
75
89
|
- lib/rage/application.rb
|
76
90
|
- lib/rage/cli.rb
|
91
|
+
- lib/rage/code_loader.rb
|
77
92
|
- lib/rage/configuration.rb
|
78
93
|
- lib/rage/controller/api.rb
|
79
94
|
- lib/rage/env.rb
|
80
95
|
- lib/rage/errors.rb
|
81
96
|
- lib/rage/fiber.rb
|
82
97
|
- lib/rage/fiber_scheduler.rb
|
83
|
-
- lib/rage/
|
98
|
+
- lib/rage/logger/json_formatter.rb
|
84
99
|
- lib/rage/logger/logger.rb
|
85
100
|
- lib/rage/logger/text_formatter.rb
|
101
|
+
- lib/rage/middleware/cors.rb
|
102
|
+
- lib/rage/middleware/fiber_wrapper.rb
|
103
|
+
- lib/rage/middleware/reloader.rb
|
86
104
|
- lib/rage/params_parser.rb
|
105
|
+
- lib/rage/rails.rb
|
87
106
|
- lib/rage/request.rb
|
107
|
+
- lib/rage/response.rb
|
88
108
|
- lib/rage/router/README.md
|
89
109
|
- lib/rage/router/backend.rb
|
90
110
|
- lib/rage/router/constrainer.rb
|
@@ -101,6 +121,7 @@ files:
|
|
101
121
|
- lib/rage/templates/config-environments-development.rb
|
102
122
|
- lib/rage/templates/config-environments-production.rb
|
103
123
|
- lib/rage/templates/config-environments-test.rb
|
124
|
+
- lib/rage/templates/config-initializers-.keep
|
104
125
|
- lib/rage/templates/config-routes.rb
|
105
126
|
- lib/rage/templates/config.ru
|
106
127
|
- lib/rage/templates/lib-.keep
|