# dynamic_configuration

Dynamic_configuration is a library for storing application settings, with the following distinguishing characteristics:

* very easy setup with only one line of code

* setting files are neat-looking Ruby files, with all of Ruby
  available for specifying the setting values

* settings are divided into groups, each group defined in a separate
  file, making it easier to remember individual setting names and
  maintain the whole configuration

* settings can be overridden locally for a given installation (useful
  for customizing webapp configuration per-server, while keeping
  default developer settings in Git)

* Rails-friendly, for example settings can be overwritten
  per-Rails-environment, they are also automatically reloaded on
  every request in Rails development environment

* throughout field- and unit- tested

Developed as part of my work for www.tutoria.de/.

## Setup

After adding dynamic_configuration to your Gemfile, or installing and requiring it in your code manually, create a root directory for the settings, for example config/opts, and then in it a config/opts/opts.rb file with the following contents:

DynamicConfiguration::create(:Opts, __FILE__)

Once you require this file somewhere in your application, the constant Opts will hold all the settings.

Side-note: many more obvious constant names like Options, or Config, are names of classes defined by Ruby, Rails or popular gems, and will cause name clashes in certain contexts. Hence the less neat but more reliable proposed Opts name.

## Usage

### Basics

You create a settings group by creating a file somewhere in the opts directory, for example opts/main.rb, and defining some settings in it, using Ruby method call syntax and semantics, but with the name of the setting taking the place of the method name:

# config/opts/main.rb
owner_email "[email protected]"

This will make Opts.main.a_string evaluate to “sample value” anywhere in your application:

Opts.main.owner_email
=> "[email protected]"

The name of the group of opts is set to be the same as the base name of the file, so if you create emails.rb, the settings will be accessible as Opts.emails.whatever_you_define etc.

The value of each settings can be any kind of Ruby object, so the following is a valid config file:

# config/opts/main.rb
a_string "Some string"

an_array [1, 2, 3]

a_fancy_string_array(%w{
string1
string2
})

Which you can use in other places of your application like this:

Opts.main.a_string
=> "Some string"
Opts.main.an_array
=> [1, 2, 3]
Opts.main.a_fancy_string_array
=> ["string1", "string2"]

Note that hash map values have to be wrapped in parenthesis, since defining a setting works under the hood as a Ruby method call, so it has to have the syntax of one.

### Overriding settings per Rails environment ###

To overwrite the settings for a given Rails environment, just create a subdirectory of the opts directory named after the name of the environment, for example config/opts/test/. Then create a file corresponding to the group of settings of which one or more you want to override. For example, if config/opts/main.rb looks like above, and you create config/opts/test/main.rb looking like this:

# config/opts/test/main.rb
a_string "Test"

Then Opts.main.a_string will evaluate to “Test” in the test environment, while all the other Opts.main settings will evaluate to their values defined in config/opts/main.rb.

### Overriding settings locally ###

This is mostly meant for applications that are stored in a version control system and on which multiple persons work. One can keep the default settings in config/opts, and also create a config/opts/local directory, that can be ignored in version control. If then someone wants to override some setting just on a particular server or just on his local development environment, he/she can create a file corresponding to the group of settings of which one or more he/she wants to override, for example config/opts/local/main.rb:

# config/opts/local/main.rb
an_array [4, 5, 6]

Then, Opts.main.an_array will evaluate to [4, 5, 6] regardless of Rails environment and other Opts.main settings will be evaluated according to their per-Rails-environment definitions if present, or according to their global definitions in config/opts/main.rb otherwise.

## Tips ##

You can make the options available very early in the Rails loading process by explicitly requiring them in config/application.rb:

module SomeApplication
  class Application < Rails::Application
    require "config/opts/opts"

    # ..., rest of the config
  end
end

## Robustness ##

dynamic_configuration overwrites method_missing in the context of the configuration files to enable the syntax it provides. It doesn’t do anything to method_missing globally, nor does it do any other “magic” that could affect any piece of your application other then the configuration files themselves.

All the settings are frozen as soon as they are defined, so you won’t accidentally modify them. If you try to access a settings group that wasn’t defined, you will get an DynamicConfiguration::MissingGroupException, if you try to access a setting that isn’t defined of a group that is defined, you will get a DynamicConfiguration::MissingGroupException.