Class: Rack::Config::Flexible
- Inherits:
-
Object
- Object
- Rack::Config::Flexible
- Defined in:
- lib/rack/config/flexible.rb
Overview
Overview
Rack::Config::Flexible is an alternative to Rack::Config, offering much greater flexibility.
Configuration options are stored as key-value pairs in sections, partitioned by environments. For example:
+ environment
+ section
key -> value pairs
A simple DSL is provided and can be used either within a passed configuration block (to ::new), or to the #configuration method.
Facilities are also provided to load whole environments, and sections from either a single YAML file structured like, or from a directory tree.
Note that values from a file/directory tree can be overridden with #configure, or by passing a block to ::new.
DSL Example
Here’s an example showing the intended usage of the provided DSL:
require 'rack/config/flexible'
use Rack::Config::Flexible do
environment :production
section :data
set :key => 'value'
environment :development
section :data
set :key => 'dev_value'
# Set the current environment
environment :production
end
data.key
would return ‘value’ in production, and ‘dev_value’ in development; and would be accessed via the Rack environment like so:
env['rack.config']['data.key']
Values can also be replaced by:
env['rack.config']['data.key'] = 'new_value'
Keep in mind that anything that you would be able to do inside the block you’re passing to ::new, can also be done in a block passed to #configure since they both run in the same scope.
Single-File Example
Loading settings from a single file is extremely easy:
require 'rack/config/flexible'
use Rack::Config::Flexible :from_file => 'settings.yaml' do
# Set the current environment to production
environment :production
end
This expects the file to be laid out as follows:
environment:
section:
key: value
...
It’s important to note that when loading from YAML files, environment names and section names will be converted to Symbols.
Directory Tree Example
This is just as easy as loading from a single file. In this case, instead of specifying a file name, we specify a path to a directory tree.
require 'rack/config/flexible'
use Rack::Config::Flexible :from_file => 'settings' do
# Set the current environment to production
environment :production
end
This expects the directory tree to be laid out as follows:
settings/environment/section.yaml
where each directory under settings is an environment, containg a separate YAML file for each section. The YAML file itself will only hold key-value pairs for that particular section.
Loading Individual Environments/Sections from YAML
You can load individual environment and section bits from a YAML file as follows:
require 'rack/config/flexible'
use Rack::Config::Flexible do
environment :production
section :data, 'cfg/production/data.yaml'
environment :development, 'cfg/development.yaml'
# Set the current environment
environment :production
end
Any other calls to #set after #environment or #section will override the data loaded from the YAML file, if the same key is specified. Otherwise, they will just add to the Hash per usual.
Instance Method Summary collapse
-
#[](idx) ⇒ Object
Hash-like accessor for config data.
-
#[]=(idx, value) ⇒ Object
Hash-like modifier for config data.
- #_call(env) ⇒ Object
- #call(env) ⇒ Object
- #configure(&block) ⇒ Object
-
#environment(env, data = nil) ⇒ Object
:category:DSL.
-
#initialize(app, options = {}, &block) ⇒ Flexible
constructor
A new instance of Flexible.
-
#section(sec, vals = nil) ⇒ Object
:category:DSL.
-
#set(vals) ⇒ Object
:category:DSL.
Constructor Details
#initialize(app, options = {}, &block) ⇒ Flexible
Returns a new instance of Flexible.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/rack/config/flexible.rb', line 130 def initialize(app,={},&block) @app = app @values = {} raise ArgumentError.new('`options\' must be a Hash') unless .is_a?(Hash) if .has_key?(:from_file) && ::File.directory?([:from_file]) # Load from a directory tree Dir[[:from_file] + '/*'].each { |env| next unless ::File.directory?(env) environment ::File.basename(env) Dir[env + '/*.yaml'].each { |sec| next unless ::File.file?(sec) section ::File.basename(sec,'.yaml'),sec } } elsif .has_key?(:from_file) && ::File.exist?([:from_file]) # Load from a single file @values = Hash[YAML.load_file([:from_file]).map { |k,v| [k.to_sym, Hash[v.map { |k,v| [ k.to_sym,v ]}]] if k.is_a?(String) && v.is_a?(Hash) }] @env = @values.keys.first @sec = @values[@env].keys.last end instance_eval(&block) if block_given? end |
Instance Method Details
#[](idx) ⇒ Object
Hash-like accessor for config data
- idx
-
Path to the requested item, starting with the section (e.g.
default.key.subkey
)
Returns the value, or nil
if the value cannot be located
236 237 238 |
# File 'lib/rack/config/flexible.rb', line 236 def [](idx) manipulate_element(idx) end |
#[]=(idx, value) ⇒ Object
Hash-like modifier for config data
This will replace the value at idx
with value
if, and only if, idx
already exists.
- idx
-
Path to the requested item, starting with the section (e.g.
default.key.subkey
) - value
-
New value to set
249 250 251 252 |
# File 'lib/rack/config/flexible.rb', line 249 def []=(idx,value) raise ArgumentError.new('`idx\' must be a String') unless idx.is_a?(String) manipulate_element(idx,value) end |
#_call(env) ⇒ Object
162 163 164 165 |
# File 'lib/rack/config/flexible.rb', line 162 def _call(env) env['rack.config'] = self @app.call(env) end |
#call(env) ⇒ Object
158 159 160 |
# File 'lib/rack/config/flexible.rb', line 158 def call(env) dup._call(env) # For thread safety... end |
#configure(&block) ⇒ Object
167 168 169 |
# File 'lib/rack/config/flexible.rb', line 167 def configure(&block) instance_eval(&block) if block_given? end |
#environment(env, data = nil) ⇒ Object
:category:DSL
Set the current environment
- env
-
Environment to use. Defaults to
:production
- data
-
If this is a
String
, it’s assumed to be the location of a YAML file to load from. Otherwise, aHash
of data for the environment. (Optional)
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/rack/config/flexible.rb', line 182 def environment(env,data=nil) raise ArgumentError.new('`env\' must be a String or Symbol') unless env.is_a?(String) || env.is_a?(Symbol) # Load from a hash (if specified) or create a new hash @env = env.to_sym @values[@env] = {} unless @values.has_key?(@env) && @values[@env].is_a?(Hash) # Load from a file, or hash, if specified if data.is_a?(String) && ::File.exist?(data) @values[@env].merge!(Hash[YAML.load_file(data).map { |k,v| [k.to_sym, v] if k.is_a?(String) }]) @sec = @values[@env].keys.last elsif data.is_a?(Hash) @values[@env].merge!(data) end end |
#section(sec, vals = nil) ⇒ Object
:category:DSL
Set the current section
- sec
-
Section to use. Defaults to
:default
- vals
-
Values to prepopulate this section with. If this is a
String
, it’s assumed to be the location of a YAML file to load from.
207 208 209 210 211 212 213 214 215 216 |
# File 'lib/rack/config/flexible.rb', line 207 def section(sec,vals=nil) raise ArgumentError.new('`sec\' must be a String or Symbol') unless sec.is_a?(String) || sec.is_a?(Symbol) @sec = sec.to_sym @values[@env][@sec] = {} unless @values[@env][@sec].is_a?(Hash) @values[@env][@sec].merge!(vals) if vals.is_a?(Hash) # If vals is a string, it's assumed to be a YAML file @values[@env][@sec].merge!(YAML.load_file(vals)) if vals.is_a?(String) && ::File.exist?(vals) end |
#set(vals) ⇒ Object
:category:DSL
Add/Update a value to/in the current section
- vals
-
Hash
Keys/Value(s) to set
224 225 226 227 |
# File 'lib/rack/config/flexible.rb', line 224 def set(vals) raise ArgumentError.new('`vals\' must be a Hash') unless vals.is_a?(Hash) @values[@env][@sec].merge!(vals) end |