ruby_routes 2.2.0 โ†’ 2.4.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +240 -163
  3. data/lib/ruby_routes/constant.rb +137 -18
  4. data/lib/ruby_routes/lru_strategies/hit_strategy.rb +31 -4
  5. data/lib/ruby_routes/lru_strategies/miss_strategy.rb +21 -0
  6. data/lib/ruby_routes/node.rb +86 -36
  7. data/lib/ruby_routes/radix_tree/finder.rb +213 -0
  8. data/lib/ruby_routes/radix_tree/inserter.rb +96 -0
  9. data/lib/ruby_routes/radix_tree.rb +65 -230
  10. data/lib/ruby_routes/route/check_helpers.rb +115 -0
  11. data/lib/ruby_routes/route/constraint_validator.rb +173 -0
  12. data/lib/ruby_routes/route/param_support.rb +200 -0
  13. data/lib/ruby_routes/route/path_builder.rb +84 -0
  14. data/lib/ruby_routes/route/path_generation.rb +87 -0
  15. data/lib/ruby_routes/route/query_helpers.rb +56 -0
  16. data/lib/ruby_routes/route/segment_compiler.rb +166 -0
  17. data/lib/ruby_routes/route/small_lru.rb +93 -18
  18. data/lib/ruby_routes/route/validation_helpers.rb +174 -0
  19. data/lib/ruby_routes/route/warning_helpers.rb +57 -0
  20. data/lib/ruby_routes/route.rb +127 -501
  21. data/lib/ruby_routes/route_set/cache_helpers.rb +76 -0
  22. data/lib/ruby_routes/route_set/collection_helpers.rb +125 -0
  23. data/lib/ruby_routes/route_set.rb +140 -132
  24. data/lib/ruby_routes/router/build_helpers.rb +99 -0
  25. data/lib/ruby_routes/router/builder.rb +97 -0
  26. data/lib/ruby_routes/router/http_helpers.rb +135 -0
  27. data/lib/ruby_routes/router/resource_helpers.rb +137 -0
  28. data/lib/ruby_routes/router/scope_helpers.rb +127 -0
  29. data/lib/ruby_routes/router.rb +196 -182
  30. data/lib/ruby_routes/segment.rb +28 -8
  31. data/lib/ruby_routes/segments/base_segment.rb +40 -4
  32. data/lib/ruby_routes/segments/dynamic_segment.rb +48 -12
  33. data/lib/ruby_routes/segments/static_segment.rb +43 -7
  34. data/lib/ruby_routes/segments/wildcard_segment.rb +58 -12
  35. data/lib/ruby_routes/string_extensions.rb +52 -15
  36. data/lib/ruby_routes/url_helpers.rb +106 -24
  37. data/lib/ruby_routes/utility/inflector_utility.rb +35 -0
  38. data/lib/ruby_routes/utility/key_builder_utility.rb +171 -77
  39. data/lib/ruby_routes/utility/method_utility.rb +137 -0
  40. data/lib/ruby_routes/utility/path_utility.rb +75 -28
  41. data/lib/ruby_routes/utility/route_utility.rb +30 -2
  42. data/lib/ruby_routes/version.rb +3 -1
  43. data/lib/ruby_routes.rb +68 -11
  44. metadata +27 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66764348265233b0904630e4193e21fc93f79e3257ec4d0e43e5c533faf1f7e1
4
- data.tar.gz: de32cc9f5f42398b12e829c4da34aa82afd071fa63ed869180a56203834beecd
3
+ metadata.gz: 57b9470b49019746492c10fd0e202c6c544c78459f36e0d2c1f8d400103def93
4
+ data.tar.gz: 8e59a14f7854cadb955d381fcf7947b7769d0041de5067f3e3dc5827d13cbb26
5
5
  SHA512:
