rage-rb 1.4.0 → 1.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43393d351828980659e1a5e574887b818727744bf679bca2c1e0e0a164848496
4
- data.tar.gz: d732652d4966c9cdcdd1825ec692b6c88286e467c229a2e4acdb7658e2b0a455
3
+ metadata.gz: 24a5bc4310d226a4072c06ac0a3cb015eb52163e7c37fc85aced61f5705b6ef5
4
+ data.tar.gz: 8bedd5b522c64c945a44fa4cb97e19f48d5b3a3aa46bb5687183c4cf3eac75f3
5
5
  SHA512:
6
- metadata.gz: e23ca7a0309a24e665850c6c7798a3a4d7cb5dd5d8f239346907bc2be0ae3c6446530e5299e2f5a6b08f773281a8e3c570dc19b9ebe1f6cbe1b0712b643ed688
7
- data.tar.gz: 9578c4f912c7ce713639acd0c043de9f4b757ff816e60dd5ae9637434699190d8c84af29a0a42fd7c0f0f32ae6724b710429cde6fab20011c23fd79bade36d13
6
+ metadata.gz: 10feb1fe42789d8470ecf9d7754be26b58db2f160f24c7e82aac8a831a5c4b828d297e01c2535b8e914d167de2bcf40a843b1964c5d1f3102ef4429016fefabd
7
+ data.tar.gz: 87c3ee06201e71f691b7158f911c0cfbf7763d2021801d298885c890772082a934d91fdb5df8c0f6bf65110acd480fd839ef19d6e9adc39d1c78d165a0e2701f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.5.0] - 2024-05-08
4
+
5
+ ### Added
6
+
7
+ - Allow to have both Rails and Rage controllers in one application (#83).
8
+ - Add `authenticate_or_request_with_http_token` (#85).
9
+ - Add the `member` and `controller` route helpers (#86).
10
+
11
+ ### Changed
12
+
13
+ - Deprecate `Rage.load_middlewares` (#83).
14
+
15
+ ### Fixed
16
+
17
+ - Correctly init console in Rails mode (credit to [efibootmgr](https://github.com/efibootmgr)) (#84).
18
+
3
19
  ## [1.4.0] - 2024-05-01
4
20
 
5
21
  ### Added
data/README.md CHANGED
@@ -155,8 +155,8 @@ Status | Changes
155
155
  :white_check_mark: | ~~Add request logging.~~
156
156
  :white_check_mark: | ~~Automatic code reloading in development with Zeitwerk.~~
157
157
  :white_check_mark: | ~~Support conditional get with `etag` and `last_modified`.~~
158
+ :white_check_mark: | ~~Expose the `cookies` and `session` objects.~~
158
159
  ⏳ | Expose the `send_data` and `send_file` methods.
159
- ⏳ | Expose the `cookies` and `session` objects.
160
160
  ⏳ | Implement Iodine-based equivalent of Action Cable.
161
161
 
162
162
  ## Development
data/lib/rage/cli.rb CHANGED
@@ -116,10 +116,8 @@ module Rage
116
116
  def environment
117
117
  require File.expand_path("config/application.rb", Dir.pwd)
118
118
 
119
- # in Rails mode we delegate code loading to Rails, and thus need
120
- # to manually load application code for CLI utilities to work
121
119
  if Rage.config.internal.rails_mode
122
- require "rage/setup"
120
+ require File.expand_path("config/environment.rb", Dir.pwd)
123
121
  end
124
122
  end
125
123
 
@@ -428,6 +428,28 @@ class RageController::API
428
428
  yield token
429
429
  end
430
430
 
431
+ # Authenticate using an HTTP Bearer token, or otherwise render an HTTP header requesting the client to send a
432
+ # Bearer token. For the authentication to be considered successful, the block should return a non-nil value.
433
+ #
434
+ # @yield [token] token value extracted from the `Authorization` header
435
+ # @example
436
+ # before_action :authenticate
437
+ #
438
+ # def authenticate
439
+ # authenticate_or_request_with_http_token do |token|
440
+ # ApiToken.find_by(token: token)
441
+ # end
442
+ # end
443
+ def authenticate_or_request_with_http_token
444
+ authenticate_with_http_token { |token| yield(token) } || request_http_token_authentication
445
+ end
446
+
447
+ # Render an HTTP header requesting the client to send a Bearer token for authentication.
448
+ def request_http_token_authentication
449
+ headers["Www-Authenticate"] = "Token"
450
+ render plain: "HTTP Token: Access denied.", status: 401
451
+ end
452
+
431
453
  if !defined?(::ActionController::Parameters)
432
454
  # Get the request data. The keys inside the hash are symbols, so `params.keys` returns an array of `Symbol`.<br>
433
455
  # You can also load Strong Params to have Rage automatically wrap `params` in an instance of `ActionController::Parameters`.<br>
@@ -68,12 +68,18 @@ class Rage::Router::Backend
68
68
  raise "Invalid route handler format, expected to match the 'controller#action' pattern" unless handler =~ STRING_HANDLER_REGEXP
69
69
 
70
70
  controller, action = Rage::Router::Util.path_to_class($1), $2
71
- run_action_method_name = controller.__register_action(action.to_sym)
72
71
 
73
- meta[:controller] = $1
74
- meta[:action] = $2
72
+ if controller.ancestors.include?(RageController::API)
73
+ run_action_method_name = controller.__register_action(action.to_sym)
75
74
 
76
- handler = eval("->(env, params) { #{controller}.new(env, params).#{run_action_method_name} }")
75
+ meta[:controller] = $1
76
+ meta[:action] = $2
77
+
78
+ handler = eval("->(env, params) { #{controller}.new(env, params).#{run_action_method_name} }")
79
+ else
80
+ # this is a Rails controller; notify `Rage::Router::Util::Cascade` to forward the request to Rails
81
+ handler = ->(_, _) { [404, { "X-Cascade" => "pass" }, []] }
82
+ end
77
83
  else
78
84
  raise "Non-string route handler should respond to `call`" unless handler.respond_to?(:call)
79
85
  # while regular handlers are expected to be called with the `env` and `params` objects,
@@ -209,6 +209,7 @@ class Rage::Router::DSL
209
209
  # @param [Hash] opts scope options.
210
210
  # @option opts [String] :module module option
211
211
  # @option opts [String] :path path option
212
+ # @option opts [String] :controller controller option
212
213
  # @example Route `/photos` to `Api::PhotosController`
213
214
  # scope module: "api" do
214
215
  # get "photos", to: "photos#index"
@@ -217,6 +218,11 @@ class Rage::Router::DSL
217
218
  # scope path: "admin" do
218
219
  # get "photos", to: "photos#index"
219
220
  # end
221
+ # @example Route `/like` to `photos#like` and `/dislike` to `photos#dislike`
222
+ # scope controller: "photos" do
223
+ # post "like"
224
+ # post "dislike"
225
+ # end
220
226
  # @example Nested calls
221
227
  # scope module: "admin" do
222
228
  # get "photos", to: "photos#index"
@@ -252,6 +258,19 @@ class Rage::Router::DSL
252
258
  @defaults.pop
253
259
  end
254
260
 
261
+ # Scopes routes to a specific controller.
262
+ #
263
+ # @example
264
+ # controller "photos" do
265
+ # post "like"
266
+ # post "dislike"
267
+ # end
268
+ def controller(controller, &block)
269
+ @controllers << controller
270
+ instance_eval &block
271
+ @controllers.pop
272
+ end
273
+
255
274
  # Add a route to the collection.
256
275
  #
257
276
  # @example Add a `photos/search` path instead of `photos/:photo_id/search`
@@ -267,6 +286,27 @@ class Rage::Router::DSL
267
286
  @path_prefixes = orig_path_prefixes
268
287
  end
269
288
 
289
+ # Add a member route.
290
+ #
291
+ # @example Add a `photos/:id/preview` path instead of `photos/:photo_id/preview`
292
+ # resources :photos do
293
+ # member do
294
+ # get "preview"
295
+ # end
296
+ # end
297
+ def member(&block)
298
+ orig_path_prefixes = @path_prefixes
299
+
300
+ if (param_prefix = @path_prefixes.last)&.start_with?(":") && @controllers.any?
301
+ member_prefix = param_prefix.delete_prefix(":#{to_singular(@controllers.last)}_")
302
+ @path_prefixes = [*@path_prefixes[0...-1], ":#{member_prefix}"]
303
+ end
304
+
305
+ instance_eval &block
306
+
307
+ @path_prefixes = orig_path_prefixes
308
+ end
309
+
270
310
  # Automatically create REST routes for a resource.
271
311
  #
272
312
  # @example Create five REST routes, all mapping to the `Photos` controller:
@@ -30,4 +30,19 @@ class Rage::Router::Util
30
30
  end
31
31
  end
32
32
  end
33
+
34
+ # @private
35
+ class Cascade
36
+ def initialize(rage_app, rails_app)
37
+ @rage_app = rage_app
38
+ @rails_app = rails_app
39
+ end
40
+
41
+ def call(env)
42
+ result = @rage_app.call(env)
43
+ return result if result[0] == :__http_defer__ || result[1]["X-Cascade".freeze] != "pass".freeze
44
+
45
+ @rails_app.call(env)
46
+ end
47
+ end
33
48
  end
@@ -1,4 +1,3 @@
1
1
  require_relative "config/application"
2
2
 
3
3
  run Rage.application
4
- Rage.load_middlewares(self)
data/lib/rage/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rage
4
- VERSION = "1.4.0"
4
+ VERSION = "1.5.0"
5
5
  end
data/lib/rage-rb.rb CHANGED
@@ -7,7 +7,25 @@ require "pathname"
7
7
 
8
8
  module Rage
9
9
  def self.application
10
- Application.new(__router)
10
+ app = Application.new(__router)
11
+
12
+ config.middleware.middlewares.reverse.inject(app) do |next_in_chain, (middleware, args, block)|
13
+ # in Rails compatibility mode we first check if the middleware is a part of the Rails middleware stack;
14
+ # if it is - it is expected to be built using `ActionDispatch::MiddlewareStack::Middleware#build`
15
+ if Rage.config.internal.rails_mode
16
+ rails_middleware = Rails.application.config.middleware.middlewares.find { |m| m.name == middleware.name }
17
+ end
18
+
19
+ if rails_middleware
20
+ rails_middleware.build(next_in_chain)
21
+ else
22
+ middleware.new(next_in_chain, *args, &block)
23
+ end
24
+ end
25
+ end
26
+
27
+ def self.multi_application
28
+ Rage::Router::Util::Cascade.new(application, Rails.application)
11
29
  end
12
30
 
13
31
  def self.routes
@@ -43,28 +61,8 @@ module Rage
43
61
  @logger ||= config.logger
44
62
  end
45
63
 
46
- def self.load_middlewares(rack_builder)
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
-
66
- rack_builder.use(middleware, *args, &block)
67
- end
64
+ def self.load_middlewares(_)
65
+ puts "`Rage.load_middlewares` is deprecated and has been merged into `Rage.application`. Please remove this call."
68
66
  end
69
67
 
70
68
  def self.code_loader
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: 1.4.0
4
+ version: 1.5.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: 2024-05-01 00:00:00.000000000 Z
11
+ date: 2024-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor