otto 1.6.0 → 2.0.0.pre1

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 (136) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +1 -1
  3. data/.github/workflows/claude-code-review.yml +53 -0
  4. data/.github/workflows/claude.yml +49 -0
  5. data/.gitignore +3 -0
  6. data/.rubocop.yml +24 -345
  7. data/CHANGELOG.rst +83 -0
  8. data/CLAUDE.md +56 -0
  9. data/Gemfile +10 -3
  10. data/Gemfile.lock +23 -28
  11. data/README.md +2 -0
  12. data/bin/rspec +4 -4
  13. data/changelog.d/20250911_235619_delano_next.rst +28 -0
  14. data/changelog.d/20250912_123055_delano_remove_ostruct.rst +21 -0
  15. data/changelog.d/20250912_175625_claude_delano_remove_ostruct.rst +21 -0
  16. data/changelog.d/README.md +120 -0
  17. data/changelog.d/scriv.ini +5 -0
  18. data/docs/.gitignore +1 -0
  19. data/docs/migrating/v2.0.0-pre1.md +276 -0
  20. data/examples/.gitignore +1 -0
  21. data/examples/advanced_routes/README.md +33 -0
  22. data/examples/advanced_routes/app/controllers/handlers/async.rb +9 -0
  23. data/examples/advanced_routes/app/controllers/handlers/dynamic.rb +9 -0
  24. data/examples/advanced_routes/app/controllers/handlers/static.rb +9 -0
  25. data/examples/advanced_routes/app/controllers/modules/auth.rb +9 -0
  26. data/examples/advanced_routes/app/controllers/modules/transformer.rb +9 -0
  27. data/examples/advanced_routes/app/controllers/modules/validator.rb +9 -0
  28. data/examples/advanced_routes/app/controllers/routes_app.rb +232 -0
  29. data/examples/advanced_routes/app/controllers/v2/admin.rb +9 -0
  30. data/examples/advanced_routes/app/controllers/v2/config.rb +9 -0
  31. data/examples/advanced_routes/app/controllers/v2/settings.rb +9 -0
  32. data/examples/advanced_routes/app/logic/admin/logic/manager.rb +27 -0
  33. data/examples/advanced_routes/app/logic/admin/panel.rb +27 -0
  34. data/examples/advanced_routes/app/logic/analytics_processor.rb +25 -0
  35. data/examples/advanced_routes/app/logic/complex/business/handler.rb +27 -0
  36. data/examples/advanced_routes/app/logic/data_logic.rb +23 -0
  37. data/examples/advanced_routes/app/logic/data_processor.rb +25 -0
  38. data/examples/advanced_routes/app/logic/input_validator.rb +24 -0
  39. data/examples/advanced_routes/app/logic/nested/feature/logic.rb +27 -0
  40. data/examples/advanced_routes/app/logic/reports_generator.rb +27 -0
  41. data/examples/advanced_routes/app/logic/simple_logic.rb +25 -0
  42. data/examples/advanced_routes/app/logic/system/config/manager.rb +27 -0
  43. data/examples/advanced_routes/app/logic/test_logic.rb +23 -0
  44. data/examples/advanced_routes/app/logic/transform_logic.rb +23 -0
  45. data/examples/advanced_routes/app/logic/upload_logic.rb +23 -0
  46. data/examples/advanced_routes/app/logic/v2/logic/dashboard.rb +27 -0
  47. data/examples/advanced_routes/app/logic/v2/logic/processor.rb +27 -0
  48. data/examples/advanced_routes/app.rb +33 -0
  49. data/examples/advanced_routes/config.rb +23 -0
  50. data/examples/advanced_routes/config.ru +7 -0
  51. data/examples/advanced_routes/puma.rb +20 -0
  52. data/examples/advanced_routes/routes +167 -0
  53. data/examples/advanced_routes/run.rb +39 -0
  54. data/examples/advanced_routes/test.rb +58 -0
  55. data/examples/authentication_strategies/README.md +32 -0
  56. data/examples/authentication_strategies/app/auth.rb +68 -0
  57. data/examples/authentication_strategies/app/controllers/auth_controller.rb +29 -0
  58. data/examples/authentication_strategies/app/controllers/main_controller.rb +28 -0
  59. data/examples/authentication_strategies/config.ru +24 -0
  60. data/examples/authentication_strategies/routes +37 -0
  61. data/examples/basic/README.md +29 -0
  62. data/examples/basic/app.rb +7 -35
  63. data/examples/basic/routes +0 -9
  64. data/examples/mcp_demo/README.md +87 -0
  65. data/examples/mcp_demo/app.rb +29 -34
  66. data/examples/mcp_demo/config.ru +9 -60
  67. data/examples/security_features/README.md +46 -0
  68. data/examples/security_features/app.rb +23 -24
  69. data/examples/security_features/config.ru +8 -10
  70. data/lib/otto/core/configuration.rb +167 -0
  71. data/lib/otto/core/error_handler.rb +86 -0
  72. data/lib/otto/core/file_safety.rb +61 -0
  73. data/lib/otto/core/middleware_stack.rb +157 -0
  74. data/lib/otto/core/router.rb +183 -0
  75. data/lib/otto/core/uri_generator.rb +44 -0
  76. data/lib/otto/design_system.rb +7 -5
  77. data/lib/otto/helpers/base.rb +3 -0
  78. data/lib/otto/helpers/request.rb +10 -8
  79. data/lib/otto/helpers/response.rb +5 -4
  80. data/lib/otto/helpers/validation.rb +9 -7
  81. data/lib/otto/mcp/auth/token.rb +10 -9
  82. data/lib/otto/mcp/protocol.rb +24 -27
  83. data/lib/otto/mcp/rate_limiting.rb +8 -3
  84. data/lib/otto/mcp/registry.rb +7 -2
  85. data/lib/otto/mcp/route_parser.rb +10 -15
  86. data/lib/otto/mcp/server.rb +21 -11
  87. data/lib/otto/mcp/validation.rb +14 -10
  88. data/lib/otto/response_handlers/auto.rb +39 -0
  89. data/lib/otto/response_handlers/base.rb +16 -0
  90. data/lib/otto/response_handlers/default.rb +16 -0
  91. data/lib/otto/response_handlers/factory.rb +39 -0
  92. data/lib/otto/response_handlers/json.rb +28 -0
  93. data/lib/otto/response_handlers/redirect.rb +25 -0
  94. data/lib/otto/response_handlers/view.rb +24 -0
  95. data/lib/otto/response_handlers.rb +9 -135
  96. data/lib/otto/route.rb +9 -9
  97. data/lib/otto/route_definition.rb +15 -18
  98. data/lib/otto/route_handlers/base.rb +121 -0
  99. data/lib/otto/route_handlers/class_method.rb +89 -0
  100. data/lib/otto/route_handlers/factory.rb +29 -0
  101. data/lib/otto/route_handlers/instance_method.rb +69 -0
  102. data/lib/otto/route_handlers/lambda.rb +59 -0
  103. data/lib/otto/route_handlers/logic_class.rb +93 -0
  104. data/lib/otto/route_handlers.rb +10 -405
  105. data/lib/otto/security/authentication/auth_strategy.rb +44 -0
  106. data/lib/otto/security/authentication/authentication_middleware.rb +123 -0
  107. data/lib/otto/security/authentication/failure_result.rb +36 -0
  108. data/lib/otto/security/authentication/strategies/api_key_strategy.rb +40 -0
  109. data/lib/otto/security/authentication/strategies/permission_strategy.rb +47 -0
  110. data/lib/otto/security/authentication/strategies/public_strategy.rb +19 -0
  111. data/lib/otto/security/authentication/strategies/role_strategy.rb +57 -0
  112. data/lib/otto/security/authentication/strategies/session_strategy.rb +41 -0
  113. data/lib/otto/security/authentication/strategy_result.rb +223 -0
  114. data/lib/otto/security/authentication.rb +28 -282
  115. data/lib/otto/security/config.rb +14 -12
  116. data/lib/otto/security/configurator.rb +219 -0
  117. data/lib/otto/security/csrf.rb +8 -143
  118. data/lib/otto/security/middleware/csrf_middleware.rb +151 -0
  119. data/lib/otto/security/middleware/rate_limit_middleware.rb +38 -0
  120. data/lib/otto/security/middleware/validation_middleware.rb +252 -0
  121. data/lib/otto/security/rate_limiter.rb +86 -0
  122. data/lib/otto/security/rate_limiting.rb +10 -105
  123. data/lib/otto/security/validator.rb +8 -253
  124. data/lib/otto/static.rb +3 -0
  125. data/lib/otto/utils.rb +14 -0
  126. data/lib/otto/version.rb +3 -1
  127. data/lib/otto.rb +142 -498
  128. data/otto.gemspec +2 -2
  129. metadata +89 -28
  130. data/examples/dynamic_pages/app.rb +0 -115
  131. data/examples/dynamic_pages/config.ru +0 -30
  132. data/examples/dynamic_pages/routes +0 -21
  133. data/examples/helpers_demo/app.rb +0 -244
  134. data/examples/helpers_demo/config.ru +0 -26
  135. data/examples/helpers_demo/routes +0 -7
  136. data/lib/concurrent_cache_store.rb +0 -68
