pure ruby scoped configuration files
configuration.rb provides a mechanism for configuring ruby programs with ruby configuration files. a configuration.rb file, for example ‘config/app.rb’, can be written simply as
Configuration.for('app') { key 'value' foo 'bar' port 42 }
and loaded via the normal ruby require/load mechanism
Kernel.load 'config/app.rb'
or with a slightly augmented loading mechnanism which simply searches an extra set of paths in addition to the standard ones
Configuration.path = %w( config configuration ) Configuration.load 'app'
configurations are completely open
Configuration.for('app') { object_id 'very open' }
support arbitrarily nested values
Configuration.for('app') { a { b { c { d 42 } } } } c = Configuration.for 'app' p c.a.b.c.d #=> 42
allow POLS scoped lookup of vars
Configuration.for('config') { outer 'bar' inner { value 42 } } c = Configuration.for 'config' p c.outer #=> 'bar' p c.inner.value #=> 42 p c.inner.outer #=> 'bar'
allow default values
default = Configuration.for( 'default' ) { a 1 b 2 } c = Configuration.for( 'config', default ) { a 10 } p c.a #=> 10 p c.b #=> 2
and not a whole lot else - configuration.rb is s very small library consisting of one file and < 150 loc
~ > cat samples/a.rb # # basic usage is quite, simple, load the config and use it's values. the # config syntax is fairly obvious, i think, but note that it *is* ruby and any # ruby can be included. also note that each config is named, allowing # multiple configs to be places in one file # require 'configuration' c = Configuration.load 'a' p c.a + c.b - c.c ~ > ruby samples/a.rb 42
~ > cat samples/b.rb # # configuration.rb supports a very natural nesting syntax. note how values # are scoped in a POLS fashion # require 'configuration' c = Configuration.for 'b' p c.www.url p c.db.url p c.mail.url ~ > ruby samples/b.rb "http://codeforpeople.com:80" "db://codeforpeople.com:5342" "mail://gmail.com:25"
~ > cat samples/c.rb # # configuration.rb let's you keep code very dry. # require 'configuration' Configuration.load 'c' p Configuration.for('development').db p Configuration.for('production').db p Configuration.for('testing').db ~ > ruby samples/c.rb "db/development" "db/production" "db/testing"
~ > cat samples/d.rb # # configuration.rb makes use of an external blank slate dsl, this means that # you Configuration objects do, in fact, have all built-in ruby methods such # as #inspect, etc, *unless* you configure over the top of them. the effect # is a configuration object that behaves like a nice ruby object, but which # allows *any* key to be configured # require 'configuration' c = Configuration.for 'd' p c.object_id p c.inspect p c.p ~ > ruby samples/d.rb config/d.rb:2:in `object_id': wrong number of arguments (1 for 0) (ArgumentError) from config/d.rb:2 from ./lib/configuration.rb:159:in `instance_eval' from ./lib/configuration.rb:159:in `call' from ./lib/configuration.rb:159:in `method_missing' from ./lib/configuration.rb:105:in `evaluate' from ./lib/configuration.rb:68:in `initialize' from ./lib/configuration.rb:29:in `new' from ./lib/configuration.rb:29:in `for' from config/d.rb:1 from ./lib/configuration.rb:53:in `load' from ./lib/configuration.rb:53:in `load' from ./lib/configuration.rb:31:in `for' from samples/d.rb:10
~ > cat samples/e.rb # # configuration.rb uses a totally clean slate dsl for the block. if you need # to access base Object methods you can do this # require 'configuration' c = Configuration.for 'e' p c.foo p c.bar p c.foobar ~ > ruby samples/e.rb 42 "forty-two" 42.0
~ > cat samples/f.rb # # configuration.rb let's you inherit values from another configuration. # Like this, you keep your code very dry. # require 'configuration' Configuration.load 'f' p c.a p c.b ~ > ruby samples/f.rb 10 2