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.



384
385
386
387
388
389
390
391
392
# File 'lib/belt/route_dsl.rb', line 384

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


468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/belt/route_dsl.rb', line 468

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



539
540
541
542
543
544
545
546
547
548
# File 'lib/belt/route_dsl.rb', line 539

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



559
560
561
562
563
# File 'lib/belt/route_dsl.rb', line 559

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



550
551
552
553
554
555
556
557
# File 'lib/belt/route_dsl.rb', line 550

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



565
566
567
568
569
570
571
572
573
574
575
# File 'lib/belt/route_dsl.rb', line 565

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


401
402
403
404
405
# File 'lib/belt/route_dsl.rb', line 401

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

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



524
525
526
527
528
529
530
531
532
533
534
535
536
537
# File 'lib/belt/route_dsl.rb', line 524

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



509
510
511
512
513
514
515
516
517
518
519
520
521
522
# File 'lib/belt/route_dsl.rb', line 509

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"


498
499
500
501
502
503
504
505
506
507
# File 'lib/belt/route_dsl.rb', line 498

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


422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
# File 'lib/belt/route_dsl.rb', line 422

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