rage-rb 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +3 -1
- data/lib/rage/all.rb +1 -0
- data/lib/rage/application.rb +14 -27
- data/lib/rage/cli.rb +7 -0
- data/lib/rage/configuration.rb +41 -0
- data/lib/rage/env.rb +34 -0
- data/lib/rage/fiber.rb +10 -0
- data/lib/rage/fiber_wrapper.rb +28 -0
- data/lib/rage/templates/config.ru +1 -0
- data/lib/rage/version.rb +1 -1
- data/lib/rage-rb.rb +9 -1
- data/rage.gemspec +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: abee0787faa5947d8ecb03f9c5851cb669295bc2bd52abe5513e7b10940ddfff
|
4
|
+
data.tar.gz: d167a4d6a48dbced809578f3c3a569c5ccdb913ed7bf51eba3e8d054b61e1c75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eea4d03aa25b675fdf1f19836037dceaeb7f38e2227af9cafc1609d59b8f322d3e3fa49da7905b4c0dd783615d16ce6e592aa11f2fa934056d711f03aaafbb43
|
7
|
+
data.tar.gz: adf6eaaee9a88eef39631581ce52eaa311b5ac61797f481a95e28502ccabf166615a87e215b5f5b3260ebdfbb5c28f8c32e1e8342566d9d23836e56eb97b14d8
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
|
5
5
|
[![Gem Version](https://badge.fury.io/rb/rage-rb.svg)](https://badge.fury.io/rb/rage-rb)
|
6
6
|
![Tests](https://github.com/rage-rb/rage/actions/workflows/main.yml/badge.svg)
|
7
|
+
![Ruby Requirement](https://img.shields.io/badge/Ruby-3.1%2B-%23f40000)
|
8
|
+
|
7
9
|
|
8
10
|
Inspired by [Deno](https://deno.com) and built on top of [Iodine](https://github.com/rage-rb/iodine), this is a Ruby web framework that is based on the following design principles:
|
9
11
|
|
@@ -11,7 +13,7 @@ Inspired by [Deno](https://deno.com) and built on top of [Iodine](https://github
|
|
11
13
|
|
12
14
|
* **High performance** - some think performance is not a major metric for a framework, but it's not true. Poor performance is a risk, and in today's world, companies refuse to use risky technologies.
|
13
15
|
|
14
|
-
* **API-only** -
|
16
|
+
* **API-only** - separation of concerns is one of the most fundamental principles in software development. Backend and frontend are very different layers with different goals and paths to those goals. Separating BE code from FE code results in a much more sustainable architecture compared with classic Rails monoliths.
|
15
17
|
|
16
18
|
* **Acceptance of modern Ruby** - the framework includes a fiber scheduler, which means your code never blocks while waiting on IO.
|
17
19
|
|
data/lib/rage/all.rb
CHANGED
data/lib/rage/application.rb
CHANGED
@@ -2,41 +2,28 @@
|
|
2
2
|
|
3
3
|
class Rage::Application
|
4
4
|
def initialize(router)
|
5
|
-
Iodine.on_state(:on_start) do
|
6
|
-
Fiber.set_scheduler(Rage::FiberScheduler.new)
|
7
|
-
end
|
8
5
|
@router = router
|
9
6
|
end
|
10
7
|
|
11
8
|
def call(env)
|
12
|
-
|
13
|
-
init_logger
|
14
|
-
|
15
|
-
handler = @router.lookup(env)
|
9
|
+
init_logger
|
16
10
|
|
17
|
-
|
18
|
-
params = Rage::ParamsParser.prepare(env, handler[:params])
|
19
|
-
handler[:handler].call(env, params)
|
20
|
-
else
|
21
|
-
[404, {}, ["Not Found"]]
|
22
|
-
end
|
11
|
+
handler = @router.lookup(env)
|
23
12
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
response = [500, {}, [exception_str]]
|
28
|
-
|
29
|
-
ensure
|
30
|
-
finalize_logger(env, response, params)
|
31
|
-
Iodine.publish(env["IODINE_REQUEST_ID"], "") # notify Iodine the request can now be served
|
32
|
-
end
|
33
|
-
|
34
|
-
# the fiber encountered blocking IO and yielded; instruct Iodine to pause the request;
|
35
|
-
if fiber.alive?
|
36
|
-
[:__http_defer__, fiber]
|
13
|
+
response = if handler
|
14
|
+
params = Rage::ParamsParser.prepare(env, handler[:params])
|
15
|
+
handler[:handler].call(env, params)
|
37
16
|
else
|
38
|
-
|
17
|
+
[404, {}, ["Not Found"]]
|
39
18
|
end
|
19
|
+
|
20
|
+
rescue Exception => e
|
21
|
+
exception_str = "#{e.class} (#{e.message}):\n#{e.backtrace.join("\n")}"
|
22
|
+
Rage.logger.error(exception_str)
|
23
|
+
response = [500, {}, [exception_str]]
|
24
|
+
|
25
|
+
ensure
|
26
|
+
finalize_logger(env, response, params)
|
40
27
|
end
|
41
28
|
|
42
29
|
private
|
data/lib/rage/cli.rb
CHANGED
@@ -20,6 +20,13 @@ module Rage
|
|
20
20
|
app = ::Rack::Builder.parse_file("config.ru")
|
21
21
|
app = app[0] if app.is_a?(Array)
|
22
22
|
|
23
|
+
unless app.is_a?(Rage::FiberWrapper)
|
24
|
+
raise <<-ERR
|
25
|
+
Couldn't find the default middleware. Make sure to add the following line to your config.ru file:
|
26
|
+
Rage.load_middlewares(self)
|
27
|
+
ERR
|
28
|
+
end
|
29
|
+
|
23
30
|
::Iodine.listen service: :http, handler: app, port: options[:port] || Rage.config.server.port
|
24
31
|
::Iodine.threads = Rage.config.server.threads_count
|
25
32
|
::Iodine.workers = Rage.config.server.workers_count
|
data/lib/rage/configuration.rb
CHANGED
@@ -8,6 +8,10 @@ class Rage::Configuration
|
|
8
8
|
@server ||= Server.new
|
9
9
|
end
|
10
10
|
|
11
|
+
def middleware
|
12
|
+
@middleware ||= Middleware.new
|
13
|
+
end
|
14
|
+
|
11
15
|
class Server
|
12
16
|
attr_accessor :port, :workers_count
|
13
17
|
attr_reader :threads_count
|
@@ -19,6 +23,43 @@ class Rage::Configuration
|
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
26
|
+
class Middleware
|
27
|
+
attr_reader :middlewares
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@middlewares = [[Rage::FiberWrapper]]
|
31
|
+
end
|
32
|
+
|
33
|
+
def use(new_middleware, *args, &block)
|
34
|
+
insert_after(@middlewares.length - 1, new_middleware, *args, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def insert_before(existing_middleware, new_middleware, *args, &block)
|
38
|
+
index = find_middleware_index(existing_middleware)
|
39
|
+
@middlewares = (@middlewares[0...index] + [[new_middleware, args, block]] + @middlewares[index..]).uniq(&:first)
|
40
|
+
end
|
41
|
+
|
42
|
+
def insert_after(existing_middleware, new_middleware, *args, &block)
|
43
|
+
index = find_middleware_index(existing_middleware)
|
44
|
+
@middlewares = (@middlewares[0..index] + [[new_middleware, args, block]] + @middlewares[index + 1..]).uniq(&:first)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def find_middleware_index(middleware)
|
50
|
+
if middleware.is_a?(Integer)
|
51
|
+
if middleware < 0 || middleware >= @middlewares.length
|
52
|
+
raise ArgumentError, "Middleware index should be in the (0...#{@middlewares.length}) range"
|
53
|
+
end
|
54
|
+
middleware
|
55
|
+
else
|
56
|
+
@middlewares.index { |m, _, _| m == middleware }.tap do |i|
|
57
|
+
raise ArgumentError, "Couldn't find #{middleware} in the middleware stack" unless i
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
22
63
|
def __finalize
|
23
64
|
@logger ||= Rage::Logger.new(nil)
|
24
65
|
@logger.formatter = @log_formatter if @logger && @log_formatter
|
data/lib/rage/env.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Rage::Env
|
4
|
+
STANDARD_ENVS = %w(development test staging production)
|
5
|
+
|
6
|
+
def initialize(env)
|
7
|
+
@env = env
|
8
|
+
|
9
|
+
STANDARD_ENVS.each do |standard_env|
|
10
|
+
self.class.define_method("#{standard_env}?") { false } if standard_env != @env
|
11
|
+
end
|
12
|
+
self.class.define_method("#{@env}?") { true }
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(method_name, *, &)
|
16
|
+
method_name.end_with?("?") ? false : super
|
17
|
+
end
|
18
|
+
|
19
|
+
def respond_to_missing?(method_name, include_private = false)
|
20
|
+
method_name.end_with?("?")
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(other)
|
24
|
+
@env == other
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_sym
|
28
|
+
@env.to_sym
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
@env
|
33
|
+
end
|
34
|
+
end
|
data/lib/rage/fiber.rb
CHANGED
@@ -23,6 +23,16 @@ class Fiber
|
|
23
23
|
@__err
|
24
24
|
end
|
25
25
|
|
26
|
+
# @private
|
27
|
+
def __get_id
|
28
|
+
@__rage_id ||= object_id.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
# @private
|
32
|
+
def __yielded?
|
33
|
+
!@__rage_id.nil?
|
34
|
+
end
|
35
|
+
|
26
36
|
# @private
|
27
37
|
# pause a fiber and resume in the next iteration of the event loop
|
28
38
|
def self.pause
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The middleware wraps every request in a Fiber and implements the custom defer protocol with Iodine.
|
5
|
+
# Scheduling fibers in a middleware allows the framework to be compatibe with custom Rack middlewares.
|
6
|
+
#
|
7
|
+
class Rage::FiberWrapper
|
8
|
+
def initialize(app)
|
9
|
+
Iodine.on_state(:on_start) do
|
10
|
+
Fiber.set_scheduler(Rage::FiberScheduler.new)
|
11
|
+
end
|
12
|
+
@app = app
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
fiber = Fiber.schedule do
|
17
|
+
@app.call(env)
|
18
|
+
ensure
|
19
|
+
Iodine.publish(Fiber.current.__get_id, "", Iodine::PubSub::PROCESS) if Fiber.current.__yielded?
|
20
|
+
end
|
21
|
+
|
22
|
+
if fiber.alive?
|
23
|
+
[:__http_defer__, fiber]
|
24
|
+
else
|
25
|
+
fiber.__get_result
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
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 ||= ENV["RAGE_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
31
|
+
@__env ||= Rage::Env.new(ENV["RAGE_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development")
|
32
32
|
end
|
33
33
|
|
34
34
|
def self.groups
|
@@ -43,6 +43,12 @@ module Rage
|
|
43
43
|
@logger ||= config.logger
|
44
44
|
end
|
45
45
|
|
46
|
+
def self.load_middlewares(rack_builder)
|
47
|
+
config.middleware.middlewares.each do |middleware, args, block|
|
48
|
+
rack_builder.use(middleware, *args, &block)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
46
52
|
module Router
|
47
53
|
module Strategies
|
48
54
|
end
|
@@ -51,3 +57,5 @@ end
|
|
51
57
|
|
52
58
|
module RageController
|
53
59
|
end
|
60
|
+
|
61
|
+
require_relative "rage/env"
|
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.5.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roman Samoilov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-12-
|
11
|
+
date: 2023-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '3.0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '3.0'
|
55
55
|
description:
|
56
56
|
email:
|
57
57
|
- rsamoi@icloud.com
|
@@ -76,9 +76,11 @@ files:
|
|
76
76
|
- lib/rage/cli.rb
|
77
77
|
- lib/rage/configuration.rb
|
78
78
|
- lib/rage/controller/api.rb
|
79
|
+
- lib/rage/env.rb
|
79
80
|
- lib/rage/errors.rb
|
80
81
|
- lib/rage/fiber.rb
|
81
82
|
- lib/rage/fiber_scheduler.rb
|
83
|
+
- lib/rage/fiber_wrapper.rb
|
82
84
|
- lib/rage/logger/logger.rb
|
83
85
|
- lib/rage/logger/text_formatter.rb
|
84
86
|
- lib/rage/params_parser.rb
|