rage-rb 1.5.1 → 1.7.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: bef8e2aac71af98b85e2946c5ce14a8869126743cc07a023eb5a051606345968
4
- data.tar.gz: e9ebad8ddc354ed3d21bc466f5bc24b409c95510c22d8664bf47bfbef90da9d8
3
+ metadata.gz: 61d3c256494b63668809f556d221c9dd86b1542ce30051c689e1f30a7b1aca00
4
+ data.tar.gz: 268fc8606e772b06985effe6918270f2ecb1c21b191bfa59ae9a74c0eeb8f459
5
5
  SHA512:
6
- metadata.gz: 3ab1605a8d6c07c9ab155c3b554ae8e51f17f09f02db1edda13c92916a4cddd4e7539c8d24e4a716253d2638c844324de187d527d4f15c733e4a6a34087f8818
7
- data.tar.gz: 3c44ce391e4d9c73f25833437ed3895815c008a4d43c60a933c6c89390e9783366789431d8bb679ca22ee95f879cd6c1bb74bc0b0c853b49975b42272763703b
6
+ metadata.gz: 0136a9c93cb94dc161367ecac78b3d106404e4450fb1f4c6df8d6e38400da242fdaeebf54a7ed18ae5fc0037bea9e62ae94b5870883a2adb493e5721059a9eb8
7
+ data.tar.gz: c10509dbc8ae25ae0f1c19b35903664863fb07fb81409fd6cc16b962bde35d46f7bb552562994757b74fcc4d32f6ef9970a66f0893d0c36f11da5c27a7f2b4df
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.7.0] - 2024-07-30
4
+
5
+ ### Added
6
+
7
+ - Support `wrap_parameters` by [@alex-rogachev](https://github.com/alex-rogachev) (#89).
8
+ - Unknown environment error handling by [@cuneyter](https://github.com/cuneyter) (#95).
9
+ - Allow `rescue_from` handlers to not accept arguments (#93).
10
+
11
+ ## [1.6.0] - 2024-07-15
12
+
13
+ ### Added
14
+
15
+ - Support legacy route helpers (#90).
16
+ - Correctly handle internal Rails routes in `Rage.multi_application` (#91).
17
+
3
18
  ## [1.5.1] - 2024-05-26
4
19
 
5
20
  ### Fixed
data/Gemfile CHANGED
@@ -8,12 +8,14 @@ gemspec
8
8
  gem "rake", "~> 13.0"
9
9
 
10
10
  gem "rspec", "~> 3.0"
11
- gem "http"
12
11
  gem "yard"
12
+ gem "rubocop", "~> 1.65", require: false
13
13
 
14
- gem "pg"
15
- gem "mysql2"
16
- gem "connection_pool", "~> 2.0"
17
-
18
- gem "rbnacl"
19
- gem "domain_name"
14
+ group :test do
15
+ gem "http"
16
+ gem "pg"
17
+ gem "mysql2"
18
+ gem "connection_pool", "~> 2.0"
19
+ gem "rbnacl"
20
+ gem "domain_name"
21
+ end
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.
data/README.md CHANGED
@@ -15,7 +15,7 @@ Inspired by [Deno](https://deno.com) and built on top of [Iodine](https://github
15
15
 
16
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.
17
17
 
18
- * **Acceptance of modern Ruby** - the framework includes a fiber scheduler, which means your code never blocks while waiting on IO.
18
+ * **Acceptance of modern Ruby** - the framework includes a fiber scheduler, which means your code never blocks while waiting on I/O.
19
19
 
20
20
  ## Installation
21
21
 
@@ -116,34 +116,48 @@ class PagesController < RageController::API
116
116
  end
117
117
  ```
118
118
 
119
- :information_source: **Note**: When using `Fiber.await`, it is important to wrap any instance of IO into a fiber using `Fiber.schedule`.
119
+ :information_source: **Note**: When using `Fiber.await`, it is important to wrap every argument into a fiber using `Fiber.schedule`.
120
120
 
121
121
  ## Benchmarks
122
122
 
123
- #### hello world
123
+ #### Hello World
124
124
 
125
125
  ```ruby
126
- class ArticlesController < ApplicationController
126
+ class BenchmarksController < ApplicationController
127
127
  def index
128
128
  render json: { hello: "world" }
129
129
  end
130
130
  end
131
131
  ```
132
- ![Requests per second](https://github.com/rage-rb/rage/assets/2270393/6c221903-e265-4c94-80e1-041f266c8f47)
133
132
 
134
- #### waiting on IO
133
+ ![Requests per second](https://github.com/user-attachments/assets/a7f864ae-0dfb-4628-a420-265a10d8591d)
134
+
135
+ #### Waiting on I/O
135
136
 
136
137
  ```ruby
137
138
  require "net/http"
138
139
 
139
- class ArticlesController < ApplicationController
140
+ class BenchmarksController < ApplicationController
140
141
  def index
141
142
  Net::HTTP.get(URI("<endpoint-that-responds-in-one-second>"))
142
143
  head :ok
143
144
  end
144
145
  end
145
146
  ```
146
- ![Time to complete 100 requests](https://github.com/rage-rb/rage/assets/2270393/007044e9-efe0-4675-9cab-8a4868154118)
147
+
148
+ ![Time to complete 100 requests](https://github.com/user-attachments/assets/4f4feda3-bd88-43d8-8999-268534c2f9de)
149
+
150
+ #### Using ActiveRecord
151
+
152
+ ```ruby
153
+ class BenchmarksController < ApplicationController
154
+ def show
155
+ render json: World.find(rand(10_000))
156
+ end
157
+ end
158
+ ```
159
+
160
+ ![Requests per second-2](https://github.com/user-attachments/assets/b7ee0bff-e7c8-4fd4-a565-ce0b67a6320e)
147
161
 
148
162
  ## Upcoming releases
149
163
 
data/lib/rage/cli.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "thor"
3
4
  require "rack"
4
5
 
@@ -40,7 +41,7 @@ module Rage
40
41
  ::Iodine.start
41
42
  end
42
43
 
43
- desc 'routes', 'List all routes.'
44
+ desc "routes", "List all routes."
44
45
  option :grep, aliases: "-g", desc: "Filter routes by pattern"
45
46
  option :help, aliases: "-h", desc: "Show this message."
46
47
  def routes
@@ -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
 
@@ -7,6 +7,7 @@ class RageController::API
7
7
  # registering means defining a new method which calls the action, makes additional calls (e.g. before actions) and
8
8
  # sends a correct response down to the server;
9
9
  # returns the name of the newly defined method;
10
+ # rubocop:disable Layout/IndentationWidth, Layout/EndAlignment, Layout/HeredocIndentation
10
11
  def __register_action(action)
11
12
  raise Rage::Errors::RouterError, "The action '#{action}' could not be found for #{self}" unless method_defined?(action)
12
13
 
@@ -65,7 +66,7 @@ class RageController::API
65
66
  lines = @__rescue_handlers.map do |klasses, handler|
66
67
  <<~RUBY
67
68
  rescue #{klasses.join(", ")} => __e
68
- #{handler}(__e)
69
+ #{instance_method(handler).arity == 0 ? handler : "#{handler}(__e)"}
69
70
  [@__status, @__headers, @__body]
70
71
  RUBY
71
72
  end
@@ -77,7 +78,24 @@ class RageController::API
77
78
 
78
79
  activerecord_loaded = defined?(::ActiveRecord)
79
80
 
80
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
81
+ wrap_parameters_chunk = if __wrap_parameters_key
82
+ <<~RUBY
83
+ wrap_key = self.class.__wrap_parameters_key
84
+ if !@__params.key?(wrap_key) && @__env["CONTENT_TYPE"]
85
+ wrap_options = self.class.__wrap_parameters_options
86
+ wrapped_params = if wrap_options[:include].any?
87
+ @__params.slice(*wrap_options[:include])
88
+ else
89
+ params_to_exclude_by_default = %i[action controller]
90
+ @__params.except(*(wrap_options[:exclude] + params_to_exclude_by_default))
91
+ end
92
+
93
+ @__params[wrap_key] = wrapped_params
94
+ end
95
+ RUBY
96
+ end
97
+
98
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
81
99
  def __run_#{action}
82
100
  #{if activerecord_loaded
83
101
  <<~RUBY
@@ -85,6 +103,7 @@ class RageController::API
85
103
  RUBY
86
104
  end}
87
105
 
106
+ #{wrap_parameters_chunk}
88
107
  #{before_actions_chunk}
89
108
  #{action}
90
109
 
@@ -119,9 +138,11 @@ class RageController::API
119
138
  end
120
139
  RUBY
121
140
  end
141
+ # rubocop:enable all
122
142
 
123
143
  # @private
124
144
  attr_writer :__before_actions, :__after_actions, :__rescue_handlers
145
+ attr_accessor :__wrap_parameters_key, :__wrap_parameters_options
125
146
 
126
147
  # @private
127
148
  # pass the variable down to the child; the child will continue to use it until changes need to be made;
@@ -130,6 +151,8 @@ class RageController::API
130
151
  klass.__before_actions = @__before_actions.freeze
131
152
  klass.__after_actions = @__after_actions.freeze
132
153
  klass.__rescue_handlers = @__rescue_handlers.freeze
154
+ klass.__wrap_parameters_key = __wrap_parameters_key
155
+ klass.__wrap_parameters_options = __wrap_parameters_options
133
156
  end
134
157
 
135
158
  # @private
@@ -151,24 +174,23 @@ class RageController::API
151
174
  # Register a global exception handler. Handlers are inherited and matched from bottom to top.
152
175
  #
153
176
  # @param klasses [Class, Array<Class>] exception classes to watch on
154
- # @param with [Symbol] the name of a handler method. The method must take one argument, which is the raised exception. Alternatively, you can pass a block, which must also take one argument.
177
+ # @param with [Symbol] the name of a handler method. Alternatively, you can pass a block.
155
178
  # @example
156
179
  # rescue_from User::NotAuthorized, with: :deny_access
157
180
  #
158
- # def deny_access(exception)
181
+ # def deny_access
159
182
  # head :forbidden
160
183
  # end
161
184
  # @example
162
- # rescue_from User::NotAuthorized do |_|
163
- # head :forbidden
185
+ # rescue_from User::NotAuthorized do |exception|
186
+ # render json: { message: exception.message }, status: :forbidden
164
187
  # end
165
- # @note Unlike in Rails, the handler must always take an argument. Use `_` if you don't care about the actual exception.
166
188
  def rescue_from(*klasses, with: nil, &block)
167
189
  unless with
168
190
  if block_given?
169
191
  with = define_tmp_method(block)
170
192
  else
171
- raise "No handler provided. Pass the `with` keyword argument or provide a block."
193
+ raise ArgumentError, "No handler provided. Pass the `with` keyword argument or provide a block."
172
194
  end
173
195
  end
174
196
 
@@ -183,7 +205,7 @@ class RageController::API
183
205
 
184
206
  # Register a new `before_action` hook. Calls with the same `action_name` will overwrite the previous ones.
185
207
  #
186
- # @param action_name [String, nil] the name of the callback to add
208
+ # @param action_name [Symbol, nil] the name of the callback to add
187
209
  # @param [Hash] opts action options
188
210
  # @option opts [Symbol, Array<Symbol>] :only restrict the callback to run only for specific actions
189
211
  # @option opts [Symbol, Array<Symbol>] :except restrict the callback to run for all actions except specified
@@ -215,7 +237,7 @@ class RageController::API
215
237
 
216
238
  if @__before_actions.nil?
217
239
  @__before_actions = [action]
218
- elsif i = @__before_actions.find_index { |a| a[:name] == action_name }
240
+ elsif (i = @__before_actions.find_index { |a| a[:name] == action_name })
219
241
  @__before_actions[i] = action
220
242
  else
221
243
  @__before_actions << action
@@ -224,7 +246,7 @@ class RageController::API
224
246
 
225
247
  # Register a new `after_action` hook. Calls with the same `action_name` will overwrite the previous ones.
226
248
  #
227
- # @param action_name [String, nil] the name of the callback to add
249
+ # @param action_name [Symbol, nil] the name of the callback to add
228
250
  # @param [Hash] opts action options
229
251
  # @option opts [Symbol, Array<Symbol>] :only restrict the callback to run only for specific actions
230
252
  # @option opts [Symbol, Array<Symbol>] :except restrict the callback to run for all actions except specified
@@ -241,7 +263,7 @@ class RageController::API
241
263
 
242
264
  if @__after_actions.nil?
243
265
  @__after_actions = [action]
244
- elsif i = @__after_actions.find_index { |a| a[:name] == action_name }
266
+ elsif (i = @__after_actions.find_index { |a| a[:name] == action_name })
245
267
  @__after_actions[i] = action
246
268
  else
247
269
  @__after_actions << action
@@ -250,14 +272,14 @@ class RageController::API
250
272
 
251
273
  # Prevent a `before_action` hook from running.
252
274
  #
253
- # @param action_name [String] the name of the callback to skip
275
+ # @param action_name [Symbol] the name of the callback to skip
254
276
  # @param only [Symbol, Array<Symbol>] restrict the callback to be skipped only for specific actions
255
277
  # @param except [Symbol, Array<Symbol>] restrict the callback to be skipped for all actions except specified
256
278
  # @example
257
279
  # skip_before_action :find_photo, only: :create
258
280
  def skip_before_action(action_name, only: nil, except: nil)
259
281
  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
282
+ raise ArgumentError, "The following action was specified to be skipped but couldn't be found: #{self}##{action_name}" unless i
261
283
 
262
284
  @__before_actions = @__before_actions.dup if @__before_actions.frozen?
263
285
 
@@ -277,6 +299,23 @@ class RageController::API
277
299
  @__before_actions[i] = action
278
300
  end
279
301
 
302
+ # Initialize controller params wrapping into a nested hash.
303
+ # If initialized, params wrapping logic will be added to the controller.
304
+ # Params get wrapped only if the CONTENT_TYPE header is present and params hash doesn't contain a param that
305
+ # has the same name as the wrapper key.
306
+ #
307
+ # @param key [Symbol] key that the wrapped params hash will nested under
308
+ # @param include [Array] array of params that should be included to the wrapped params hash
309
+ # @param exclude [Array] array of params that should be excluded from the wrapped params hash
310
+ # @example
311
+ # wrap_parameters :user, include: %i[name age]
312
+ # @example
313
+ # wrap_parameters :user, exclude: %i[address]
314
+ def wrap_parameters(key, include: [], exclude: [])
315
+ @__wrap_parameters_key = key
316
+ @__wrap_parameters_options = { include:, exclude: }
317
+ end
318
+
280
319
  private
281
320
 
282
321
  # used by `before_action` and `after_action`
@@ -284,10 +323,10 @@ class RageController::API
284
323
  if block_given?
285
324
  action_name = define_tmp_method(block)
286
325
  elsif action_name.nil?
287
- raise "No handler provided. Pass the `action_name` parameter or provide a block."
326
+ raise ArgumentError, "No handler provided. Pass the `action_name` parameter or provide a block."
288
327
  end
289
328
 
290
- _only, _except, _if, _unless = opts.values_at(:only, :except, :if, :unless)
329
+ _only, _except, _if, _unless = opts.values_at(:only, :except, :if, :unless)
291
330
 
292
331
  action = {
293
332
  name: action_name,
data/lib/rage/cookies.rb CHANGED
@@ -97,7 +97,7 @@ class Rage::Cookies
97
97
  return
98
98
  end
99
99
 
100
- if domain = value[:domain]
100
+ if (domain = value[:domain])
101
101
  host = @env["HTTP_HOST"]
102
102
 
103
103
  _domain = if domain.is_a?(String)
@@ -141,7 +141,7 @@ class Rage::Cookies
141
141
  return @request_cookies if @parsed
142
142
 
143
143
  @parsed = true
144
- if cookie_header = @env["HTTP_COOKIE"]
144
+ if (cookie_header = @env["HTTP_COOKIE"])
145
145
  cookie_header.split(/; */n).each do |cookie|
146
146
  next if cookie.empty?
147
147
  key, value = cookie.split("=", 2).yield_self { |k, _| [k.to_sym, _] }
@@ -193,7 +193,7 @@ class Rage::Cookies
193
193
  nil
194
194
  rescue RbNaCl::CryptoError
195
195
  i ||= 0
196
- if box = fallback_boxes[i]
196
+ if (box = fallback_boxes[i])
197
197
  i += 1
198
198
  retry
199
199
  end
@@ -230,10 +230,8 @@ class Rage::Cookies
230
230
  end
231
231
 
232
232
  def fallback_boxes
233
- @fallback_boxes ||= begin
234
- Rage.config.fallback_secret_key_base.map do |key|
235
- RbNaCl::SimpleBox.from_secret_key(RbNaCl::Hash.blake2b(key, digest_size: 32, salt: SALT))
236
- end
233
+ @fallback_boxes ||= Rage.config.fallback_secret_key_base.map do |key|
234
+ RbNaCl::SimpleBox.from_secret_key(RbNaCl::Hash.blake2b(key, digest_size: 32, salt: SALT))
237
235
  end
238
236
  end
239
237
  end # class << self
@@ -97,7 +97,7 @@ module Rage::Ext::ActiveRecord::ConnectionPool
97
97
 
98
98
  # Signal that the fiber is finished with the current connection and it can be returned to the pool.
99
99
  def release_connection(owner = Fiber.current)
100
- if conn = @__in_use.delete(owner)
100
+ if (conn = @__in_use.delete(owner))
101
101
  conn.__idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
102
102
  @__connections << conn
103
103
  Iodine.publish("ext:ar-connection-released", "", Iodine::PubSub::PROCESS) if @__blocked.length > 0
data/lib/rage/fiber.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ##
4
4
  # Rage provides a simple and efficient API to wait on several instances of IO at the same time - {Fiber.await}.
5
- #
5
+ #
6
6
  # Let's say we have the following controller:
7
7
  # ```ruby
8
8
  # class UsersController < RageController::API
@@ -34,7 +34,7 @@
34
34
  # end
35
35
  # ```
36
36
  # With this change, if each request takes 1 second to execute, the total execution time will still be 1 second.
37
- #
37
+ #
38
38
  # ## Creating fibers
39
39
  # Many developers see fibers as "lightweight threads" that should be used in conjunction with fiber pools, the same way we use thread pools for threads.<br>
40
40
  # Instead, it makes sense to think of fibers as regular Ruby objects. We don't use a pool of arrays when we need to create an array - we create a new object and let Ruby and the GC do their job.<br>
@@ -68,7 +68,7 @@ class Fiber
68
68
  @__rage_id = object_id.to_s
69
69
  end
70
70
 
71
- # @private
71
+ # @private
72
72
  def __get_id
73
73
  @__rage_id
74
74
  end
@@ -66,7 +66,7 @@ class Rage::FiberScheduler
66
66
  end
67
67
 
68
68
  # TODO: GC works a little strange with this closure;
69
- #
69
+ #
70
70
  # def timeout_after(duration, exception_class = Timeout::Error, *exception_arguments, &block)
71
71
  # fiber, block_status = Fiber.current, :running
72
72
  # ::Iodine.run_after((duration * 1000).to_i) do
@@ -15,7 +15,7 @@ class Rage::JSONFormatter
15
15
  context.each { |k, v| context_msg << "\"#{k}\":#{v.to_json}," }
16
16
  end
17
17
 
18
- if final = logger[:final]
18
+ if (final = logger[:final])
19
19
  params, env = final[:params], final[:env]
20
20
  if params && params[:controller]
21
21
  return "{\"tags\":[\"#{tags[0]}\"],\"timestamp\":\"#{timestamp}\",\"pid\":\"#{@pid}\",\"level\":\"info\",\"method\":\"#{env["REQUEST_METHOD"]}\",\"path\":\"#{env["PATH_INFO"]}\",\"controller\":\"#{Rage::Router::Util.path_to_name(params[:controller])}\",\"action\":\"#{params[:action]}\",#{context_msg}\"status\":#{final[:response][0]},\"duration\":#{final[:duration]}}\n"
@@ -8,7 +8,7 @@ require "logger"
8
8
  # [fecbba0735355738] timestamp=2023-10-19T11:12:56+00:00 pid=1825 level=info message=hello
9
9
  # ```
10
10
  # In the log entry above, `timestamp`, `pid`, `level`, and `message` are keys, while `fecbba0735355738` is a tag.
11
- #
11
+ #
12
12
  # Use {tagged} to add custom tags to an entry:
13
13
  # ```ruby
14
14
  # Rage.logger.tagged("ApiCall") do
@@ -15,7 +15,7 @@ class Rage::TextFormatter
15
15
  context.each { |k, v| context_msg << "#{k}=#{v} " }
16
16
  end
17
17
 
18
- if final = logger[:final]
18
+ if (final = logger[:final])
19
19
  params, env = final[:params], final[:env]
20
20
  if params && params[:controller]
21
21
  return "[#{tags[0]}] timestamp=#{timestamp} pid=#{@pid} level=info method=#{env["REQUEST_METHOD"]} path=#{env["PATH_INFO"]} controller=#{Rage::Router::Util.path_to_name(params[:controller])} action=#{params[:action]} #{context_msg}status=#{final[:response][0]} duration=#{final[:duration]}\n"
@@ -19,7 +19,7 @@ class Rage::Cors
19
19
 
20
20
  response
21
21
  ensure
22
- if !$! && origin = @cors_check.call(env)
22
+ if !$! && (origin = @cors_check.call(env))
23
23
  headers = response[1]
24
24
  headers["Access-Control-Allow-Origin"] = origin
25
25
  if @origins != "*"
@@ -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 = []
@@ -99,7 +99,7 @@ class Rage::Cors
99
99
  def create_headers
100
100
  headers = {
101
101
  "Access-Control-Allow-Origin" => "",
102
- "Access-Control-Allow-Methods" => @methods,
102
+ "Access-Control-Allow-Methods" => @methods
103
103
  }
104
104
 
105
105
  if @allow_headers
@@ -8,7 +8,7 @@ class Rage::Reloader
8
8
  def call(env)
9
9
  Rage.code_loader.reload
10
10
  @app.call(env)
11
- rescue Exception => e
11
+ rescue Exception => e
12
12
  exception_str = "#{e.class} (#{e.message}):\n#{e.backtrace.join("\n")}"
13
13
  puts(exception_str)
14
14
  [500, {}, [exception_str]]
@@ -29,7 +29,7 @@ class Rage::ParamsParser
29
29
  url_params
30
30
  end
31
31
 
32
- rescue => e
32
+ rescue
33
33
  raise Rage::Errors::BadRequest
34
34
  end
35
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"
@@ -51,8 +51,8 @@ class Rage::Router::Backend
51
51
  def on(method, path, handler, constraints: {}, defaults: nil)
52
52
  raise "Path could not be empty" if path&.empty?
53
53
 
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
54
+ if (match_index = (path =~ OPTIONAL_PARAM_REGEXP))
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
@@ -200,12 +200,10 @@ class Rage::Router::Backend
200
200
  end
201
201
 
202
202
  @routes.each do |existing_route|
203
- if (
204
- existing_route[:method] == method &&
205
- existing_route[:pattern] == pattern &&
206
- existing_route[:constraints] == constraints
207
- )
208
- raise "Method '#{method}' already declared for route '#{pattern}' with constraints '#{constraints.inspect}'"
203
+ if existing_route[:method] == method &&
204
+ existing_route[:pattern] == pattern &&
205
+ existing_route[:constraints] == constraints
206
+ raise ArgumentError, "Method '#{method}' already declared for route '#{pattern}' with constraints '#{constraints.inspect}'"
209
207
  end
210
208
  end
211
209
 
@@ -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 '/'.
@@ -198,7 +213,7 @@ class Rage::Router::DSL
198
213
  @path_prefixes << path_prefix
199
214
  @module_prefixes << module_prefix
200
215
 
201
- instance_eval &block
216
+ instance_eval(&block)
202
217
 
203
218
  @path_prefixes.pop
204
219
  @module_prefixes.pop
@@ -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"
@@ -238,7 +253,7 @@ class Rage::Router::DSL
238
253
  @module_prefixes << opts[:module] if opts[:module]
239
254
  @controllers << opts[:controller] if opts[:controller]
240
255
 
241
- instance_eval &block
256
+ instance_eval(&block)
242
257
 
243
258
  @path_prefixes.pop if opts[:path]
244
259
  @module_prefixes.pop if opts[:module]
@@ -254,7 +269,7 @@ class Rage::Router::DSL
254
269
  # end
255
270
  def defaults(defaults, &block)
256
271
  @defaults << defaults
257
- instance_eval &block
272
+ instance_eval(&block)
258
273
  @defaults.pop
259
274
  end
260
275
 
@@ -267,7 +282,7 @@ class Rage::Router::DSL
267
282
  # end
268
283
  def controller(controller, &block)
269
284
  @controllers << controller
270
- instance_eval &block
285
+ instance_eval(&block)
271
286
  @controllers.pop
272
287
  end
273
288
 
@@ -282,7 +297,7 @@ class Rage::Router::DSL
282
297
  def collection(&block)
283
298
  orig_path_prefixes = @path_prefixes
284
299
  @path_prefixes = @path_prefixes[0...-1] if @path_prefixes.last&.start_with?(":")
285
- instance_eval &block
300
+ instance_eval(&block)
286
301
  @path_prefixes = orig_path_prefixes
287
302
  end
288
303
 
@@ -302,13 +317,19 @@ class Rage::Router::DSL
302
317
  @path_prefixes = [*@path_prefixes[0...-1], ":#{member_prefix}"]
303
318
  end
304
319
 
305
- instance_eval &block
320
+ instance_eval(&block)
306
321
 
307
322
  @path_prefixes = orig_path_prefixes
308
323
  end
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
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
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
@@ -64,7 +64,7 @@ class Rage::Router::HandlerStorage
64
64
  end
65
65
  end
66
66
 
67
- eval "->(param_values) { { #{lines.join(',')} } }"
67
+ eval "->(param_values) { { #{lines.join(",")} } }"
68
68
  end
69
69
 
70
70
  def get_handler_matching_constraints(_derived_constraints)
@@ -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/setup.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  Iodine.patch_rack
2
2
 
3
- require_relative "#{Rage.root}/config/environments/#{Rage.env}"
3
+ begin
4
+ require_relative "#{Rage.root}/config/environments/#{Rage.env}"
5
+ rescue LoadError
6
+ raise LoadError, "The <#{Rage.env}> environment could not be found. Please check the environment name."
7
+ end
4
8
 
5
9
  # Run application initializers
6
10
  Dir["#{Rage.root}/config/initializers/**/*.rb"].each { |initializer| load(initializer) }
@@ -13,7 +13,7 @@ class Rage::SidekiqSession
13
13
  SESSION_KEY = "rage.sidekiq.session"
14
14
 
15
15
  def self.with_session(env)
16
- env["rack.session"] = session = self.new(env)
16
+ env["rack.session"] = session = new(env)
17
17
  response = yield
18
18
 
19
19
  if session.changed
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.1"
4
+ VERSION = "1.7.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
data/rage.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
21
  spec.files = Dir.chdir(__dir__) do
22
22
  `git ls-files -z`.split("\x0").reject do |f|
23
- (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor])
23
+ (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor .rubocop])
24
24
  end
25
25
  end
26
26
  spec.bindir = "exe"
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.1
4
+ version: 1.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: 2024-05-26 00:00:00.000000000 Z
11
+ date: 2024-07-30 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