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



461
462
463
464
465
466
467
468
469
470
# File 'lib/belt/route_dsl.rb', line 461

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



481
482
483
484
485
# File 'lib/belt/route_dsl.rb', line 481

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



472
473
474
475
476
477
478
479
# File 'lib/belt/route_dsl.rb', line 472

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



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

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



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

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



431
432
433
434
435
436
437
438
439
440
441
442
443
444
# File 'lib/belt/route_dsl.rb', line 431

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

#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