Skip to content

Standalone Application

Using MywayConfig in non-Rails Ruby applications like gems, CLI tools, and background workers.

Ruby Gem

Directory Structure

my_gem/
├── lib/
│   ├── my_gem.rb
│   └── my_gem/
│       ├── config.rb
│       └── config/
│           └── defaults.yml
├── my_gem.gemspec
└── Gemfile

Configuration Class

# lib/my_gem/config.rb
require 'myway_config'

module MyGem
  class Config < MywayConfig::Base
    config_name :my_gem
    env_prefix  :my_gem
    defaults_path File.expand_path("config/defaults.yml", __dir__)
    auto_configure!
  end
end

Defaults File

# lib/my_gem/config/defaults.yml
defaults:
  api:
    base_url: https://api.service.com
    timeout: 30
    retries: 3

  cache:
    enabled: true
    ttl: 3600

  log_level: :info

Main Module

# lib/my_gem.rb
require_relative 'my_gem/config'

module MyGem
  class << self
    def config
      @config ||= Config.new
    end

    def configure
      yield config if block_given?
    end

    def reset_config!
      @config = nil
    end
  end
end

Usage

require 'my_gem'

# Default configuration
MyGem.config.api.base_url  # => "https://api.service.com"

# Environment variable override
# MY_GEM_API__TIMEOUT=60 ruby app.rb
MyGem.config.api.timeout   # => 60

# XDG user config (~/.config/my_gem/my_gem.yml)
# Automatically loaded if present

CLI Application

Using Thor

#!/usr/bin/env ruby
require 'thor'
require 'myway_config'

module MyCLI
  class Config < MywayConfig::Base
    config_name :mycli
    env_prefix  :mycli
    defaults_path File.expand_path("../config/defaults.yml", __dir__)
    auto_configure!
  end

  class << self
    def config
      @config ||= Config.new
    end
  end

  class CLI < Thor
    desc "status", "Show current configuration"
    def status
      puts "API URL: #{MyCLI.config.api.base_url}"
      puts "Timeout: #{MyCLI.config.api.timeout}s"
    end

    desc "run", "Run the main task"
    option :verbose, type: :boolean, default: false
    def run
      config = MyCLI.config

      if config.debug || options[:verbose]
        puts "Debug mode enabled"
      end

      # Your application logic
    end
  end
end

MyCLI::CLI.start(ARGV)

Custom Config File

class CLI < Thor
  class_option :config, type: :string, desc: "Path to config file"

  desc "run", "Run with optional custom config"
  def run
    config = if options[:config]
               MyCLI::Config.new(options[:config])
             else
               MyCLI.config
             end

    # Use config...
  end
end

Background Worker

Sidekiq Example

# config/initializers/sidekiq.rb
require 'myway_config'

module MyWorker
  class Config < MywayConfig::Base
    config_name :my_worker
    env_prefix  :my_worker
    defaults_path File.expand_path("../../config/defaults.yml", __dir__)
    auto_configure!
  end

  class << self
    def config
      @config ||= Config.new
    end
  end
end

Sidekiq.configure_server do |config|
  config.redis = {
    url: MyWorker.config.redis.url,
    pool_size: MyWorker.config.redis.pool_size
  }
end

Worker Class

class ProcessingWorker
  include Sidekiq::Worker

  def perform(item_id)
    config = MyWorker.config

    timeout = config.processing.timeout
    retries = config.processing.retries

    # Process with configured settings
  end
end

Multiple Configurations

For applications with multiple configuration concerns:

module MyApp
  class DatabaseConfig < MywayConfig::Base
    config_name :database
    env_prefix  :myapp_db
    defaults_path File.expand_path("config/database.yml", __dir__)
    auto_configure!
  end

  class ApiConfig < MywayConfig::Base
    config_name :api
    env_prefix  :myapp_api
    defaults_path File.expand_path("config/api.yml", __dir__)
    auto_configure!
  end

  class << self
    def database_config
      @database_config ||= DatabaseConfig.new
    end

    def api_config
      @api_config ||= ApiConfig.new
    end
  end
end

# Usage
MyApp.database_config.host
MyApp.api_config.timeout

Testing Configuration

# test/test_helper.rb
require 'minitest/autorun'
require 'my_gem'

module TestHelpers
  def with_config(overrides, &block)
    original = MyGem.instance_variable_get(:@config)
    MyGem.instance_variable_set(:@config, MyGem::Config.new(overrides))
    yield
  ensure
    MyGem.instance_variable_set(:@config, original)
  end
end

class MyTest < Minitest::Test
  include TestHelpers

  def test_with_custom_config
    with_config(api: { timeout: 5 }) do
      assert_equal 5, MyGem.config.api.timeout
    end
  end
end