Class: BugBunny::Routing::RouteSet

Inherits:
Object
  • Object
show all
Defined in:
lib/bug_bunny/routing/route_set.rb

Overview

Gestiona la colección de rutas de la aplicación y expone el DSL de configuración.

Actúa como el motor principal del enrutador. Permite definir rutas de forma declarativa (estilo Rails) e incluye macros convenientes como ‘resources`, soportando bloques anidados `member` y `collection`.

Examples:

Configuración del DSL en un inicializador

route_set = RouteSet.new
route_set.draw do
  get 'ping', to: 'health#ping'

  resources :nodes, except: [:create, :destroy] do
    member do
      put :drain
    end
    collection do
      get :stats
    end
  end
end

Instance Attribute Summary collapse

DSL de Verbos HTTP collapse

Instance Method Summary collapse

Constructor Details

#initializeRouteSet

Inicializa un conjunto de rutas vacío y prepara el stack de scopes.



32
33
34
35
# File 'lib/bug_bunny/routing/route_set.rb', line 32

def initialize
  @routes = []
  @scopes = [] # Pila para rastrear el contexto (namespaces, resources, members)
end

Instance Attribute Details

#routesArray<BugBunny::Routing::Route> (readonly)

Returns Lista de rutas registradas y compiladas.

Returns:



29
30
31
# File 'lib/bug_bunny/routing/route_set.rb', line 29

def routes
  @routes
end

Instance Method Details

#clear!void

This method returns an undefined value.

Borra todas las rutas registradas y limpia los scopes. Es útil para entornos de pruebas (testing) o recarga en caliente (hot-reloading).



50
51
52
53
# File 'lib/bug_bunny/routing/route_set.rb', line 50

def clear!
  @routes.clear
  @scopes.clear
end

#collection { ... } ⇒ void

This method returns an undefined value.

Define rutas aplicables a la colección completa del recurso (Sin ID).

Al usar este bloque, el router antepondrá automáticamente el nombre del recurso a la URL generada e inferirá el controlador base.

Examples:

resources :nodes do
  collection do
    get :stats # Genera: GET nodes/stats => NodesController#stats
  end
end

Yields:

  • Bloque conteniendo definiciones de rutas.

Raises:

  • (ArgumentError)

    Si se llama fuera de un bloque ‘resources`.



189
190
191
192
193
194
195
196
197
# File 'lib/bug_bunny/routing/route_set.rb', line 189

def collection(&block)
  unless current_scope[:type] == :resource
    raise ArgumentError, "El bloque 'collection' solo puede usarse dentro de un bloque 'resources'"
  end

  with_scope({ type: :collection }) do
    instance_eval(&block)
  end
end

#delete(path, to: nil) ⇒ Object

Registra una ruta para el verbo DELETE.

Parameters:

  • path (String, Symbol)

    Patrón de la URL.

  • to (String, nil) (defaults to: nil)

    Destino (controlador#accion). Si es nil, se infiere del scope.



88
89
90
# File 'lib/bug_bunny/routing/route_set.rb', line 88

def delete(path, to: nil)
  add_route('DELETE', path, to: to)
end

#draw { ... } ⇒ void

This method returns an undefined value.

Evalúa un bloque de código en el contexto de esta instancia para construir el mapa. Utiliza ‘instance_eval` para exponer el DSL directamente.

Yields:

  • Bloque de configuración conteniendo las definiciones de ruteo.



42
43
44
# File 'lib/bug_bunny/routing/route_set.rb', line 42

def draw(&block)
  instance_eval(&block)
end

#get(path, to: nil) ⇒ Object

Registra una ruta para el verbo GET.

Parameters:

  • path (String, Symbol)

    Patrón de la URL.

  • to (String, nil) (defaults to: nil)

    Destino (controlador#accion). Si es nil, se infiere del scope.



60
61
62
# File 'lib/bug_bunny/routing/route_set.rb', line 60

def get(path, to: nil)
  add_route('GET', path, to: to)
end

#member { ... } ⇒ void

This method returns an undefined value.

Define rutas aplicables a un miembro específico del recurso (Requieren un ID).

Al usar este bloque, el router antepondrá automáticamente el nombre del recurso y el parámetro ‘:id` a la URL generada, e inferirá el controlador base.

Examples:

resources :nodes do
  member do
    put :drain # Genera: PUT nodes/:id/drain => NodesController#drain
  end
end

Yields:

  • Bloque conteniendo definiciones de rutas.

Raises:

  • (ArgumentError)

    Si se llama fuera de un bloque ‘resources`.



165
166
167
168
169
170
171
172
173
# File 'lib/bug_bunny/routing/route_set.rb', line 165

def member(&block)
  unless current_scope[:type] == :resource
    raise ArgumentError, "El bloque 'member' solo puede usarse dentro de un bloque 'resources'"
  end

  with_scope({ type: :member }) do
    instance_eval(&block)
  end
end

#namespace(name) { ... } ⇒ void

This method returns an undefined value.

Define un bloque de namespace para organizar controladores en módulos. Los namespaces pueden anidarse y se acumulan (ej: ‘namespace :api { namespace :v1 }` resulta en el namespace “Api::V1”).

