Introducing Configr, an elegant configuration interface in Ruby



2010/03/01 // Leeds // // Feed



I’ve never really been happy with my previous solution to making configuration easy and elegant. It still felt too clunky and lacked the syntactical sugar that I’ve become accustomed to within Ruby. So configr was born.

Configr aims to provide a clean interface for configuring and reading a set of configuration values. The idea evolved from using a standard hash as a configuration store into a more elegant way to declare and read values from within a hash.

I wanted a way to be able to declare my configurations in a simple format, whether that be inline (in the format of a block), from a YAML file or as a mixture of the two. I also wanted to be able to have a simple way of overriding values for certain environments (for frameworks such as Sinatra and Rails). The project is far from done but it’s the start of a more elegant solution to these problems over my previous method (simple hash based configuration).

Using Configr is simple:

  configuration = Configr::Configuration.configure do |config|
    config.example_one = "One"
    config.example_two = "Two"
  end

  puts configuration.example_one
  puts configuration.example_two

Declaring values inline is great, but its also useful to pull them in from a YAML file:

  configuration = Configr::Configuration.configure("/path/to/file.yml")

  puts configuration.value_one
  puts configuration.value_two

Or as a YAML string:

  yaml = <<YAML

  example_one: "Hello"
  example_two: "It loads from YAML too!"
  
  YAML
  
  configuration = Configr::Configuration.configure(yaml)

  puts configuration.example_one
  puts configuration.example_two

Or a mixture of both methods:

  yaml = <<YAML

  example_three: "three"
  example_four: "four"
  
  YAML
  
  configuration = Configr::Configuration.configure(yaml) do |config|
    config.example_one = "one"
    config.example_two = "two"
  end
  
  puts configuration.example_one
  puts configuration.example_two
  puts configuration.example_three
  puts configuration.example_four

The idea is for Configr to be quite flexible in how you declare your configurations. The end result being able to read them in a more natural format:

  puts configuration.one.two.three

Sometimes when using configuration values you might want to assert whether the value exists before using it. Configr allows you to do this with the #key_name? syntax:

  puts configuration.one.two.three? # => true

Configr is intended to be framework agnostic, but it’s easy to get it going inside of any of the latest frameworks. I don’t plan to provide any “out of the box” way to hook Configr into Rails but it’s easy to implement:

  # In config/configuration.rb
  yaml_file = Rails.root.join("config", "environments", "#{Rails.env}.yml")
  
  Configuration = Configr::Configuration.configure(yaml_file) do |config|
    config.my.configuration.value = "value"
  end
  
  # In config/initializers/configuration.rb
  require Rails.root.join("config", "configuration.rb")
  
  # Anywhere in your Rails app
  Configuration.my.configuration.value

By requiring a different YAML file based on the environment it is easy to override global values with environment specific ones. For more examples of using Configr with other frameworks see the readme.

By design a configuration value is not meant to be edited or created after the configuration block has been run (if you do you will run into a Configr::ConfigurationLocked error). In my opinion configurations such as those created by Configr are meant to be read-only during the lifetime of the application.

The gem is now available on rubygems.org:

  gem install configr

It’s still early days for the project but I’m already enjoying using it in a few personal and client projects, for me it certainly beats the previous method. If you use it and find any bugs please file an issue to help me wean out any problems.

Other (possibly related) posts

Comments