lib/ztk/config.rb
require 'ostruct'
module ZTK
# Config Error Class
#
# @author Zachary Patten <zpatten AT jovelabs DOT io>
class ConfigError < Error; end
# Configuration Module
#
# Extend an existing class with this module to turn it into a singleton
# configuration class.
#
# Given we have some code like:
#
# class C
# extend(ZTK::Config)
# end
#
# We can then do things like:
#
# C.thing = "something"
#
# or we can reference keys this way:
#
# C[:thing] = "something"
#
# Accessing the value is just as simple:
#
# puts C.thing
#
# We can also load configurations from disk. Assuming we have a file (i.e. config.rb) like:
#
# message "Hello World"
# thing (1+1)
#
# We can load it like so:
#
# C.from_file("config.rb")
#
# Then we can reference the configuration defined in the file as easily as:
#
# puts C.message
#
# @author Zachary Patten <zpatten AT jovelabs DOT io>
module Config
# Extend base class with this module.
#
# This will add the *configuration* attribute to the base class and create
# a new *OpenStruct* object assigning it to the *configuration* attribute.
#
def self.extended(base)
class << base
attr_accessor :configuration
end
base.configuration = OpenStruct.new
end
# Loads a configuration from a file.
#
def from_file(filename)
self.instance_eval(IO.read(filename), filename)
end
# Yields the configuration OpenStruct object to a block.
#
# @yield [configuration] Pass the configuration OpenStruct object to the
# specified block.
#
def config(&block)
block and block.call(self.configuration)
end
# Get the value of a configuration key.
#
# @param [Symbol, String] key A symbol or string of the configuration
# key to return.
#
# @return The value currently assigned to the configuration key.
#
def [](key)
_get(key)
end
# Set the value of a configuration key.
#
# @param [Symbol, String] key A symbol or string of the configuration
# key to set.
# @param value The value which you want to assign to the configuration
# key.
#
# @return The value assigned to the configuration key.
#
def []=(key, value)
_set(key, value)
end
# @see Hash#keys
#
def keys
self.configuration.send(:table).keys
end
# @see Hash#has_key?
#
def has_key?(key)
self.configuration.send(:table).has_key?(key)
end
# @see Hash#merge
#
def merge(hash)
self.configuration.send(:table).merge(hash)
end
# @see Hash#merge!
#
def merge!(hash)
self.configuration.send(:table).merge!(hash)
end
# Handles method calls for our configuration keys.
#
def method_missing(method_symbol, *method_args)
if method_args.length > 0
_set(method_symbol, method_args.first)
end
_get(method_symbol)
end
private
def _set(key, value)
key = key.to_s
(key =~ /=/) or key += '='
self.configuration.send(key.to_sym, value)
end
def _get(key)
key = key.to_s
(key !~ /=/) or key = key[0..-2]
self.configuration.send(key.to_sym)
end
end
end