Examples:

namespace :api do
  resources :users # Busca Api::UsersController
end

Parameters:

  • name (Symbol, String)

    Nombre del namespace (ej: :api, :v1).

Yields:

  • Bloque conteniendo las definiciones de rutas dentro de este namespace.



105
106
107
108
109
# File 'lib/bug_bunny/routing/route_set.rb', line 105

def namespace(name, &block)
  with_scope({ type: :namespace, name: name.to_s.camelize }) do
    instance_eval(&block)
  end
end

#patch(path, to: nil) ⇒ Object

Registra una ruta para el verbo PATCH.

Parameters:

  • path (String, Symbol)

    Patrón de la URL.

  • to (String, nil) (defaults to: nil)

    Destino (controlador#accion). Si es nil, se infiere del scope.



81
82
83
# File 'lib/bug_bunny/routing/route_set.rb', line 81

def patch(path, to: nil)
  add_route('PATCH', path, to: to)
end

#post(path, to: nil) ⇒ Object

Registra una ruta para el verbo POST.

Parameters:

  • path (String, Symbol)

    Patrón de la URL.

  • to (String, nil) (defaults to: nil)

    Destino (controlador#accion). Si es nil, se infiere del scope.



67
68
69
# File 'lib/bug_bunny/routing/route_set.rb', line 67

def post(path, to: nil)
  add_route('POST', path, to: to)
end

#put(path, to: nil) ⇒ Object

Registra una ruta para el verbo PUT.

Parameters:

  • path (String, Symbol)

    Patrón de la URL.

  • to (String, nil) (defaults to: nil)

    Destino (controlador#accion). Si es nil, se infiere del scope.



74
75
76
# File 'lib/bug_bunny/routing/route_set.rb', line 74

def put(path, to: nil)
  add_route('PUT', path, to: to)
end

#recognize(method, path) ⇒ Hash?

Evalúa una petición entrante contra el mapa de rutas.

Recorre las rutas en el orden en que fueron definidas. La primera ruta que haga match será la ganadora. Retorna los datos necesarios para instanciar el controlador e inyectarle los parámetros dinámicos extraídos.

Parameters:

  • method (String)

    Verbo HTTP entrante (ej. ‘GET’).

  • path (String)

    URL entrante (ej. ‘nodes/123/drain’).

Returns:

  • (Hash, nil)

    Hash con ‘:controller`, `:action`, `:params` y `:namespace`, o `nil` si no hay match.



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/bug_bunny/routing/route_set.rb', line 208

def recognize(method, path)
  @routes.each do |route|
    next unless route.match?(method, path)

    extracted_params = route.extract_params(path)

    return {
      controller: route.controller,
      action: route.action,
      params: extracted_params,
      namespace: route.namespace
    }
  end

  # Si llegamos aquí, es un 404 seguro.
  nil
end

#resources(name, only: nil, except: nil) { ... } ⇒ void

This method returns an undefined value.

Macro que genera automáticamente las rutas CRUD para un recurso RESTful. Soporta filtrado mediante ‘only` y `except`, y acepta un bloque para rutas anidadas.

Mapea las acciones: index (GET), show (GET /:id), create (POST), update (PUT/PATCH /:id) y destroy (DELETE /:id).

Parameters:

  • name (Symbol, String)

    Nombre del recurso en plural (ej. :nodes).

  • only (Array<Symbol>, Symbol, nil) (defaults to: nil)

    Acciones a incluir exclusivamente.

  • except (Array<Symbol>, Symbol, nil) (defaults to: nil)

    Acciones a excluir.

Yields:

  • Bloque para definir rutas ‘member` o `collection`.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/bug_bunny/routing/route_set.rb', line 122

def resources(name, only: nil, except: nil, &block)
  resource_path = name.to_s

  # Todas las acciones estándar disponibles
  actions = %i[index show create update destroy]

  # Aplicamos los filtros si existen
  if only
    actions &= Array(only).map(&:to_sym)
  elsif except
    actions -= Array(except).map(&:to_sym)
  end

  # Rutas estándar (Fuera del scope anidado)
  get    resource_path,          to: "#{resource_path}#index"   if actions.include?(:index)
  post   resource_path,          to: "#{resource_path}#create"  if actions.include?(:create)
  get    "#{resource_path}/:id", to: "#{resource_path}#show"    if actions.include?(:show)
  put    "#{resource_path}/:id", to: "#{resource_path}#update"  if actions.include?(:update)
  patch  "#{resource_path}/:id", to: "#{resource_path}#update"  if actions.include?(:update)
  delete "#{resource_path}/:id", to: "#{resource_path}#destroy" if actions.include?(:destroy)

  # Si se pasa un bloque, abrimos un Scope de Recurso para rutas anidadas
  return unless block_given?

  with_scope({ type: :resource, name: resource_path }) do
    instance_eval(&block)
  end
end