rage-rb 1.4.0 → 1.5.0

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