Tinyconfig

TinyConfig provides a base class to create a Ruby configuration file loader.

The resulting configuration file is usable for people not familiar with Ruby, but it is possible for a power user to use full power of Ruby to script the configuration

Installation

Add this line to your application's Gemfile:

gem 'tinyconfig'

And then execute:

$ bundle

Or install it yourself as:

$ gem install tinyconfig

Usage

First, define your configuration class by creating a subclass of TinyConfig. Use option method to define known options. You may provide a default value as a second argument, and a validator/postprocessing as a block.

The block receives one argument: value as provided by user. It should raise ::ArgumentError if the provided value is invalid, and return the desired value otherwise. See the example/hello.rb file for a sample usage:

require 'tinyconfig'

class HelloConfig < TinyConfig
  option :recipient, 'World'

  option :repeat, 1 do |value|
    int_value = value.to_i
    if int_value < 1
      raise ::ArgumentError, "#{value.inspect} is not a number or is less than 1"
    end
    int_value
  end

  option :extra_greeting
end

cfg = HelloConfig.new
cfg.load ARGV.first if ARGV.first

cfg.repeat.times do
  puts "Hello, #{cfg.recipient}!"
end
puts cfg.extra_greeting if cfg.extra_greeting
$ ruby hello.rb
Hello, World!
$ cat config1.rb
recipient 'You'
$ ruby hello.rb config1.rb
Hello, You!
$ cat config2.rb
repeat 3
$ ruby hello.rb config2.rb
Hello, World!
Hello, World!
Hello, World!
$ cat config3.rb
repeat '2'
extra_greeting 'Really, hello!'
$ ruby hello.rb config3.rb
Hello, World!
Hello, World!
Really, hello!
$ cat config-invalid.rb
repeat 'whatever'
$ ruby hello.rb config-invalid.rb
hello.rb:9:in `block in <class:HelloConfig>': "whatever" is not a number or is less than 1 (ArgumentError)
    from /Users/japhy/Projekty/tinyconfig/lib/tinyconfig.rb:16:in `call'
    from /Users/japhy/Projekty/tinyconfig/lib/tinyconfig.rb:16:in `block in option'
    from ./config-invalid.rb:in `load'
    from /Users/japhy/Projekty/tinyconfig/lib/tinyconfig.rb:36:in `instance_eval'
    from /Users/japhy/Projekty/tinyconfig/lib/tinyconfig.rb:36:in `load'
    from hello.rb:18:in `<main>'

You can use the load method multiple times from your code, or you can load other files from your config files. The method also accepts glob expressions (e.g. load 'config_*.rb'). The bulk_load method load all files in the directory next to current config file, of the same name as current config.

Example: If file foo.rb calls:

bulk_load

it should do the same as

load 'foo/*.rb'

You can also use cfg.configure method to update the configuration inline in a block.

When you provide a lambda as a default or provided value, it will be called at runtime to determine the value. This way you can use settings that are not yet specified when the config file is being read:

class LambdaExample < TinyConfig
  option :foo
  option :bar, ->{ "Bar for foo=#{foo.inspect}" }
  option :baz
end

cfg = LambdaExample.new
cfg.bar # => "Bar for foo=nil"

cfg.configure do
  foo 23
end
cfg.bar # => "Bar for foo=23"

cfg.configure do
  baz ->{ bar.reverse }
end
cfg.baz # => "32=oof rof raB"

For details and corner cases, look into spec/ for the test cases.

Acknowledements

TinyConfig has been heavily inspired by Opscode's Mixlib::Config. We chose to implement our own tool, because Mixlib::Config configuration is global, which makes it very hard to provide isolation between test cases in the unit tests. TinyConfig is instance-based, which is easier to manage locally.

Contributing

See the CONTRIBUTING.md file