Class: Belt::Application::RouteBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/belt/route_dsl.rb

Instance Method Summary collapse

Constructor Details

#initialize(gateway) ⇒ RouteBuilder

Returns a new instance of RouteBuilder.



323
324
325
326
327
328
329
330
331
# File 'lib/belt/route_dsl.rb', line 323

def initialize(gateway)
  @gateway = gateway
  @scope_prefix = ''
  @scope_module = nil
  @lambda_target = nil
  @scope_auth = nil
  @scope_tables = []
  @scope_controller = nil
end

Instance Method Details

#function(name, options = {}) ⇒ Object

Target a different Lambda function for enclosed routes. Routes within this block will have their :lambda field set to name. Does NOT affect path prefixes or controller module resolution.

Example:

gateway :api, auth: :cognito do
resources :posts                # → lambda: "api"

function :onboarding do
  resources :stuff              # → lambda: "onboarding"
end

function :custom do
  get '/blah'                   # → lambda: "custom"
end
end


407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/belt/route_dsl.rb', line 407

def function(name, options = {}, &)
  previous_lambda = @lambda_target
  @lambda_target = name.to_s
  # function blocks can also carry auth/tables
  previous_auth = @scope_auth
  previous_tables = @scope_tables
  @scope_auth = options[:auth] if options[:auth]
  @scope_tables = (@scope_tables + Array(options[:tables] || [])).uniq

  instance_eval(&) if block_given?

  @lambda_target = previous_lambda
  @scope_auth = previous_auth
  @scope_tables = previous_tables
end

#mount(mountable, options = {}) ⇒ Object



478
479
480
481
482
483
484
485
486
487
# File 'lib/belt/route_dsl.rb', line 478

def mount(mountable, options = {})
  prefix = options[:at]&.to_s&.gsub(%r{^/|/$}, '') || ''
  extra_tables = Array(options[:tables] || [])
  auth_override = options[:auth]
  route_definitions = mountable.respond_to?(:routes) ? mountable.routes : []

  route_definitions.each do |route_def|
    mount_route(route_def, prefix, extra_tables, auth_override)
  end
end

#mount_full_path(path, prefix) ⇒ Object



498
499
500
501
502
# File 'lib/belt/route_dsl.rb', line 498

def mount_full_path(path, prefix)
  full_path = prefix.empty? ? path : "/#{prefix}#{path}"
  full_path = full_path.chomp('/') unless full_path == '/'
  build_path(full_path)
end

#mount_route(route_def, prefix, extra_tables, auth_override) ⇒ Object



489
490
491
492
493
494
495
496
# File 'lib/belt/route_dsl.rb', line 489

def mount_route(route_def, prefix, extra_tables, auth_override)
  method = route_def[:method].to_sym
  path = route_def[:path].to_s.gsub(/:([a-zA-Z_]\w*)/) { "{#{::Regexp.last_match(1)}}" }
  full_path = mount_full_path(path, prefix)
  route_options = mount_route_options(route_def, path, prefix, extra_tables, auth_override)

  @gateway.send(method, full_path, route_options)
end

#mount_route_options(route_def, path, prefix, extra_tables, auth_override) ⇒ Object



504
505
506
507
508
509
510
511
512
513
514
# File 'lib/belt/route_dsl.rb', line 504

def mount_route_options(route_def, path, prefix, extra_tables, auth_override)
  route_options = (route_def[:options] || {}).dup
  route_options[:tables] = (extra_tables + Array(route_options[:tables] || [])).uniq
  route_options[:auth] = auth_override if auth_override
  route_options[:auth] ||= @scope_auth if @scope_auth
  route_options[:tables] = (@scope_tables + route_options[:tables]).uniq if @scope_tables.any?
  route_options[:controller] ||= prefix.gsub('-', '_') unless prefix.empty?
  stripped = path.gsub(%r{^/|/$}, '')
  route_options[:action] ||= stripped.empty? ? 'index' : stripped.gsub('-', '_')
  route_options
end

#namespace(name, options = {}) ⇒ Object