@@ -0,0 +1,276 @@
1
+ # Migrating to Otto v2.0.0-pre1
2
+
3
+ ## What's New in v2.0.0-pre1
4
+
5
+ This pre-release includes extensive test coverage improvements (76 new test cases), core module refactoring, middleware stack unification, and a major update to Logic class authentication patterns. See the [full changelog](../../CHANGELOG.rst#changelog-2.0.0-pre1) for complete details.
6
+
7
+ The main breaking changes affect:
8
+ 1. Applications that directly manipulate the middleware stack
9
+ 2. Logic classes using the old authentication signature
10
+
11
+ ## Middleware Stack Unified API
12
+
13
+ Otto v2.0.0-pre1 introduces a significant refactoring of the middleware stack management, providing a more consistent and efficient approach to middleware configuration.
14
+
15
+ ### Key Changes
16
+
17
+ #### Unified Middleware Registration
18
+
19
+ Previous versions had separate legacy and new middleware stacks. In v2.0.0-pre1, we've consolidated these into a single, more powerful middleware stack.
20
+
21
+ **Before:**
22
+ ```ruby
23
+ # Old approach with separate stacks
24
+ otto.middleware_stack << SomeMiddleware
25
+ otto.middleware.add(AnotherMiddleware)
26
+ ```
27
+
28
+ **After:**
29
+ ```ruby
30
+ # Unified middleware registration
31
+ otto.use(SomeMiddleware)
32
+ otto.use(AnotherMiddleware)
33
+ ```
34
+
35
+ #### Performance Improvements
36
+
37
+ - Middleware lookup is now O(1) using a Set
38
+ - Memoized middleware list reduces repeated array creation
39
+ - Prevent duplicate middleware registrations with identical configurations
40
+
41
+ ### Migration Steps
42
+
43
+ 1. Replace all `otto.middleware_stack <<` calls with `otto.use()`
44
+ 2. Remove any direct references to `otto.middleware_stack`
45
+ 3. Use `otto.middleware.includes?()` instead of manual stack checks
46
+
47
+ ### Authentication and Security Methods
48
+
49
+ Authentication and security methods now consistently use the new unified middleware stack:
50
+
51
+ ```ruby
52
+ # Before
53
+ otto.middleware_stack << Otto::Security::CSRFMiddleware
54
+
55
+ # After (no change needed)
56
+ otto.enable_csrf_protection!
57
+ ```
58
+
59
+ ### Performance Considerations
60
+
61
+ The new implementation is more memory-efficient and provides faster middleware lookups, especially for applications with many middleware components.
62
+
63
+ ### Potential Breaking Changes
64
+
65
+ - Code relying on direct manipulation of `middleware_stack` will need updates
66
+ - Method signatures for middleware configuration remain the same
67
+
68
+ ### Example Migration
69
+
70
+ ```ruby
71
+ # Old code
72
+ class MyApp
73
+ def initialize
74
+ @otto = Otto.new
75
+ @otto.middleware_stack << CustomMiddleware
76
+ @otto.middleware.add(AnotherMiddleware)
77
+ end
78
+ end
79
+
80
+ # New code
81
+ class MyApp
82
+ def initialize
83
+ @otto = Otto.new
84
+ @otto.use(CustomMiddleware)
85
+ @otto.use(AnotherMiddleware)
86
+ end
87
+ end
88
+ ```
89
+
90
+ ### Troubleshooting
91
+
92
+ If you encounter any issues with middleware registration or configuration, please file an issue at [Otto GitHub Repository](https://github.com/delano/otto/issues).
93
+
94
+ ## Logic Class RequestContext Pattern
95
+
96
+ Otto v2.0.0-pre1 introduces a major improvement to Logic class authentication with the new RequestContext pattern.
97
+
98
+ ### Key Changes
99
+
100
+ #### New Constructor Signature
101
+
102
+ Logic classes now use a cleaner, more powerful constructor signature that provides immutable context.
103
+
104
+ **Before:**
105
+ ```ruby
106
+ class MyLogic
107
+ attr_reader :session, :user, :params, :locale
108
+
109
+ def initialize(session, user, params, locale)
110
+ @session = session
111
+ @user = user
112
+ @params = params
113
+ @locale = locale
114
+ end
115
+
116
+ def process
117
+ return { error: 'not authenticated' } unless @user
118
+ { result: 'success', user_name: @user['name'] }
119
+ end
120
+ end
121
+ ```
122
+
123
+ **After:**
124
+ ```ruby
125
+ class MyLogic
126
+ attr_reader :context, :params, :locale
127
+
128
+ def initialize(context, params, locale)
129
+ @context = context
130
+ @params = params
131
+ @locale = locale
132
+ end
133
+
134
+ def process
135
+ return { error: 'not authenticated' } unless @context.authenticated?
136
+ {
137
+ result: 'success',
138
+ user_name: @context.user_name,
139
+ roles: @context.roles,
140
+ permissions: @context.permissions
141
+ }
142
+ end
143
+ end
144
+ ```
145
+
146
+ #### RequestContext Benefits
147
+
148
+ 1. **Immutable Structure** - RequestContext is a Ruby Data class that can't be accidentally modified
149
+ 2. **Helper Methods** - Built-in methods like `authenticated?`, `has_role?`, `has_permission?`
150
+ 3. **Cleaner Interface** - Single context parameter instead of separate session/user parameters
151
+ 4. **Type Safety** - Better IDE support and documentation
152
+ 5. **Future-proof** - New authentication data automatically available
153
+
154
+ #### RequestContext API
155
+
156
+ ```ruby
157
+ # Authentication status
158
+ context.authenticated? # Boolean: has non-empty user data
159
+ context.anonymous? # Boolean: not authenticated
160
+
161
+ # User information
162
+ context.user_id # User ID from various possible locations
163
+ context.user_name # User name/username
164
+ context.session_id # Session identifier
165
+
166
+ # Role and permission checks
167
+ context.has_role?('admin') # Single role check
168
+ context.has_permission?('write') # Single permission check
169
+ context.has_any_role?('admin', 'mod') # Multiple role check
170
+ context.roles # Array of all user roles
171
+ context.permissions # Array of all user permissions
172
+
173
+ # Raw data access
174
+ context.session # Session hash
175
+ context.user # User hash
176
+ context.auth_method # Authentication method used
177
+ context.metadata # Additional context data
178
+ ```
179
+
180
+ ### Migration Steps
181
+
182
+ 1. **Update Logic class constructor signatures** from 4 parameters to 3:
183
+ ```ruby
184
+ # Change this:
185
+ def initialize(session, user, params, locale)
186
+
187
+ # To this:
188
+ def initialize(context, params, locale)
189
+ ```
190
+
191
+ 2. **Update instance variables**:
192
+ ```ruby
193
+ # Change this:
194
+ @session = session
195
+ @user = user
196
+
197
+ # To this:
198
+ @context = context
199
+ ```
200
+
201
+ 3. **Update authentication checks**:
202
+ ```ruby
203
+ # Change this:
204
+ return error unless @user
205
+
206
+ # To this:
207
+ return error unless @context.authenticated?
208
+ ```
209
+
210
+ 4. **Update data access**:
211
+ ```ruby
212
+ # Change this:
213
+ user_name = @user&.dig('name')
214
+ user_role = @user&.dig('role')
215
+
216
+ # To this:
217
+ user_name = @context.user_name
218
+ user_role = @context.roles.first
219
+ ```
220
+
221
+ ### Example Migration
222
+
223
+ **Before (v1.x):**
224
+ ```ruby
225
+ class AdminPanel
226
+ attr_reader :session, :user, :params, :locale
227
+
228
+ def initialize(session, user, params, locale)
229
+ @session = session
230
+ @user = user
231
+ @params = params
232
+ @locale = locale
233
+ end
234
+
235
+ def raise_concerns
236
+ raise 'Access denied' unless @user&.dig('role') == 'admin'
237
+ end
238
+
239
+ def process
240
+ {
241
+ panel: 'admin',
242
+ user: @user&.dig('name') || 'unknown',
243
+ session_id: @session&.dig('id')
244
+ }
245
+ end
246
+ end
247
+ ```
248
+
249
+ **After (v2.0):**
250
+ ```ruby
251
+ class AdminPanel
252
+ attr_reader :context, :params, :locale
253
+
254
+ def initialize(context, params, locale)
255
+ @context = context
256
+ @params = params
257
+ @locale = locale
258
+ end
259
+
260
+ def raise_concerns
261
+ raise 'Access denied' unless @context.has_role?('admin')
262
+ end
263
+
264
+ def process
265
+ {
266
+ panel: 'admin',
267
+ user: @context.user_name || 'unknown',
268
+ session_id: @context.session_id,
269
+ authenticated: @context.authenticated?,
270
+ permissions: @context.permissions
271
+ }
272
+ end
273
+ end
274
+ ```
275
+
276
+ This provides a cleaner, more maintainable interface while giving Logic classes access to rich authentication context.
@@ -0,0 +1 @@
1
+ !**/README.md
@@ -0,0 +1,33 @@
1
+ # Otto - Advanced Routes Example
2
+
3
+ This example demonstrates the advanced routing syntax features available in Otto, such as response type negotiation, CSRF exemptions, and routing to logic classes.
4
+
5
+ ## Project Structure
6
+
7
+ The example is structured to separate concerns, making it easier to navigate:
8
+
9
+ - `config.ru`: The main Rackup file that loads and runs the Otto application.
10
+ - `routes`: A comprehensive file demonstrating various advanced routing syntaxes. This file serves as a good reference.
11
+ - `app.rb`: A simple loader that requires all controller and logic files.
12
+ - `app/controllers/`: Contains the `RoutesApp` class and other namespaced controller modules that handle incoming requests.
13
+ - `app/logic/`: Contains various "Logic Classes". These are special classes that can be routed to directly, encapsulating business logic for a specific route. They are organized into namespaces to show how Otto handles complex class names.
14
+ - `run.rb`, `puma.rb`, `test.rb`: Alternative ways to run or test the application.
15
+
16
+ ## Key Features Demonstrated
17
+
18
+ - **Response Types:** Defining `response=json`, `response=view`, etc., directly in the `routes` file.
19
+ - **CSRF Exemption:** Using `csrf=exempt` for APIs or webhooks.
20
+ - **Logic Classes:** Routing directly to a class (e.g., `GET /logic/simple SimpleLogic`). Otto automatically instantiates it and calls its `process` method.
21
+ - **Namespaced Targets:** Routing to deeply namespaced classes and modules (e.g., `GET /logic/v2/dashboard V2::Logic::Dashboard`).
22
+ - **Custom Parameters:** Adding arbitrary key-value parameters to a route for custom logic.
23
+
24
+ ## Running the Example
25
+
26
+ 1. Make sure you have the necessary gems installed (`bundle install`).
27
+ 2. Run the application from the root of the `otto` project:
28
+
29
+ ```sh
30
+ rackup examples/advanced_routes/config.ru
31
+ ```
32
+
33
+ 3. The application will be running at `http://localhost:9292`. You can use `curl` or your browser to test the various routes defined in the `routes` file.
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Handlers
4
+ class Async
5
+ def execute
6
+ [200, { 'content-type' => 'application/json' }, ['{"execution": "async", "csrf": "exempt"}']]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Handlers
4
+ class Dynamic
5
+ def process
6
+ [200, { 'content-type' => 'application/json' }, ['{"handler": "dynamic", "processed": true}']]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Handlers
4
+ class Static
5
+ def self.serve
6
+ [200, { 'content-type' => 'text/html' }, ['<h1>Static Handler</h1><p>Static content served</p>']]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Modules
4
+ class Auth
5
+ def process
6
+ [200, { 'content-type' => 'text/html' }, ['<h1>Auth Module</h1><p>Instance method implementation</p>']]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Modules
4
+ class Transformer
5
+ def transform
6
+ [200, { 'content-type' => 'application/json' }, ['{"transformation": "complete", "csrf": "exempt"}']]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Modules
4
+ class Validator
5
+ def validate
6
+ [200, { 'content-type' => 'application/json' }, ['{"validation": "passed", "module": "Validator"}']]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,232 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'time'
5
+
6
+ # Main application class demonstrating advanced routes syntax
7
+ class RoutesApp
8
+ # ========================================
9
+ # BASIC ROUTES
10
+ # ========================================
11
+
12
+ def self.index
13
+ [200, { 'content-type' => 'text/html' }, ['<h1>Advanced Routes Syntax Example</h1><p>Otto v1.5.0+ Features</p>']]
14
+ end
15
+
16
+ def self.receive_feedback
17
+ [200, { 'content-type' => 'text/plain' }, ['Feedback received']]
18
+ end
19
+
20
+ # ========================================
21
+ # RESPONSE TYPE ROUTES
22
+ # ========================================
23
+
24
+ def self.list_users
25
+ users = [
26
+ { id: 1, name: 'Alice', role: 'admin' },
27
+ { id: 2, name: 'Bob', role: 'user' },
28
+ ]
29
+ [200, { 'content-type' => 'application/json' }, [users.to_json]]
30
+ end
31
+
32
+ def self.create_user
33
+ [201, { 'content-type' => 'application/json' }, ['{"message": "User created", "id": 3}']]
34
+ end
35
+
36
+ def self.health_check
37
+ [200, { 'content-type' => 'application/json' }, ['{"status": "healthy", "timestamp": "' + Time.now.iso8601 + '"}']]
38
+ end
39
+
40
+ def self.update_user
41
+ [200, { 'content-type' => 'application/json' }, ['{"message": "User updated"}']]
42
+ end
43
+
44
+ def self.delete_user
45
+ [204, {}, ['']]
46
+ end
47
+
48
+ def self.dashboard
49
+ [200, { 'content-type' => 'text/html' }, ['<h1>Dashboard</h1><p>HTML view response</p>']]
50
+ end
51
+
52
+ def self.reports
53
+ [200, { 'content-type' => 'text/html' }, ['<h1>Reports</h1><p>View response type demonstration</p>']]
54
+ end
55
+
56
+ def self.admin_panel
57
+ [200, { 'content-type' => 'text/html' }, ['<h1>Admin Panel</h1><p>Administrative interface</p>']]
58
+ end
59
+
60
+ def self.login_redirect
61
+ [302, { 'location' => '/dashboard' }, ['']]
62
+ end
63
+
64
+ def self.logout_redirect
65
+ [302, { 'location' => '/' }, ['']]
66
+ end
67
+
68
+ def self.home_redirect
69
+ [302, { 'location' => '/dashboard' }, ['']]
70
+ end
71
+
72
+ def self.flexible_data
73
+ data = { message: 'This is flexible data', timestamp: Time.now.iso8601 }
74
+ [200, { 'content-type' => 'application/json' }, [data.to_json]]
75
+ end
76
+
77
+ def self.flexible_content
78
+ [200, { 'content-type' => 'application/json' }, ['{"content": "Auto response type", "format": "negotiated"}']]
79
+ end
80
+
81
+ # ========================================
82
+ # CSRF ROUTES
83
+ # ========================================
84
+
85
+ def self.webhook_handler
86
+ [200, { 'content-type' => 'application/json' }, ['{"message": "Webhook processed (CSRF exempt)"}']]
87
+ end
88
+
89
+ def self.external_update
90
+ [200, { 'content-type' => 'application/json' }, ['{"message": "External update processed"}']]
91
+ end
92
+
93
+ def self.cleanup_data
94
+ [200, { 'content-type' => 'application/json' }, ['{"message": "Data cleanup completed"}']]
95
+ end
96
+
97
+ def self.sync_data
98
+ [200, { 'content-type' => 'application/json' }, ['{"message": "Data sync completed"}']]
99
+ end
100
+
101
+ def self.update_settings
102
+ [200, { 'content-type' => 'text/plain' }, ['Settings updated (CSRF protected)']]
103
+ end
104
+
105
+ def self.change_password
106
+ [200, { 'content-type' => 'text/plain' }, ['Password changed (CSRF protected)']]
107
+ end
108
+
109
+ def self.delete_profile
110
+ [204, {}, ['']]
111
+ end
112
+
113
+ # ========================================
114
+ # MULTIPLE PARAMETER COMBINATIONS
115
+ # ========================================
116
+
117
+ def self.api_data
118
+ [200, { 'content-type' => 'application/json' }, ['{"api": "v1", "data": "response"}']]
119
+ end
120
+
121
+ def self.api_submit
122
+ [201, { 'content-type' => 'application/json' }, ['{"message": "API submission processed"}']]
123
+ end
124
+
125
+ def self.api_update
126
+ [200, { 'content-type' => 'application/json' }, ['{"message": "API update completed"}']]
127
+ end
128
+
129
+ def self.admin_dashboard
130
+ [200, { 'content-type' => 'text/html' }, ['<h1>Admin Dashboard</h1><p>Administrative view</p>']]
131
+ end
132
+
133
+ def self.admin_settings
134
+ [200, { 'content-type' => 'text/html' }, ['<h1>Admin Settings</h1><p>Settings updated</p>']]
135
+ end
136
+
137
+ def self.mixed_content
138
+ [200, { 'content-type' => 'application/json' }, ['{"type": "mixed", "csrf": "exempt", "response": "auto"}']]
139
+ end
140
+
141
+ # ========================================
142
+ # CUSTOM PARAMETERS
143
+ # ========================================
144
+
145
+ def self.show_config
146
+ [200, { 'content-type' => 'application/json' }, ['{"environment": "production", "config": "displayed"}']]
147
+ end
148
+
149
+ def self.debug_info
150
+ [200, { 'content-type' => 'application/json' }, ['{"environment": "development", "debug": true}']]
151
+ end
152
+
153
+ def self.update_config
154
+ [200, { 'content-type' => 'application/json' }, ['{"message": "Config updated", "environment": "production"}']]
155
+ end
156
+
157
+ def self.feature_flags
158
+ [200, { 'content-type' => 'application/json' }, ['{"feature": "advanced", "mode": "enabled", "flags": []}']]
159
+ end
160
+
161
+ def self.toggle_feature
162
+ [200, { 'content-type' => 'application/json' }, ['{"feature": "beta", "mode": "test", "toggled": true}']]
163
+ end
164
+
165
+ # ========================================
166
+ # PARAMETER VALUE VARIATIONS
167
+ # ========================================
168
+
169
+ def self.api_v1
170
+ [200, { 'content-type' => 'application/json' }, ['{"version": "1.0", "api": "v1"}']]
171
+ end
172
+
173
+ def self.api_v2
174
+ [200, { 'content-type' => 'application/json' }, ['{"version": "2.0", "api": "v2"}']]
175
+ end
176
+
177
+ def self.api_legacy
178
+ [200, { 'content-type' => 'application/json' }, ['{"version": "legacy", "deprecated": true}']]
179
+ end
180
+
181
+ def self.complex_query
182
+ [200, { 'content-type' => 'application/json' }, ['{"query": "complex", "filter": "key=value"}']]
183
+ end
184
+
185
+ def self.config_db
186
+ [200, { 'content-type' => 'application/json' }, ['{"connection": "host=localhost", "configured": true}']]
187
+ end
188
+
189
+ # ========================================
190
+ # ERROR HANDLERS
191
+ # ========================================
192
+
193
+ def self.not_found
194
+ [404, { 'content-type' => 'text/html' }, ['<h1>404 - Page Not Found</h1><p>Advanced routes syntax example</p>']]
195
+ end
196
+
197
+ def self.server_error
198
+ [500, { 'content-type' => 'text/html' }, ['<h1>500 - Server Error</h1><p>Something went wrong</p>']]
199
+ end
200
+
201
+ # ========================================
202
+ # TESTING ROUTES
203
+ # ========================================
204
+
205
+ def self.test_json
206
+ [200, { 'content-type' => 'application/json' }, ['{"test": "json", "response_type": "json"}']]
207
+ end
208
+
209
+ def self.test_view
210
+ [200, { 'content-type' => 'text/html' }, ['<h1>Test View</h1><p>HTML view response</p>']]
211
+ end
212
+
213
+ def self.test_redirect
214
+ [302, { 'location' => '/' }, ['']]
215
+ end
216
+
217
+ def self.test_auto
218
+ [200, { 'content-type' => 'application/json' }, ['{"test": "auto", "response_type": "auto"}']]
219
+ end
220
+
221
+ def self.test_csrf
222
+ [200, { 'content-type' => 'text/html' }, ['<h1>CSRF Test</h1><p>POST request (CSRF protected)</p>']]
223
+ end
224
+
225
+ def self.test_no_csrf
226
+ [200, { 'content-type' => 'text/html' }, ['<h1>No CSRF Test</h1><p>POST request (CSRF exempt)</p>']]
227
+ end
228
+
229
+ def self.test_everything
230
+ [200, { 'content-type' => 'application/json' }, ['{"message": "All parameters tested", "csrf": "exempt", "custom": "value"}']]
231
+ end
232
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module V2
4
+ class Admin
5
+ def self.show
6
+ [200, { 'content-type' => 'text/html' }, ['<h1>V2 Admin</h1><p>Class method implementation</p>']]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module V2
4
+ class Config
5
+ def self.update
6
+ [200, { 'content-type' => 'application/json' }, ['{"message": "V2 config updated"}']]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module V2
4
+ class Settings
5
+ def self.modify
6
+ [200, { 'content-type' => 'application/json' }, ['{"message": "V2 settings modified", "csrf": "exempt"}']]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Admin
4
+ module Logic
5
+ class Manager
6
+ attr_reader :context, :params, :locale
7
+
8
+ def initialize(context, params, locale)
9
+ @context = context
10
+ @params = params
11
+ @locale = locale
12
+ end
13
+
14
+ def process
15
+ {
16
+ admin_manager: 'Active',
17
+ namespace: 'Admin::Logic',
18
+ management_tools: ['users', 'settings', 'logs'],
19
+ }
20
+ end
21
+
22
+ def response_data
23
+ { admin_logic_manager: process }
24
+ end
25
+ end
26
+ end
27
+ end