Class: Spikard::App
- Inherits:
-
Object
- Object
- Spikard::App
- Includes:
- LifecycleHooks, ProvideSupport
- Defined in:
- lib/spikard/app.rb
Overview
Collects route metadata so the Rust engine can execute handlers. rubocop:disable Metrics/ClassLength
Constant Summary collapse
- HTTP_METHODS =
%w[GET POST PUT PATCH DELETE OPTIONS HEAD TRACE].freeze
- SUPPORTED_OPTIONS =
%i[request_schema response_schema parameter_schema file_params is_async cors].freeze
Instance Attribute Summary collapse
-
#routes ⇒ Object
readonly
Returns the value of attribute routes.
Instance Method Summary collapse
- #default_handler_name(method, path) ⇒ Object
- #handler_map ⇒ Object
-
#initialize ⇒ App
constructor
A new instance of App.
- #register_route(method, path, handler_name: nil, **options, &block) ⇒ Object
- #route_metadata ⇒ Object
-
#run(config: nil, host: nil, port: nil) ⇒ Object
Run the Spikard server with the given configuration.
-
#sse(path, _handler_name: nil, **_options) { ... } ⇒ Proc
Register a Server-Sent Events endpoint.
-
#sse_producers ⇒ Hash
Get all registered SSE producers.
-
#websocket(path, _handler_name: nil, **_options) { ... } ⇒ Proc
Register a WebSocket endpoint.
-
#websocket_handlers ⇒ Hash
Get all registered WebSocket handlers.
Methods included from ProvideSupport
Methods included from LifecycleHooks
#lifecycle_hooks, #on_error, #on_request, #on_response, #pre_handler, #pre_validation
Constructor Details
#initialize ⇒ App
Returns a new instance of App.
130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/spikard/app.rb', line 130 def initialize @routes = [] @websocket_handlers = {} @sse_producers = {} @dependencies = {} @lifecycle_hooks = { on_request: [], pre_validation: [], pre_handler: [], on_response: [], on_error: [] } end |
Instance Attribute Details
#routes ⇒ Object (readonly)
Returns the value of attribute routes.
128 129 130 |
# File 'lib/spikard/app.rb', line 128 def routes @routes end |
Instance Method Details
#default_handler_name(method, path) ⇒ Object
187 188 189 190 191 |
# File 'lib/spikard/app.rb', line 187 def default_handler_name(method, path) normalized_path = path.gsub(/[^a-zA-Z0-9]+/, '_').gsub(/__+/, '_').sub(/^_+|_+$/, '') normalized_path = 'root' if normalized_path.empty? "#{method.to_s.downcase}_#{normalized_path}" end |
#handler_map ⇒ Object
177 178 179 180 181 182 183 184 185 |
# File 'lib/spikard/app.rb', line 177 def handler_map map = {} @routes.each do |entry| name = entry.[:handler_name] # Pass raw handler - DI resolution happens in Rust layer map[name] = entry.handler end map end |
#register_route(method, path, handler_name: nil, **options, &block) ⇒ Object
144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/spikard/app.rb', line 144 def register_route(method, path, handler_name: nil, **, &block) validate_route_arguments!(block, ) handler_name ||= default_handler_name(method, path) # Extract handler dependencies from block parameters handler_dependencies = extract_handler_dependencies(block) = (method, path, handler_name, , handler_dependencies) @routes << RouteEntry.new(, block) block end |
#route_metadata ⇒ Object
163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/spikard/app.rb', line 163 def # Extract handler dependencies when metadata is requested # This allows dependencies to be registered after routes @routes.map do |entry| = entry..dup # Re-extract dependencies in case they were registered after the route handler_dependencies = extract_handler_dependencies(entry.handler) [:handler_dependencies] = handler_dependencies unless handler_dependencies.empty? end end |
#run(config: nil, host: nil, port: nil) ⇒ Object
Run the Spikard server with the given configuration
rubocop:disable Metrics/AbcSize, Metrics/MethodLength
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/spikard/app.rb', line 262 def run(config: nil, host: nil, port: nil) require 'json' # Backward compatibility: if host/port are provided directly, create a config if config.nil? && (host || port) config = ServerConfig.new( host: host || '127.0.0.1', port: port || 8000 ) elsif config.nil? config = ServerConfig.new elsif config.is_a?(Hash) config = ServerConfig.new(**config) end # Convert route metadata to JSON routes_json = JSON.generate() # Get handler map handlers = handler_map # Get lifecycle hooks hooks = lifecycle_hooks # Get WebSocket handlers and SSE producers ws_handlers = websocket_handlers sse_prods = sse_producers # Get dependencies for DI deps = dependencies # Call the Rust extension's run_server function Spikard::Native.run_server(routes_json, handlers, config, hooks, ws_handlers, sse_prods, deps) # Keep Ruby process alive while server runs sleep rescue LoadError => e raise 'Failed to load Spikard extension. ' \ "Build it with: task build:ruby\n#{e.}" end |
#sse(path, _handler_name: nil, **_options) { ... } ⇒ Proc
Register a Server-Sent Events endpoint
220 221 222 223 224 225 |
# File 'lib/spikard/app.rb', line 220 def sse(path, _handler_name: nil, **, &factory) raise ArgumentError, 'block required for SSE producer factory' unless factory @sse_producers[path] = factory factory end |
#sse_producers ⇒ Hash
Get all registered SSE producers
237 238 239 |
# File 'lib/spikard/app.rb', line 237 def sse_producers @sse_producers.dup end |
#websocket(path, _handler_name: nil, **_options) { ... } ⇒ Proc
Register a WebSocket endpoint
203 204 205 206 207 208 |
# File 'lib/spikard/app.rb', line 203 def websocket(path, _handler_name: nil, **, &factory) raise ArgumentError, 'block required for WebSocket handler factory' unless factory @websocket_handlers[path] = factory factory end |
#websocket_handlers ⇒ Hash
Get all registered WebSocket handlers
230 231 232 |
# File 'lib/spikard/app.rb', line 230 def websocket_handlers @websocket_handlers.dup end |