rage-rb 1.5.0 → 1.6.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: 24a5bc4310d226a4072c06ac0a3cb015eb52163e7c37fc85aced61f5705b6ef5
4
- data.tar.gz: 8bedd5b522c64c945a44fa4cb97e19f48d5b3a3aa46bb5687183c4cf3eac75f3
3
+ metadata.gz: 39c84f49894f7ae6e8c53e78d5c84eef65885c15f3ad7d6469458a79dba6e691
4
+ data.tar.gz: 3a8b37eb48370a2a63c1b78f09417013f60593cdbcf0385958dd495ce35e494c
5
5
  SHA512:
6
- metadata.gz: 10feb1fe42789d8470ecf9d7754be26b58db2f160f24c7e82aac8a831a5c4b828d297e01c2535b8e914d167de2bcf40a843b1964c5d1f3102ef4429016fefabd
7
- data.tar.gz: 87c3ee06201e71f691b7158f911c0cfbf7763d2021801d298885c890772082a934d91fdb5df8c0f6bf65110acd480fd839ef19d6e9adc39d1c78d165a0e2701f
6
+ metadata.gz: 8db258b1f23a58def4118ca0bdb1efcf6534ff03362ac82c45ded5276c90ab42809e007a9d7f72972dc8fd2597ac5eab2bbfaf27d6efb38a3857b1133fdbecde
7
+ data.tar.gz: eb7a5910f52399ff67bc0bc4078fcc970e023fcc038dc65dd16b19e17afa902a95a7c1b62cca7f61a5f5e38ba45702dc2a314ef841868fd7cf40289a65a0fe0f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.6.0] - 2024-07-15
4
+
5
+ ### Added
6
+
7
+ - Support legacy route helpers (#90).
8
+ - Correctly handle internal Rails routes in `Rage.multi_application` (#91).
9
+
10
+ ## [1.5.1] - 2024-05-26
11
+
12
+ ### Fixed
13
+
14
+ - Correctly reload code in multi apps (#87).
15
+
3
16
  ## [1.5.0] - 2024-05-08
4
17
 
5
18
  ### Added
data/OVERVIEW.md ADDED
@@ -0,0 +1,53 @@
1
+ ### Boot sequence and request lifecycle
2
+
3
+ The following diagram describes some of Rage's internal components and the way they interact with each other:
4
+
5
+ ![overview](https://github.com/rage-rb/rage/assets/2270393/0d45bbe3-622c-4b17-b8d8-552c567fecb3)
6
+
7
+ ### Executing controller actions
8
+
9
+ When `Rage::Router::DSL` parses the `config/routes.rb` file and calls the `Rage::Router::Backend` class, it registers actions and stores handler procs.
10
+
11
+ Consider we have the following controller:
12
+
13
+ ```ruby
14
+ class UsersController < RageController::API
15
+ before_action :find_user
16
+ rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
17
+
18
+ def show
19
+ render json: @user
20
+ end
21
+
22
+ private
23
+
24
+ def find_user
25
+ @user = User.find(params[:id])
26
+ end
27
+
28
+ def render_not_found(_)
29
+ render status: :not_found
30
+ end
31
+ end
32
+ ```
33
+
34
+ Before processing requests to `UsersController#show`, Rage has to [register](https://github.com/rage-rb/rage/blob/master/lib/rage/controller/api.rb#L10) the show action. Registering means defining a new method that will look like this:
35
+
36
+ ```ruby
37
+ class UsersController
38
+ def __run_show
39
+ find_user
40
+ show
41
+ rescue ActiveRecord::RecordNotFound => e
42
+ render_not_found(e)
43
+ end
44
+ end
45
+ ```
46
+
47
+ After that, Rage will create and store a handler proc that will look exactly like this:
48
+
49
+ ```ruby
50
+ ->(env, params) { UsersController.new(env, params).__run_show }
51
+ ```
52
+
53
+ All of this happens at boot time. Once the request comes in at runtime, Rage will only need to retrieve the handler proc defined earlier and call it.
@@ -114,7 +114,7 @@ class Rage::Configuration
114
114
  def config = self
115
115
 
116
116
  def log_formatter=(formatter)
117
- raise "Custom log formatter should respond to `#call`" unless formatter.respond_to?(:call)
117
+ raise ArgumentError, "Custom log formatter should respond to `#call`" unless formatter.respond_to?(:call)
118
118
  @log_formatter = formatter
119
119
  end
120
120
 
@@ -168,7 +168,7 @@ class RageController::API
168
168
  if block_given?
169
169
  with = define_tmp_method(block)
170
170
  else
171
- raise "No handler provided. Pass the `with` keyword argument or provide a block."
171
+ raise ArgumentError, "No handler provided. Pass the `with` keyword argument or provide a block."
172
172
  end
173
173
  end
174
174
 
@@ -224,7 +224,7 @@ class RageController::API
224
224
 
225
225
  # Register a new `after_action` hook. Calls with the same `action_name` will overwrite the previous ones.
226
226
  #
227
- # @param action_name [String, nil] the name of the callback to add
227
+ # @param action_name [Symbol, nil] the name of the callback to add
228
228
  # @param [Hash] opts action options
229
229
  # @option opts [Symbol, Array<Symbol>] :only restrict the callback to run only for specific actions
230
230
  # @option opts [Symbol, Array<Symbol>] :except restrict the callback to run for all actions except specified
@@ -250,14 +250,14 @@ class RageController::API
250
250
 
251
251
  # Prevent a `before_action` hook from running.
252
252
  #
253
- # @param action_name [String] the name of the callback to skip
253
+ # @param action_name [Symbol] the name of the callback to skip
254
254
  # @param only [Symbol, Array<Symbol>] restrict the callback to be skipped only for specific actions
255
255
  # @param except [Symbol, Array<Symbol>] restrict the callback to be skipped for all actions except specified
256
256
  # @example
257
257
  # skip_before_action :find_photo, only: :create
258
258
  def skip_before_action(action_name, only: nil, except: nil)
259
259
  i = @__before_actions&.find_index { |a| a[:name] == action_name }
260
- raise "The following action was specified to be skipped but couldn't be found: #{self}##{action_name}" unless i
260
+ raise ArgumentError, "The following action was specified to be skipped but couldn't be found: #{self}##{action_name}" unless i
261
261
 
262
262
  @__before_actions = @__before_actions.dup if @__before_actions.frozen?
263
263
 
@@ -284,7 +284,7 @@ class RageController::API
284
284
  if block_given?
285
285
  action_name = define_tmp_method(block)
286
286
  elsif action_name.nil?
287
- raise "No handler provided. Pass the `action_name` parameter or provide a block."
287
+ raise ArgumentError, "No handler provided. Pass the `action_name` parameter or provide a block."
288
288
  end
289
289
 
290
290
  _only, _except, _if, _unless = opts.values_at(:only, :except, :if, :unless)
@@ -64,7 +64,7 @@ class Rage::Cors
64
64
  @methods = if methods != "*"
65
65
  methods.map! { |method| method.to_s.upcase }.tap { |m|
66
66
  if (invalid_methods = m - @default_methods).any?
67
- raise "Unsupported method passed to Rage::Cors: #{invalid_methods[0]}"
67
+ raise ArgumentError, "Unsupported method passed to Rage::Cors: #{invalid_methods[0]}"
68
68
  end
69
69
  }.join(", ")
70
70
  elsif @allow_credentials
@@ -74,8 +74,8 @@ class Rage::Cors
74
74
  end
75
75
 
76
76
  if @allow_credentials
77
- raise "Rage::Cors requires you to explicitly list allowed headers when using `allow_credentials: true`" if @allow_headers == "*"
78
- raise "Rage::Cors requires you to explicitly list exposed headers when using `allow_credentials: true`" if @expose_headers == "*"
77
+ raise ArgumentError, "Rage::Cors requires you to explicitly list allowed headers when using `allow_credentials: true`" if @allow_headers == "*"
78
+ raise ArgumentError, "Rage::Cors requires you to explicitly list exposed headers when using `allow_credentials: true`" if @expose_headers == "*"
79
79
  end
80
80
 
81
81
  @origins = []
data/lib/rage/rails.rb CHANGED
@@ -22,12 +22,14 @@ end
22
22
  Rails.configuration.after_initialize do
23
23
  conditional_mutex = Module.new do
24
24
  def call(env)
25
- @mutex ||= Mutex.new
26
- if Rails.application.reloader.check!
27
- @mutex.synchronize { super }
25
+ res = if Rails.application.reloader.check! || !$rage_code_loaded
26
+ Fiber.new(blocking: true) { super }.resume
28
27
  else
29
28
  super
30
29
  end
30
+ $rage_code_loaded = true
31
+
32
+ res
31
33
  end
32
34
  end
33
35
 
@@ -20,7 +20,7 @@ class Rage::Router::Backend
20
20
  end
21
21
 
22
22
  def mount(path, handler, methods)
23
- raise "Mount handler should respond to `call`" unless handler.respond_to?(:call)
23
+ raise ArgumentError, "Mount handler should respond to `call`" unless handler.respond_to?(:call)
24
24
 
25
25
  raw_handler = handler
26
26
  is_sidekiq = handler.respond_to?(:name) && handler.name == "Sidekiq::Web"
@@ -52,7 +52,7 @@ class Rage::Router::Backend
52
52
  raise "Path could not be empty" if path&.empty?
53
53
 
54
54
  if match_index = (path =~ OPTIONAL_PARAM_REGEXP)
55
- raise "Optional Parameter has to be the last parameter of the path" if path.length != match_index + $&.length
55
+ raise ArgumentError, "Optional Parameter has to be the last parameter of the path" if path.length != match_index + $&.length
56
56
 
57
57
  path_full = path.sub(OPTIONAL_PARAM_REGEXP, "/#{$1}")
58
58
  path_optional = path.sub(OPTIONAL_PARAM_REGEXP, "")
@@ -65,7 +65,7 @@ class Rage::Router::Backend
65
65
  meta = { raw_handler: handler }
66
66
 
67
67
  if handler.is_a?(String)
68
- raise "Invalid route handler format, expected to match the 'controller#action' pattern" unless handler =~ STRING_HANDLER_REGEXP
68
+ raise ArgumentError, "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
71
 
@@ -81,7 +81,7 @@ class Rage::Router::Backend
81
81
  handler = ->(_, _) { [404, { "X-Cascade" => "pass" }, []] }
82
82
  end
83
83
  else
84
- raise "Non-string route handler should respond to `call`" unless handler.respond_to?(:call)
84
+ raise ArgumentError, "Non-string route handler should respond to `call`" unless handler.respond_to?(:call)
85
85
  # while regular handlers are expected to be called with the `env` and `params` objects,
86
86
  # lambda handlers expect just `env` as an argument;
87
87
  # TODO: come up with something nicer?
@@ -189,7 +189,7 @@ class Rage::Router::Backend
189
189
  params << "*"
190
190
  current_node = current_node.create_wildcard_child
191
191
  parent_node_path_index = i + 1
192
- raise "Wildcard must be the last character in the route" if i != pattern.length - 1
192
+ raise ArgumentError, "Wildcard must be the last character in the route" if i != pattern.length - 1
193
193
  end
194
194
 
195
195
  i += 1
@@ -205,7 +205,7 @@ class Rage::Router::Backend
205
205
  existing_route[:pattern] == pattern &&
206
206
  existing_route[:constraints] == constraints
207
207
  )
208
- raise "Method '#{method}' already declared for route '#{pattern}' with constraints '#{constraints.inspect}'"
208
+ raise ArgumentError, "Method '#{method}' already declared for route '#{pattern}' with constraints '#{constraints.inspect}'"
209
209
  end
210
210
  end
211
211
 
@@ -45,14 +45,14 @@ class Rage::Router::Constrainer
45
45
  end
46
46
 
47
47
  def new_store_for_constraint(constraint)
48
- raise "No strategy registered for constraint key '#{constraint}'" unless @strategies[constraint]
48
+ raise ArgumentError, "No strategy registered for constraint key '#{constraint}'" unless @strategies[constraint]
49
49
  @strategies[constraint].storage
50
50
  end
51
51
 
52
52
  def validate_constraints(constraints)
53
53
  constraints.each do |key, value|
54
54
  strategy = @strategies[key]
55
- raise "No strategy registered for constraint key '#{key}'" unless strategy
55
+ raise ArgumentError, "No strategy registered for constraint key '#{key}'" unless strategy
56
56
 
57
57
  strategy.validate(value)
58
58
  end
@@ -73,7 +73,7 @@ class Rage::Router::Constrainer
73
73
  if key == :host
74
74
  lines << " host: env['HTTP_HOST'.freeze],"
75
75
  else
76
- raise 'unknown non-custom strategy for compiling constraint derivation function'
76
+ raise ArgumentError, 'unknown non-custom strategy for compiling constraint derivation function'
77
77
  end
78
78
  else
79
79
  lines << " #{strategy.name}: @strategies[#{key}].derive_constraint(env),"
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "dsl_plugins/legacy_hash_notation"
4
+ require_relative "dsl_plugins/legacy_root_notation"
5
+ require_relative "dsl_plugins/named_route_helpers"
6
+ require_relative "dsl_plugins/controller_action_options"
7
+
3
8
  class Rage::Router::DSL
4
9
  def initialize(router)
5
10
  @router = router
@@ -47,6 +52,11 @@ class Rage::Router::DSL
47
52
  # resources :posts
48
53
  # end
49
54
  class Handler
55
+ prepend Rage::Router::DSLPlugins::ControllerActionOptions
56
+ prepend Rage::Router::DSLPlugins::NamedRouteHelpers
57
+ prepend Rage::Router::DSLPlugins::LegacyHashNotation
58
+ prepend Rage::Router::DSLPlugins::LegacyRootNotation
59
+
50
60
  # @private
51
61
  def initialize(router)
52
62
  @router = router
@@ -67,12 +77,13 @@ class Rage::Router::DSL
67
77
  # @param to [String] the route handler in the format of "controller#action"
68
78
  # @param constraints [Hash] a hash of constraints for the route
69
79
  # @param defaults [Hash] a hash of default parameters for the route
80
+ # @param on [nil, :member, :collection] a shorthand for wrapping routes in a specific RESTful context
70
81
  # @example
71
82
  # get "/photos/:id", to: "photos#show", constraints: { host: /myhost/ }
72
83
  # @example
73
84
  # get "/photos(/:id)", to: "photos#show", defaults: { id: "-1" }
74
- def get(path, to: nil, constraints: nil, defaults: nil)
75
- __on("GET", path, to, constraints, defaults)
85
+ def get(path, to: nil, constraints: nil, defaults: nil, on: nil)
86
+ __with_on_scope(on) { __on("GET", path, to, constraints, defaults) }
76
87
  end
77
88
 
78
89
  # Register a new POST route.
@@ -81,12 +92,13 @@ class Rage::Router::DSL
81
92
  # @param to [String] the route handler in the format of "controller#action"
82
93
  # @param constraints [Hash] a hash of constraints for the route
83
94
  # @param defaults [Hash] a hash of default parameters for the route
95
+ # @param on [nil, :member, :collection] a shorthand for wrapping routes in a specific RESTful context
84
96
  # @example
85
97
  # post "/photos", to: "photos#create", constraints: { host: /myhost/ }
86
98
  # @example
87
99
  # post "/photos", to: "photos#create", defaults: { format: "jpg" }
88
- def post(path, to: nil, constraints: nil, defaults: nil)
89
- __on("POST", path, to, constraints, defaults)
100
+ def post(path, to: nil, constraints: nil, defaults: nil, on: nil)
101
+ __with_on_scope(on) { __on("POST", path, to, constraints, defaults) }
90
102
  end
91
103
 
92
104
  # Register a new PUT route.
@@ -95,12 +107,13 @@ class Rage::Router::DSL
95
107
  # @param to [String] the route handler in the format of "controller#action"
96
108
  # @param constraints [Hash] a hash of constraints for the route
97
109
  # @param defaults [Hash] a hash of default parameters for the route
110
+ # @param on [nil, :member, :collection] a shorthand for wrapping routes in a specific RESTful context
98
111
  # @example
99
112
  # put "/photos/:id", to: "photos#update", constraints: { host: /myhost/ }
100
113
  # @example
101
114
  # put "/photos(/:id)", to: "photos#update", defaults: { id: "-1" }
102
- def put(path, to: nil, constraints: nil, defaults: nil)
103
- __on("PUT", path, to, constraints, defaults)
115
+ def put(path, to: nil, constraints: nil, defaults: nil, on: nil)
116
+ __with_on_scope(on) { __on("PUT", path, to, constraints, defaults) }
104
117
  end
105
118
 
106
119
  # Register a new PATCH route.
@@ -109,12 +122,13 @@ class Rage::Router::DSL
109
122
  # @param to [String] the route handler in the format of "controller#action"
110
123
  # @param constraints [Hash] a hash of constraints for the route
111
124
  # @param defaults [Hash] a hash of default parameters for the route
125
+ # @param on [nil, :member, :collection] a shorthand for wrapping routes in a specific RESTful context
112
126
  # @example
113
127
  # patch "/photos/:id", to: "photos#update", constraints: { host: /myhost/ }
114
128
  # @example
115
129
  # patch "/photos(/:id)", to: "photos#update", defaults: { id: "-1" }
116
- def patch(path, to: nil, constraints: nil, defaults: nil)
117
- __on("PATCH", path, to, constraints, defaults)
130
+ def patch(path, to: nil, constraints: nil, defaults: nil, on: nil)
131
+ __with_on_scope(on) { __on("PATCH", path, to, constraints, defaults) }
118
132
  end
119
133
 
120
134
  # Register a new DELETE route.
@@ -123,12 +137,13 @@ class Rage::Router::DSL
123
137
  # @param to [String] the route handler in the format of "controller#action"
124
138
  # @param constraints [Hash] a hash of constraints for the route
125
139
  # @param defaults [Hash] a hash of default parameters for the route
140
+ # @param on [nil, :member, :collection] a shorthand for wrapping routes in a specific RESTful context
126
141
  # @example
127
142
  # delete "/photos/:id", to: "photos#destroy", constraints: { host: /myhost/ }
128
143
  # @example
129
144
  # delete "/photos(/:id)", to: "photos#destroy", defaults: { id: "-1" }
130
- def delete(path, to: nil, constraints: nil, defaults: nil)
131
- __on("DELETE", path, to, constraints, defaults)
145
+ def delete(path, to: nil, constraints: nil, defaults: nil, on: nil)
146
+ __with_on_scope(on) { __on("DELETE", path, to, constraints, defaults) }
132
147
  end
133
148
 
134
149
  # Register a new route pointing to '/'.
@@ -207,9 +222,9 @@ class Rage::Router::DSL
207
222
  # Scopes a set of routes to the given default options.
208
223
  #
209
224
  # @param [Hash] opts scope options.
210
- # @option opts [String] :module module option
211
- # @option opts [String] :path path option
212
- # @option opts [String] :controller controller option
225
+ # @option opts [String] :module the namespace for the controller
226
+ # @option opts [String] :path the path prefix for the routes
227
+ # @option opts [String] :controller scopes routes to a specific controller
213
228
  # @example Route `/photos` to `Api::PhotosController`
214
229
  # scope module: "api" do
215
230
  # get "photos", to: "photos#index"
@@ -309,6 +324,12 @@ class Rage::Router::DSL
309
324
 
310
325
  # Automatically create REST routes for a resource.
311
326
  #
327
+ # @param [Hash] opts resource options
328
+ # @option opts [String] :module the namespace for the controller
329
+ # @option opts [String] :path the path prefix for the routes
330
+ # @option opts [Symbol, Array<Symbol>] :only only generate routes for the given actions
331
+ # @option opts [Symbol, Array<Symbol>] :except generate all routes except for the given actions
332
+ # @option opts [String] :param overrides the default param name of `:id` in the URL
312
333
  # @example Create five REST routes, all mapping to the `Photos` controller:
313
334
  # resources :photos
314
335
  # # GET /photos => photos#index
@@ -325,7 +346,7 @@ class Rage::Router::DSL
325
346
  end
326
347
 
327
348
  _module, _path, _only, _except, _param = opts.values_at(:module, :path, :only, :except, :param)
328
- raise ":param option can't contain colons" if _param.to_s.include?(":")
349
+ raise ArgumentError, ":param option can't contain colons" if _param.to_s.include?(":")
329
350
 
330
351
  _only = Array(_only) if _only
331
352
  _except = Array(_except) if _except
@@ -358,17 +379,7 @@ class Rage::Router::DSL
358
379
  # mount Sidekiq::Web => "/sidekiq"
359
380
  # @example
360
381
  # mount Sidekiq::Web, at: "/sidekiq", via: :get
361
- def mount(*args)
362
- if args.first.is_a?(Hash)
363
- app = args.first.keys.first
364
- at = args.first.values.first
365
- via = args[0][:via]
366
- else
367
- app = args.first
368
- at = args[1][:at]
369
- via = args[1][:via]
370
- end
371
-
382
+ def mount(app, at:, via: :all)
372
383
  at = "/#{at}" unless at.start_with?("/")
373
384
  at = at.delete_suffix("/") if at.end_with?("/")
374
385
 
@@ -395,7 +406,7 @@ class Rage::Router::DSL
395
406
  if @controllers.any?
396
407
  to = "#{@controllers.last}##{path}"
397
408
  else
398
- raise "Missing :to key on routes definition, please check your routes."
409
+ raise ArgumentError, "Missing :to key on routes definition, please check your routes."
399
410
  end
400
411
  end
401
412
 
@@ -421,6 +432,19 @@ class Rage::Router::DSL
421
432
  end
422
433
  end
423
434
 
435
+ def __with_on_scope(on, &block)
436
+ case on
437
+ when nil
438
+ block.call
439
+ when :member
440
+ member(&block)
441
+ when :collection
442
+ collection(&block)
443
+ else
444
+ raise ArgumentError, "Unknown scope :#{on} given to :on"
445
+ end
446
+ end
447
+
424
448
  def to_singular(str)
425
449
  @active_support_loaded ||= str.respond_to?(:singularize) || :false
426
450
  return str.singularize if @active_support_loaded != :false
@@ -0,0 +1,25 @@
1
+ ##
2
+ # Support the `:controller` and `:action` options.
3
+ #
4
+ # @example
5
+ # get :admins, controller: :users
6
+ # @example
7
+ # post :search, action: :index
8
+ module Rage::Router::DSLPlugins::ControllerActionOptions
9
+ %i(get post put patch delete).each do |action_name|
10
+ define_method(action_name) do |*args, **kwargs|
11
+ if args.length == 1 && !kwargs.has_key?(:to) && (kwargs.has_key?(:controller) || kwargs.has_key?(:action))
12
+ path = args[0]
13
+ controller = kwargs.delete(:controller) || @controllers.last || raise(ArgumentError, "Could not derive the controller value from the route definitions")
14
+ action = kwargs.delete(:action) || path.split("/").last
15
+ end
16
+
17
+ if controller && action
18
+ kwargs[:to] = "#{controller}##{action}"
19
+ super(path, **kwargs)
20
+ else
21
+ super(*args, **kwargs)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,46 @@
1
+ ##
2
+ # Support legacy URL helpers that use hashes instead of the `:to` keyword argument.
3
+ #
4
+ # @example
5
+ # get "/photos/:id" => "photos#show"
6
+ # @example
7
+ # mount Sidekiq::Web => "/sidekiq"
8
+ # @example
9
+ # get "search" => :index
10
+ # @example
11
+ # get "admin_users" => "users"
12
+ module Rage::Router::DSLPlugins::LegacyHashNotation
13
+ %i(get post put patch delete).each do |action_name|
14
+ define_method(action_name) do |*args, **kwargs|
15
+ if args.empty? && !kwargs.empty?
16
+ path, handler = kwargs.first
17
+
18
+ to = if handler.is_a?(Symbol)
19
+ raise ArgumentError, "Could not derive the controller value from the route definitions" if @controllers.empty?
20
+ "#{@controllers.last}##{handler}"
21
+ elsif handler.is_a?(String) && !handler.include?("#")
22
+ "#{handler}##{path.split("/").last}"
23
+ elsif handler.is_a?(String)
24
+ handler
25
+ end
26
+ end
27
+
28
+ if path && to
29
+ options = kwargs.except(path).merge(to: to)
30
+ super(path, **options)
31
+ else
32
+ super(*args, **kwargs)
33
+ end
34
+ end
35
+ end
36
+
37
+ def mount(*args, **kwargs)
38
+ if args.empty? && !kwargs.empty?
39
+ app, at = kwargs.first
40
+ options = kwargs.except(app).merge(at: at)
41
+ super(app, **options)
42
+ else
43
+ super(*args, **kwargs)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,14 @@
1
+ ##
2
+ # Support legacy root helpers that don't use the `:to` keyword argument.
3
+ #
4
+ # @example
5
+ # root "photos#index"
6
+ module Rage::Router::DSLPlugins::LegacyRootNotation
7
+ def root(*args, **kwargs)
8
+ if args.length == 1 && args[0].is_a?(String) && kwargs.empty?
9
+ super(to: args[0])
10
+ else
11
+ super(*args, **kwargs)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ ##
2
+ # Support the `as` option. As Rage currently doesn't generate named route helpers, we simply ignore it.
3
+ #
4
+ # @example
5
+ # get "/photos/:id", to: "photos#show", as: :user_photos
6
+ module Rage::Router::DSLPlugins::NamedRouteHelpers
7
+ %i(get post put patch delete).each do |action_name|
8
+ define_method(action_name) do |*args, **kwargs|
9
+ kwargs.delete(:as)
10
+ super(*args, **kwargs)
11
+ end
12
+ end
13
+ end
@@ -35,7 +35,7 @@ class Rage::Router::HandlerStorage
35
35
  end
36
36
 
37
37
  if @handlers.length >= 32
38
- raise "Limit reached: a maximum of 32 route handlers per node allowed when there are constraints"
38
+ raise ArgumentError, "Limit reached: a maximum of 32 route handlers per node allowed when there are constraints"
39
39
  end
40
40
 
41
41
  @handlers << handler_object
@@ -18,7 +18,7 @@ class Rage::Router::Strategies::Host
18
18
 
19
19
  def validate(value)
20
20
  if !value.is_a?(String) && !value.is_a?(Regexp)
21
- raise "Host should be a string or a Regexp"
21
+ raise ArgumentError, "Host should be a string or a Regexp"
22
22
  end
23
23
  end
24
24
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Rage::Router::Util
2
4
  class << self
3
5
  # converts controller name in a path form into a class
@@ -40,9 +42,13 @@ class Rage::Router::Util
40
42
 
41
43
  def call(env)
42
44
  result = @rage_app.call(env)
43
- return result if result[0] == :__http_defer__ || result[1]["X-Cascade".freeze] != "pass".freeze
45
+ return result if result[0] == :__http_defer__
44
46
 
45
- @rails_app.call(env)
47
+ if result[1]["X-Cascade"] == "pass" || env["PATH_INFO"].start_with?("/rails/")
48
+ @rails_app.call(env)
49
+ else
50
+ result
51
+ end
46
52
  end
47
53
  end
48
54
  end
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.5.0"
4
+ VERSION = "1.6.0"
5
5
  end
data/lib/rage-rb.rb CHANGED
@@ -93,6 +93,9 @@ module Rage
93
93
  module Router
94
94
  module Strategies
95
95
  end
96
+
97
+ module DSLPlugins
98
+ end
96
99
  end
97
100
 
98
101
  module Ext
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.5.0
4
+ version: 1.6.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-08 00:00:00.000000000 Z
11
+ date: 2024-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -94,6 +94,7 @@ files:
94
94
  - CODE_OF_CONDUCT.md
95
95
  - Gemfile
96
96
  - LICENSE.txt
97
+ - OVERVIEW.md
97
98
  - README.md
98
99
  - Rakefile
99
100
  - exe/rage
@@ -126,6 +127,10 @@ files:
126
127
  - lib/rage/router/backend.rb
127
128
  - lib/rage/router/constrainer.rb
128
129
  - lib/rage/router/dsl.rb
130
+ - lib/rage/router/dsl_plugins/controller_action_options.rb
131
+ - lib/rage/router/dsl_plugins/legacy_hash_notation.rb
132
+ - lib/rage/router/dsl_plugins/legacy_root_notation.rb
133
+ - lib/rage/router/dsl_plugins/named_route_helpers.rb
129
134
  - lib/rage/router/handler_storage.rb
130
135
  - lib/rage/router/node.rb
131
136
  - lib/rage/router/strategies/host.rb