6
- metadata.gz: 21442f1a73e4045fedbb9bd215c639770c55135f6d55c78c17384996515d1347851d7b3afa952db345793a5aa92d5c14368d28faf0e35d4c985d608d94c8b980
7
- data.tar.gz: 5570f4054ceaf76569bb4f28eca4d94347a559a24febe1936e39dfb9896ccfa281cdd1e2ce24e8e2b157b3d7f3870a67cc9ecdb61b62338bce7e28b5d0c32e4e
6
+ metadata.gz: c746c95407c222fdd209e464c3f1b89971987d8b41a557b7f173e1acb55fa5d6626b030bab26aed81c7ff766bd9da8c4ba4c2895ce167558a61c089923e14f12
7
+ data.tar.gz: 6b512f5e810f19fa4031b33f29d3efa72feabb841e8ac3558af67ce6ec43556cacc85577993015cde7f3f400c10e9a36cbc8e007831808a798fa80204fd57046
data/README.md CHANGED
@@ -1,26 +1,42 @@
1
- # Ruby Routes Gem
1
+ # Ruby Routes
2
2
 
3
- A lightweight, flexible routing system for Ruby that provides a Rails-like DSL for defining and matching HTTP routes.
3
+ A high-performance, lightweight routing system for Ruby applications providing a Rails-like DSL for defining and matching HTTP routes.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Rails-like DSL**: Familiar syntax for defining routes
8
- - **HTTP Method Support**: GET, POST, PUT, PATCH, DELETE, and custom methods
9
- - **RESTful Resources**: Automatic generation of RESTful routes
10
- - **Nested Routes**: Support for nested resources and namespaces
11
- - **Secure Route Constraints**: Powerful constraint system with built-in security ([see CONSTRAINTS.md](CONSTRAINTS.md))
12
- - **Named Routes**: Generate URLs from route names
13
- - **Path Generation**: Build URLs with parameters
14
- - **Scope Support**: Group routes with common options
15
- - **Concerns**: Reusable route groups
16
- - **Lightweight**: Minimal dependencies, fast performance
7
+ - **๐Ÿš€ High Performance**: Fast routing with 99.99% cache hit rate
8
+ - **๐Ÿ”„ Rails-like DSL**: Familiar syntax for defining routes
9
+ - **๐Ÿ›ฃ๏ธ RESTful Resources**: Automatic generation of RESTful routes
10
+ - **๐Ÿ”’ Secure Constraints**: Built-in security with comprehensive constraint system
11
+ - **๐Ÿงฉ Modular Design**: Nested resources, scopes, concerns, and namespaces
12
+ - **๐Ÿ“ Named Routes**: Generate paths from route names with automatic parameter handling
13
+ - **๐Ÿงต Thread Safety**: All caching and shared resources are thread-safe
14
+ - **๐Ÿ” Optimized Caching**: Smart caching strategies for route recognition and path generation
15
+ - **๐Ÿชถ Lightweight**: Minimal dependencies for easy integration
16
+
17
+ ## Table of Contents
18
+
19
+ - [Installation](#installation)
20
+ - [Quick Start](#quick-start)
21
+ - [Basic Usage](#basic-usage)
22
+ - [Route Constraints](#route-constraints)
23
+ - [Route Matching](#route-matching)
24
+ - [Path Generation](#path-generation)
25
+ - [Integration with Rack](#integration-with-rack)
26
+ - [API Reference](#api-reference)
27
+ - [Performance](#performance)
28
+ - [Security](#security)
29
+ - [Documentation](#documentation)
30
+ - [Testing](#testing)
31
+ - [Contributing](#contributing)
32
+ - [License](#license)
17
33
 
18
34
  ## Installation
19
35
 
20
36
  Add this line to your application's Gemfile:
21
37
 
22
38
  ```ruby
23
- gem 'ruby_routes'
39
+ gem 'ruby_routes', '~> 2.3.0'
24
40
  ```
25
41
 
26
42
  And then execute:
@@ -35,13 +51,35 @@ Or install it yourself as:
35
51
  gem install ruby_routes
36
52
  ```
37
53
 
54
+ ## Quick Start
55
+
56
+ ```ruby
57
+ require 'ruby_routes'
58
+
59
+ # Define routes
60
+ router = RubyRoutes.draw do
61
+ root to: 'home#index'
62
+ resources :users
63
+
64
+ namespace :api do
65
+ resources :products
66
+ end
67
+ end
68
+
69
+ # Match a request
70
+ result = router.route_set.match('GET', '/users/123')
71
+ # => {controller: 'users', action: 'show', params: {'id' => '123'}, route: #<RubyRoutes::Route...>}
72
+
73
+ # Generate a path
74
+ path = router.route_set.generate_path(:user, id: 456)
75
+ # => "/users/456"
76
+ ```
77
+
38
78
  ## Basic Usage
39
79
 
40
80
  ### Simple Routes
41
81
 
42
82
  ```ruby
43
- require 'ruby_routes'
44
-
45
83
  router = RubyRoutes.draw do
46
84
  get '/', to: 'home#index'
47
85
  get '/about', to: 'pages#about'
@@ -57,19 +95,19 @@ end
57
95
  router = RubyRoutes.draw do
58
96
  resources :users
59
97
  resources :posts
60
- resources :comments
61
98
  end
62
99
  ```
63
100
 
64
101
  This creates the following routes:
65
- - `GET /users` โ†’ `users#index`
66
- - `GET /users/new` โ†’ `users#new`
67
- - `POST /users` โ†’ `users#create`
68
- - `GET /users/:id` โ†’ `users#show`
69
- - `GET /users/:id/edit` โ†’ `users#edit`
70
- - `PUT /users/:id` โ†’ `users#update`
71
- - `PATCH /users/:id` โ†’ `users#update`
72
- - `DELETE /users/:id` โ†’ `users#destroy`
102
+ | HTTP Method | Path | Controller#Action | Named Route |
103
+ |-------------|--------------------|--------------------|-------------------|
104
+ | GET | /users | users#index | users_path |
105
+ | GET | /users/new | users#new | new_user_path |
106
+ | POST | /users | users#create | users_path |
107
+ | GET | /users/:id | users#show | user_path |
108
+ | GET | /users/:id/edit | users#edit | edit_user_path |
109
+ | PUT/PATCH | /users/:id | users#update | user_path |
110
+ | DELETE | /users/:id | users#destroy | user_path |
73
111
 
74
112
  ### Named Routes
75
113
 
@@ -77,7 +115,6 @@ This creates the following routes:
77
115
  router = RubyRoutes.draw do
78
116
  get '/users', as: :users, to: 'users#index'
79
117
  get '/users/:id', as: :user, to: 'users#show'
80
- post '/users', as: :create_user, to: 'users#create'
81
118
  end
82
119
 
83
120
  # Generate paths
@@ -94,13 +131,12 @@ router = RubyRoutes.draw do
94
131
  resources :posts
95
132
  end
96
133
  end
97
-
98
- # Creates routes like:
99
- # GET /admin/users โ†’ admin/users#index
100
- # GET /admin/users/:id โ†’ admin/users#show
101
- # etc.
102
134
  ```
103
135
 
136
+ Creates routes like:
137
+ - `GET /admin/users` โ†’ `admin/users#index`
138
+ - `GET /admin/users/:id` โ†’ `admin/users#show`
139
+
104
140
  ### Nested Resources
105
141
 
106
142
  ```ruby
@@ -109,18 +145,60 @@ router = RubyRoutes.draw do
109
145
  resources :products
110
146
  end
111
147
  end
148
+ ```
149
+
150
+ Creates routes like:
151
+ - `GET /categories/:category_id/products` โ†’ `products#index`
152
+ - `GET /categories/:category_id/products/:id` โ†’ `products#show`
153
+
154
+ ### Scopes & Concerns
155
+
156
+ ```ruby
157
+ router = RubyRoutes.draw do
158
+ # Scopes
159
+ scope defaults: { format: 'json' } do
160
+ get '/api/users', to: 'api/users#index'
161
+ end
162
+
163
+ # Concerns (reusable route groups)
164
+ concern :commentable do
165
+ resources :comments
166
+ end
167
+
168
+ resources :posts, concerns: :commentable
169
+ resources :articles, concerns: :commentable
170
+ end
171
+ ```
172
+
173
+ ### Method Chaining
112
174
 
113
- # Creates routes like:
114
- # GET /categories/:category_id/products โ†’ products#index
115
- # GET /categories/:category_id/products/:id โ†’ products#show
116
- # etc.
175
+ ```ruby
176
+ router = RubyRoutes.draw do
177
+ get('/users', to: 'users#index')
178
+ .post('/users', to: 'users#create')
179
+ .put('/users/:id', to: 'users#update')
180
+ .delete('/users/:id', to: 'users#destroy')
181
+ end
182
+ ```
183
+
184
+ ### Thread-safe Builder
185
+
186
+ ```ruby
187
+ # Accumulate routes without mutating a live router
188
+ router = RubyRoutes::Router.build do
189
+ resources :users
190
+ namespace :admin do
191
+ resources :posts
192
+ end
193
+ end
194
+ # router is now finalized and thread-safe
117
195
  ```
118
196
 
119
- ### Route Constraints
197
+ ## Route Constraints
120
198
 
121
- Ruby Routes provides a powerful and secure constraint system to validate route parameters. **For security reasons, Proc constraints are deprecated** - use the secure alternatives below.
199
+ Ruby Routes provides a powerful constraint system to validate route parameters before they reach your controllers.
122
200
 
123
- #### Built-in Constraint Types
201
+ ### Built-in Constraint Types
124
202
 
125
203
  ```ruby
126
204
  router = RubyRoutes.draw do
@@ -133,18 +211,12 @@ router = RubyRoutes.draw do
133
211
  # Email validation
134
212
  get '/users/:email', to: 'users#show', constraints: { email: :email }
135
213
 
136
- # URL-friendly slug validation
214
+ # Slug validation
137
215
  get '/posts/:slug', to: 'posts#show', constraints: { slug: :slug }
138
-
139
- # Alphabetic characters only
140
- get '/categories/:name', to: 'categories#show', constraints: { name: :alpha }
141
-
142
- # Alphanumeric characters only
143
- get '/codes/:code', to: 'codes#show', constraints: { code: :alphanumeric }
144
216
  end
145
217
  ```
146
218
 
147
- #### Hash-based Constraints (Recommended)
219
+ ### Hash-based Constraints (Recommended)
148
220
 
149
221
  ```ruby
150
222
  router = RubyRoutes.draw do
@@ -160,19 +232,15 @@ router = RubyRoutes.draw do
160
232
 
161
233
  # Allowed values (whitelist)
162
234
  get '/posts/:status', to: 'posts#show',
163
- constraints: {
164
- status: { in: %w[draft published archived] }
165
- }
235
+ constraints: { status: { in: %w[draft published archived] } }
166
236
 
167
237
  # Numeric ranges
168
238
  get '/products/:price', to: 'products#show',
169
- constraints: {
170
- price: { range: 1..10000 }
171
- }
239
+ constraints: { price: { range: 1..10000 } }
172
240
  end
173
241
  ```
174
242
 
175
- #### Regular Expression Constraints
243
+ ### Regular Expression Constraints
176
244
 
177
245
  ```ruby
178
246
  router = RubyRoutes.draw do
@@ -182,7 +250,7 @@ router = RubyRoutes.draw do
182
250
  end
183
251
  ```
184
252
 
185
- #### โš ๏ธ Security Notice: Proc Constraints Deprecated
253
+ โš ๏ธ **Security Notice**: Proc constraints are deprecated due to security risks:
186
254
 
187
255
  ```ruby
188
256
  # โŒ DEPRECATED - Security risk!
@@ -194,44 +262,8 @@ get '/users/:id', to: 'users#show',
194
262
  constraints: { id: { range: 1..Float::INFINITY } }
195
263
  ```
196
264
 
197
- **๐Ÿ“š For complete constraint documentation, see [CONSTRAINTS.md](CONSTRAINTS.md)**
198
- **๐Ÿ”„ For migration help, see [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md)**
199
-
200
- ### Scopes
201
-
202
- ```ruby
203
- router = RubyRoutes.draw do
204
- scope defaults: { format: 'html' } do
205
- get '/posts', to: 'posts#index'
206
- end
207
- end
208
- ```
209
-
210
- ### Concerns
211
-
212
- ```ruby
213
- router = RubyRoutes.draw do
214
- concern :commentable do
215
- resources :comments
216
- end
217
-
218
- resources :posts do
219
- concerns :commentable
220
- end
221
-
222
- resources :articles do
223
- concerns :commentable
224
- end
225
- end
226
- ```
227
-
228
- ### Root Route
229
-
230
- ```ruby
231
- router = RubyRoutes.draw do
232
- root to: 'home#index'
233
- end
234
- ```
265
+ ๐Ÿ“š For complete constraint documentation, see [CONSTRAINTS.md](CONSTRAINTS.md)
266
+ ๐Ÿ”„ For migration help, see [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md)
235
267
 
236
268
  ## Route Matching
237
269
 
@@ -244,12 +276,10 @@ end
244
276
  # Match a request
245
277
  result = router.route_set.match('GET', '/users/123')
246
278
  if result
247
- puts "Controller: #{result[:controller]}"
248
- puts "Action: #{result[:action]}"
249
- puts "Params: #{result[:params]}"
250
- # => Controller: users
251
- # => Action: show
252
- # => Params: {"id"=>"123"}
279
+ controller = result[:controller] # => "users"
280
+ action = result[:action] # => "show"
281
+ params = result[:params] # => {"id"=>"123"}
282
+ route = result[:route] # => #<RubyRoutes::Route...>
253
283
  end
254
284
  ```
255
285
 
@@ -262,10 +292,10 @@ router = RubyRoutes.draw do
262
292
  end
263
293
 
264
294
  # Generate paths
265
- router.route_set.generate_path(:user, id: '123')
295
+ path1 = router.route_set.generate_path(:user, id: '123')
266
296
  # => "/users/123"
267
297
 
268
- router.route_set.generate_path(:post_comment, id: '456', comment_id: '789')
298
+ path2 = router.route_set.generate_path(:post_comment, id: '456', comment_id: '789')
269
299
  # => "/posts/456/comments/789"
270
300
  ```
271
301
 
@@ -275,33 +305,28 @@ router.route_set.generate_path(:post_comment, id: '456', comment_id: '789')
275
305
  require 'rack'
276
306
  require 'ruby_routes'
277
307
 
278
- # Define routes
279
- router = RubyRoutes.draw do
280
- get '/', to: 'home#index'
281
- get '/users', to: 'users#index'
282
- get '/users/:id', to: 'users#show'
283
- end
284
-
285
- # Create Rack app
286
308
  class RubyRoutesApp
287
- def initialize(router)
288
- @router = router
309
+ def initialize
310
+ @router = RubyRoutes.draw do
311
+ root to: 'home#index'
312
+ resources :users
313
+ get '/about', to: 'pages#about'
314
+ end
289
315
  end
290
316
 
291
317
  def call(env)
292
318
  request_method = env['REQUEST_METHOD']
293
319
  request_path = env['PATH_INFO']
294
320
 
295
- route_info = @router.route_set.match(request_method, request_path)
321
+ result = @router.route_set.match(request_method, request_path)
296
322
 
297
- if route_info
298
- # Handle the request
299
- controller = route_info[:controller]
300
- action = route_info[:action]
301
- params = route_info[:params]
323
+ if result
324
+ controller_name = result[:controller]
325
+ action_name = result[:action]
326
+ params = result[:params]
302
327
 
303
328
  # Your controller logic here
304
- [200, {'Content-Type' => 'text/html'}, ["Hello from #{controller}##{action}"]]
329
+ [200, {'Content-Type' => 'text/html'}, ["#{controller_name}##{action_name} with #{params}"]]
305
330
  else
306
331
  [404, {'Content-Type' => 'text/html'}, ['Not Found']]
307
332
  end
@@ -309,89 +334,103 @@ class RubyRoutesApp
309
334
  end
310
335
 
311
336
  # Run the app
312
- app = RubyRoutesApp.new(router)
313
- Rack::Handler::WEBrick.run app, Port: 9292
337
+ Rack::Handler::WEBrick.run RubyRoutesApp.new, Port: 9292
314
338
  ```
315
339
 
316
340
  ## API Reference
317
341
 
318
- ### RubyRoutes.draw(&block)
319
-
320
- Creates a new router instance and yields to the block for route definition.
321
-
322
- ### HTTP Methods
323
-
324
- - `get(path, options = {})`
325
- - `post(path, options = {})`
326
- - `put(path, options = {})`
327
- - `patch(path, options = {})`
328
- - `delete(path, options = {})`
329
- - `match(path, options = {})`
330
-
331
- ### Resource Methods
342
+ ### RubyRoutes
332
343
 
333
- - `resources(name, options = {})` - Creates RESTful routes for a collection
334
- - `resource(name, options = {})` - Creates RESTful routes for a singular resource
344
+ - `RubyRoutes.draw(&block)` - Creates a new router and yields the block for route definition
335
345
 
336
- ### Options
346
+ ### Router Methods
337
347
 
338
- - `to: 'controller#action'` - Specifies controller and action
339
- - `controller: 'name'` - Specifies controller name
340
- - `action: 'name'` - Specifies action name
341
- - `as: :name` - Names the route for path generation
342
- - `via: :method` - Specifies HTTP method(s)
343
- - `constraints: {}` - Adds route constraints
344
- - `defaults: {}` - Sets default parameters
348
+ - `get(path, options = {})` - Define a GET route
349
+ - `post(path, options = {})` - Define a POST route
350
+ - `put(path, options = {})` - Define a PUT route
351
+ - `patch(path, options = {})` - Define a PATCH route
352
+ - `delete(path, options = {})` - Define a DELETE route
353
+ - `match(path, options = {})` - Define a route for multiple HTTP methods
354
+ - `root(options = {})` - Define a root route (/)
355
+ - `resources(name, options = {})` - Define RESTful resource routes
356
+ - `resource(name, options = {})` - Define singular RESTful resource routes
357
+ - `namespace(name, options = {})` - Group routes with a namespace
358
+ - `scope(options = {})` - Group routes with shared options
359
+ - `concern(name, &block)` - Define a reusable route concern
360
+ - `concerns(names)` - Use defined concerns in the current context
361
+ - `build(&block)` - Create a thread-safe, finalized router by accumulating routes in a builder
345
362
 
346
363
  ### RouteSet Methods
347
364
 
348
- - `match(method, path)` - Matches a request to a route
349
- - `generate_path(name, params = {})` - Generates path from named route
350
- - `find_route(method, path)` - Finds a specific route
351
- - `find_named_route(name)` - Finds a named route
365
+ - `match(method, path)` - Match a request to a route
366
+ - `generate_path(name, params = {})` - Generate a path from a named route
367
+ - `find_route(method, path)` - Find a specific route
368
+ - `find_named_route(name)` - Find a named route by name
352
369
 
353
- ## Documentation
370
+ ## Performance
354
371
 
355
- ### Core Documentation
356
- - **[CONSTRAINTS.md](CONSTRAINTS.md)** - Complete guide to route constraints and security best practices
357
- - **[MIGRATION_GUIDE.md](MIGRATION_GUIDE.md)** - Step-by-step guide for migrating from deprecated Proc constraints
372
+ Ruby Routes is optimized for high-performance applications:
358
373
 
359
- ### Examples
374
+ - **Fast** routing
375
+ - **99.99% cache hit rate** for common access patterns
376
+ - **Low memory footprint** with bounded caches and object reuse
377
+ - **Zero memory leaks** in long-running applications
360
378
 
361
- See the `examples/` directory for more detailed examples:
379
+ Performance metrics (from `benchmark/` directory):
362
380
 
363
- - `examples/basic_usage.rb` - Basic routing examples
364
- - `examples/rack_integration.rb` - Full Rack application example
381
+ | Operation | Operations/sec | Memory Usage |
382
+ |-----------|----------------|-------------|
383
+ | Route Matching | ~250,000/sec | Low |
384
+ | Path Generation | ~400,000/sec | Low |
385
+ | Static Routes | ~500,000/sec | Minimal |
365
386
 
366
387
  ## Security
367
388
 
368
- Ruby Routes prioritizes security and has implemented several protections:
389
+ Ruby Routes prioritizes security with these protections:
369
390
 
370
391
  ### ๐Ÿ”’ Security Features
371
- - **XSS Protection**: All HTML output is properly escaped
392
+
372
393
  - **ReDoS Protection**: Regular expression constraints have timeout protection
373
- - **Secure Constraints**: Deprecated dangerous Proc constraints in favor of secure alternatives
374
- - **Thread Safety**: All caching and shared resources are thread-safe
375
- - **Input Validation**: Comprehensive parameter validation before reaching application code
394
+ - **Secure Constraints**: Type-safe constraint system without code execution
395
+ - **Thread Safety**: All shared resources are thread-safe
396
+ - **Input Validation**: Comprehensive parameter validation
397
+
398
+ ### โš ๏ธ Security Notice
376
399
 
377
- ### โš ๏ธ Important Security Notice
378
400
  **Proc constraints are deprecated due to security risks** and will be removed in a future version. They allow arbitrary code execution which can be exploited for:
401
+
379
402
  - Code injection attacks
380
403
  - Denial of service attacks
381
404
  - System compromise
382
405
 
383
406
  **Migration Required**: If you're using Proc constraints, please migrate to secure alternatives using our [Migration Guide](MIGRATION_GUIDE.md).
384
407
 
408
+ **Note**: RubyRoutes is a routing library and does not provide application-level security features such as XSS protection, CSRF protection, or authentication. These should be handled by your web framework or additional security middleware.
409
+
410
+ ## Documentation
411
+
412
+ ### Core Documentation
413
+
414
+ - **[CONSTRAINTS.md](CONSTRAINTS.md)** - Complete guide to route constraints and security
415
+ - **[MIGRATION_GUIDE.md](MIGRATION_GUIDE.md)** - Guide for migrating from deprecated Proc constraints
416
+ - **[USAGE.md](USAGE.md)** - Extended usage scenarios
417
+
418
+ ### Examples
419
+
420
+ See the `examples/` directory for more detailed examples:
421
+
422
+ - `examples/basic_usage.rb` - Basic routing examples
423
+ - `examples/rack_integration.rb` - Full Rack application example
424
+ - `examples/constraints.rb` - Route constraint examples
425
+
385
426
  ## Testing
386
427
 
387
- Run the test suite:
428
+ Ruby Routes has comprehensive test coverage:
388
429
 
389
430
  ```bash
390
431
  bundle exec rspec
391
432
  ```
392
433
 
393
- The test suite includes comprehensive security tests to ensure all protections are working correctly.
394
-
395
434
  ## Contributing
396
435
 
397
436
  1. Fork the repository
@@ -407,3 +446,41 @@ This gem is available as open source under the terms of the [MIT License](LICENS
407
446
  ## Acknowledgments
408
447
 
409
448
  This gem was inspired by Rails routing and aims to provide a lightweight alternative for Ruby applications that need flexible routing without the full Rails framework.
449
+
450
+ ## Thread-safe Build (Isolated Builder)
451
+
452
+ Use the builder to accumulate routes without mutating a live router:
453
+
454
+ ```ruby
455
+ router = RubyRoutes::Router.build do
456
+ resources :users
457
+ namespace :admin do
458
+ resources :posts
459
+ end
460
+ end
461
+ # router is now finalized (immutable)
462
+ ```
463
+
464
+ If you need manual steps:
465
+
466
+ ```ruby
467
+ builder = RubyRoutes::Router::Builder.new do
468
+ get '/health', to: 'system#health'
469
+ end
470
+ router = builder.build # finalized
471
+ ```
472
+
473
+ ## Fluent Method Chaining
474
+
475
+ For a more concise style, the routing DSL supports method chaining:
476
+
477
+ ```ruby
478
+ router = RubyRoutes.draw do
479
+ get('/users', to: 'users#index')
480
+ .post('/users', to: 'users#create')
481
+ .put('/users/:id', to: 'users#update')
482
+ .delete('/users/:id', to: 'users#destroy')
483
+ .resources(:posts)
484
+ end
485
+ ```
486
+