class Kangaru::Application

def apply_config!

def apply_config!
  raise "config already applied" if configured?
  config.import!(config_path) unless config_path.nil?
  validate_config!
  @database = setup_database!
  @configured = true
end

def autoloader

def autoloader
  @autoloader ||= Zeitwerk::Loader.new.tap do |loader|
    loader.inflector = Zeitwerk::GemInflector.new(paths.source.to_s)
    loader.collapse(paths.collapsed_dirs)
    loader.push_dir(paths.lib_path.to_s)
  end
end

def config

Lazy-loaded to allow defaults to be set after application is created.
def config
  @config ||= Config.new
end

def configure(&block)

def configure(&block)
  block.call(config)
end

def configured?

def configured?
  @configured == true
end

def const_get(const)

def const_get(const)
  return unless namespace.const_defined?(const)
  namespace.const_get(const)
end

def initialize(source:, namespace:)

def initialize(source:, namespace:)
  @paths = Paths.new(source:)
  @namespace = namespace
  autoloader.setup
end

def router

def router
  @router ||= Router.new(namespace:)
end

def run!(*argv)

def run!(*argv)
  request = RequestBuilder.new(argv).build
  router.resolve(request)
end

def setup_database!

def setup_database!
  return unless config.database.adaptor
  Database.new(**config.database.serialise).tap do |database|
    database.setup!
    database.migrate!
  end
end

def validate_config!

def validate_config!
  return if config.valid?
  message = config.errors.map(&:full_message).join(", ")
  raise InvalidConfigError, message
end