Rails-like namespace — adds both a path prefix AND a module prefix. Equivalent to: scope path: "admin", module: "admin"

Example:

namespace :admin do
resources :users   # → /admin/users, controller: "admin/users"
end


340
341
342
343
344
# File 'lib/belt/route_dsl.rb', line 340

def namespace(name, options = {}, &)
  segment = name.to_s
  merged = { path: segment, module: segment }.merge(options)
  scope(merged, &)
end

#resource(name, options = {}) ⇒ Object



463
464
465
466
467
468
469
470
471
472
473
474
475
476
# File 'lib/belt/route_dsl.rb', line 463

def resource(name, options = {})
  options = apply_scope_options(options)

  if @scope_prefix.empty? && @scope_module.nil?
    @gateway.resource(name, options)
  elsif @scope_prefix.empty?
    resource_name = name.to_s
    controller = determine_scoped_controller(resource_name)
    options = options.merge(controller: controller) unless options[:controller]
    @gateway.resource(name, options)
  else
    build_scoped_resource(name, options)
  end
end

#resources(name, options = {}) ⇒ Object



448
449
450
451
452
453
454
455
456
457
458
459
460
461
# File 'lib/belt/route_dsl.rb', line 448

def resources(name, options = {}, &)
  options = apply_scope_options(options)

  if @scope_prefix.empty? && @scope_module.nil?
    @gateway.resources(name, options, &)
  elsif @scope_prefix.empty?
    resource_name = name.to_s
    controller = determine_scoped_controller(resource_name)
    options = options.merge(controller: controller) unless options[:controller]
    @gateway.resources(name, options, &)
  else
    build_scoped_resources(name, options, &)
  end
end

#root(options_or_target = nil, **options) ⇒ Object

Rails-like root — defines a GET / route.

Examples:

root to: "welcome#show"
root action: :show, controller: :welcome
root "pages#home"


437
438
439
440
441
442
443
444
445
446
# File 'lib/belt/route_dsl.rb', line 437

def root(options_or_target = nil, **options)
  if options_or_target.is_a?(String)
    options[:to] = options_or_target
  elsif options_or_target.is_a?(Hash)
    options = options_or_target.merge(options)
  end
  options[:auth] ||= :none
  route_options = apply_scope_to_route(options)
  @gateway.send(:get, '/', route_options)
end

#scope(options = {}) ⇒ Object

Rails-like scope — groups routes with shared options (path prefix, module, auth, tables, controller).

Examples:

scope path: "admin" do
resources :users   # → /admin/users
end

scope module: "v2" do
resources :users   # → /users, controller: "v2/users"
end

scope path: "v1", module: "v1", auth: :cognito do
resources :posts   # → /v1/posts, controller: "v1/posts", auth: cognito
end


361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/belt/route_dsl.rb', line 361

def scope(options = {}, &)
  previous_prefix = @scope_prefix
  previous_module = @scope_module
  previous_auth = @scope_auth
  previous_tables = @scope_tables
  previous_controller = @scope_controller

  # Nest path segments: scope path: "a" { scope path: "b" } → "a/b"
  if options.key?(:path)
    segment = options[:path].to_s.gsub(%r{^/|/$}, '')
    @scope_prefix = @scope_prefix.to_s.empty? ? segment : "#{@scope_prefix}/#{segment}"
  end
  # Nest module segments: namespace :admin { namespace :v2 } → "admin/v2"
  if options.key?(:module)
    mod_segment = options[:module].to_s
    @scope_module = @scope_module.to_s.empty? ? mod_segment : "#{@scope_module}/#{mod_segment}"
  end
  @scope_auth = options[:auth] || @scope_auth
  @scope_tables = (@scope_tables + Array(options[:tables] || [])).uniq
  @scope_controller = options[:controller] || @scope_controller

  instance_eval(&) if block_given?

  @scope_prefix = previous_prefix
  @scope_module = previous_module
  @scope_auth = previous_auth
  @scope_tables = previous_tables
  @scope_controller = previous_controller
end