Loaders¶
MywayConfig provides custom loaders that extend Anyway Config's loading system.
Loading Priority¶
Configuration values are loaded in order (lowest to highest priority):
- DefaultsLoader - Bundled defaults from your gem
- XdgConfigLoader - User's XDG config files
- Anyway Config loaders - Project config, local overrides
- Environment variables -
PREFIX_KEY=value - Constructor overrides - Hash passed to
new
Higher priority sources override lower priority values.
DefaultsLoader¶
Loads bundled default configuration from a YAML file.
Purpose¶
Ensures default values are always available regardless of where the gem is installed. The defaults file is the single source of truth for configuration structure.
Registration¶
class MyApp::Config < MywayConfig::Base
config_name :myapp
defaults_path File.expand_path("config/defaults.yml", __dir__)
end
Class Methods¶
register¶
Register a defaults file path.
defaults_path¶
Get the registered path for a config name.
defaults_exist?¶
Check if defaults file exists.
schema¶
Get the defaults section from the YAML file.
MywayConfig::Loaders::DefaultsLoader.schema(:myapp)
# => {database: {host: "localhost", ...}, log_level: :info, ...}
valid_environments¶
Get list of valid environment names.
MywayConfig::Loaders::DefaultsLoader.valid_environments(:myapp)
# => [:development, :production, :test]
valid_environment?¶
Check if an environment name is valid.
MywayConfig::Loaders::DefaultsLoader.valid_environment?(:myapp, :production)
# => true
MywayConfig::Loaders::DefaultsLoader.valid_environment?(:myapp, :staging)
# => false
Loading Behavior¶
The loader:
- Reads the
defaults:section as base values - Deep-merges current environment's overrides
- Returns the merged configuration
# defaults.yml
defaults:
database:
host: localhost
port: 5432
production:
database:
host: prod-db.example.com
In production, the loader returns:
XdgConfigLoader¶
Loads user configuration from XDG Base Directory paths.
Purpose¶
Allows users to override configuration globally without modifying project files. Useful for personal preferences or machine-specific settings.
XDG Paths¶
The loader checks these paths (in order of priority):
- macOS only:
~/Library/Application Support/{app}/{app}.yml ~/.config/{app}/{app}.yml(XDG default)$XDG_CONFIG_HOME/{app}/{app}.yml(if set)
Higher-numbered paths take precedence.
Class Methods¶
config_paths¶
Get all potential config directory paths.
MywayConfig::Loaders::XdgConfigLoader.config_paths(:myapp)
# => [
# "/Users/me/Library/Application Support/myapp", # macOS only
# "/Users/me/.config/myapp"
# ]
find_config_file¶
Find the first existing config file.
MywayConfig::Loaders::XdgConfigLoader.find_config_file(:myapp)
# => "/Users/me/.config/myapp/myapp.yml" or nil
File Format¶
XDG config files can be flat or environment-specific:
Flat format:
With environments:
# ~/.config/myapp/myapp.yml
development:
database:
host: dev-custom-host
production:
database:
host: prod-custom-host
Example Usage¶
Create a user-specific override:
mkdir -p ~/.config/myapp
cat > ~/.config/myapp/myapp.yml << 'EOF'
database:
host: custom-db.local
port: 5433
EOF
Now your application uses these values:
config = MyApp::Config.new
config.database.host # => "custom-db.local"
config.database.port # => 5433
Loader Registration¶
Loaders are automatically registered when you call MywayConfig.setup! (which happens when requiring the gem).
# lib/myway_config.rb
module MywayConfig
def self.setup!
return if @setup_complete
Anyway.loaders.insert_before(
:yml,
:xdg_config,
Loaders::XdgConfigLoader
)
Anyway.loaders.insert_before(
:xdg_config,
:bundled_defaults,
Loaders::DefaultsLoader
)
@setup_complete = true
end
end
Manual Setup¶
If you need to control when loaders are registered:
require 'myway_config'
# Check if already set up
MywayConfig.setup? # => true (automatic)
# Reset and re-setup (mainly for testing)
MywayConfig.reset!
MywayConfig.setup!
Custom Loaders¶
You can create custom loaders by extending Anyway::Loaders::Base:
class MyCustomLoader < Anyway::Loaders::Base
def call(name:, **options)
trace!(:custom, source: "my_source") do
# Return a Hash of configuration values
load_from_custom_source(name)
end
end
private
def load_from_custom_source(name)
# Your loading logic here
{}
end
end
# Register the loader
Anyway.loaders.insert_after(:yml, :custom, MyCustomLoader)