Module: Tina4::Router

Defined in:
lib/tina4/router.rb

Defined Under Namespace

Classes: GroupContext

Class Method Summary collapse

Class Method Details

.add(method, path, handler, auth_handler: nil, swagger_meta: {}, middleware: [], template: nil) ⇒ Object



262
263
264
265
266
267
268
269
270
271
272
# File 'lib/tina4/router.rb', line 262

def add(method, path, handler, auth_handler: nil, swagger_meta: {}, middleware: [], template: nil)
  route = Route.new(method, path, handler,
                    auth_handler: auth_handler,
                    swagger_meta: swagger_meta,
                    middleware: middleware,
                    template: template)
  routes << route
  method_index[route.method] << route
  Tina4::Log.debug("Route registered: #{method.upcase} #{path}")
  route
end

.any(path, middleware: [], swagger_meta: {}, template: nil, &block) ⇒ Object



294
295
296
# File 'lib/tina4/router.rb', line 294

def any(path, middleware: [], swagger_meta: {}, template: nil, &block)
  add("ANY", path, block, middleware: middleware, swagger_meta: swagger_meta, template: template)
end

.clear!Object Also known as: clear



336
337
338
339
340
# File 'lib/tina4/router.rb', line 336

def clear!
  @routes = []
  @method_index = Hash.new { |h, k| h[k] = [] }
  @ws_routes = []
end

.delete(path, middleware: [], swagger_meta: {}, template: nil, &block) ⇒ Object



290
291
292
# File 'lib/tina4/router.rb', line 290

def delete(path, middleware: [], swagger_meta: {}, template: nil, &block)
  add("DELETE", path, block, middleware: middleware, swagger_meta: swagger_meta, template: template)
end

.find_route(method, path) ⇒ Object



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/tina4/router.rb', line 298

def find_route(method, path)
  normalized_method = method.upcase
  # Normalize path once (not per-route)
  normalized_path = path.gsub("\\", "/")
  normalized_path = "/#{normalized_path}" unless normalized_path.start_with?("/")
  normalized_path = normalized_path.chomp("/") unless normalized_path == "/"

  # Check ANY routes first, then method-specific routes
  candidates = (method_index["ANY"] || []) + (method_index[normalized_method] || [])
  candidates.each do |route|
    params = route.match_path(normalized_path)
    return [route, params] if params
  end
  nil
end

.find_ws_route(path) ⇒ Object

Find a matching WebSocket route for a given path. Returns [ws_route, params] or nil.



245
246
247
248
249
250
251
252
253
254
255
# File 'lib/tina4/router.rb', line 245

def find_ws_route(path)
  normalized = path.gsub("\\", "/")
  normalized = "/#{normalized}" unless normalized.start_with?("/")
  normalized = normalized.chomp("/") unless normalized == "/"

  ws_routes.each do |ws_route|
    params = ws_route.match?(normalized)
    return [ws_route, params] if params
  end
  nil
end

.get(path, middleware: [], swagger_meta: {}, template: nil, &block) ⇒ Object

Convenience registration methods



274
275
276
# File 'lib/tina4/router.rb', line 274

def get(path, middleware: [], swagger_meta: {}, template: nil, &block)
  add("GET", path, block, middleware: middleware, swagger_meta: swagger_meta, template: template)
end

.get_routesObject



213
214
215
# File 'lib/tina4/router.rb', line 213

def get_routes
  routes
end

.get_web_socket_routesObject

Parity alias — returns all registered WebSocket routes.



227
228
229
# File 'lib/tina4/router.rb', line 227

def get_web_socket_routes
  ws_routes
end

.group(prefix, auth_handler: nil, middleware: [], &block) ⇒ Object



343
344
345
# File 'lib/tina4/router.rb', line 343

def group(prefix, auth_handler: nil, middleware: [], &block)
  GroupContext.new(prefix, auth_handler, middleware).instance_eval(&block)
end

.list_routesObject



217
218
219
# File 'lib/tina4/router.rb', line 217

def list_routes
  routes
end

.load_routes(directory) ⇒ Object

Load route files from a directory (file-based route discovery)



348
349
350
351
352
353
354
355
356
357
358
# File 'lib/tina4/router.rb', line 348

def load_routes(directory)
  return unless Dir.exist?(directory)
  Dir.glob(File.join(directory, "**/*.rb")).sort.each do |file|
    begin
      load file
      Tina4::Log.debug("Route loaded: #{file}")
    rescue => e
      Tina4::Log.error("Failed to load route #{file}: #{e.message}")
    end
  end
end

.match(method, path) ⇒ Object

Find a route matching method + path. Returns [route, params] or nil. match(method, path) — consistent with Python, PHP, and Node.



316
317
318
# File 'lib/tina4/router.rb', line 316

def match(method, path)
  find_route(method, path)
end

.method_indexObject

Routes indexed by HTTP method for O(1) method lookup



258
259
260
# File 'lib/tina4/router.rb', line 258

def method_index
  @method_index ||= Hash.new { |h, k| h[k] = [] }
end

.patch(path, middleware: [], swagger_meta: {}, template: nil, &block) ⇒ Object



286
287
288
# File 'lib/tina4/router.rb', line 286

def patch(path, middleware: [], swagger_meta: {}, template: nil, &block)
  add("PATCH", path, block, middleware: middleware, swagger_meta: swagger_meta, template: template)
end

.post(path, middleware: [], swagger_meta: {}, template: nil, &block) ⇒ Object



278
279
280
# File 'lib/tina4/router.rb', line 278

def post(path, middleware: [], swagger_meta: {}, template: nil, &block)
  add("POST", path, block, middleware: middleware, swagger_meta: swagger_meta, template: template)
end

.put(path, middleware: [], swagger_meta: {}, template: nil, &block) ⇒ Object



282
283
284
# File 'lib/tina4/router.rb', line 282

def put(path, middleware: [], swagger_meta: {}, template: nil, &block)
  add("PUT", path, block, middleware: middleware, swagger_meta: swagger_meta, template: template)
end

.routesObject



209
210
211
# File 'lib/tina4/router.rb', line 209

def routes
  @routes ||= []
end

.use(klass) ⇒ Object

Register a class-based middleware globally. The class should define static before_* and/or after_* methods. Example:

class AuthMiddleware
  def self.before_auth(request, response)
    unless request.headers["authorization"]
      return [request, response.json({ error: "Unauthorized" }, 401)]
    end
    [request, response]
  end
end
Tina4::Router.use(AuthMiddleware)


332
333
334
# File 'lib/tina4/router.rb', line 332

def use(klass)
  Tina4::Middleware.use(klass)
end

.websocket(path, &block) ⇒ Object

Register a WebSocket route. The handler block receives (connection, event, data) where:

connection — WebSocketConnection with #send, #broadcast, #close, #params
event      — :open, :message, or :close
data       — String payload for :message, nil for :open/:close


236
237
238
239
240
241
# File 'lib/tina4/router.rb', line 236

def websocket(path, &block)
  ws_route = WebSocketRoute.new(path, block)
  ws_routes << ws_route
  Tina4::Log.debug("WebSocket route registered: #{path}")
  ws_route
end

.ws_routesObject

Registered WebSocket routes



222
223
224
# File 'lib/tina4/router.rb', line 222

def ws_routes
  @ws_routes ||= []
end