Ruby is the Ultimate Config File Format
App developers spend a lot of time implementing and doing battle with a babylon of config file formats when Ruby can provide a dynamic, concise, standardized alternative
Problems with Config Files
- Too many file formats: Config files for applications are built using a menagerie of standard (INI, YAML, XML, JSON, TOML) and non-standard (mutant-xml for fluentd) file formats.
- Static Files, Dynamic Environments: Whether you know it or not, your devops team spends a tremendous amount of time creating variant config files for your different development, staging and production environments. Upgrades often create cascading technical debt for configuration management.
- Platform Variations: Little tweaks are needed if your code runs on multiple platforms like OSX or different variations of Linux. A single parameter difference means a different config file is needs to be created for every supported system.
How Ruby Config Files Work
Applications written in any language can load a ruby config file at runtime by executing a system call (pseudocode):
actual_config = system(‘ruby app.conf.rb’)
…which enables that application to take advantage of many of the awesome features of ruby including string interpolation, here documents, backtick system calls, enumerators, regular expressions, helper methods, et al. when constructing the config. This means shorter, smarter config files like this (simple-app.conf.rb):
puts <<-EOF
development:
username: myuser
db: #{`hostname`.strip}production:
username: remote_user
db: remote
allowed: #{%w{*.dev mydomain.com}.join(‘, ‘)}
EOF
Applications with native support can go one step further and build simple DSLs to design semantically robust config files without the underlying ruby being conspicuous (pure-app.conf.rb):
config do
allow [‘server.com’, `hostname`.strip] vhost ‘api.server.com’ do
path ‘/usr/local/api’
end vhost ‘www.server.com' do
path ‘/usr/local/web’
end %w{wiki blog support}.each do |host|
vhost “#{host}.server.com” do
path “/usr/local/#{host}
end
end
end
This config file offers an easy to understand basic (even static) syntax for non-programmers, while allowing power users to create expansive smart configurations with very few lines of code. Configs can dynamically load remote data from databases or other remote sources.
A third option of course is to construct well defined classes for your configuration and use the core .to_json(), .to_yaml() or similar methods as an intermediate output format.
I encourage application developers to start using ruby to process their config files instead of inventing new formats and logic processing capabilities. Apps in other languages can simply execute a system call to process the files with ruby on load, and in the future, lightweight embedded ruby engines might simplify dependencies even further.