require 'yaml' require 'facet/object/constant' require 'glue/attribute' require 'glue/hash' require 'glue/flexob' # A Configuration holds a group of Settings organized by # Owners. #-- # TODO: implement with annotations. #++ class Configuration # A hash of setting owners. Use double @'s to allow for # the Settings alias. #-- # TODO: find a better name. #++ @@owners = Glue::SafeHash.new # A datastructure to store Settings metadata. class Setting attr_accessor :owner, :name, :type, :value, :options def initialize(owner, name, options) raise ArgumentError.new('A default value is required') unless options.key?(:default) @owner, @name = owner, name @options = options @value = options[:default] @type = options[:type] = options[:type] || @value.class end def value=(value) @value = value constant(@owner).module_eval %{ @@#{@name} = #{value.inspect} } end def to_s @value.to_s end end class << self def setup(options) options.each do |owner, ss| owner = constant(owner) ss.each do |name, s| @@owners[owner][name.to_sym].value = s owner.module_eval %{ @@#{name} = #{s.inspect} } end end end def parse(options) temp = YAML::load(options) options = {} temp.each { |k, v| options[constant(k.gsub(/\./, '::').to_sym)] = v } setup(options) end def load(filename) parse(File.read(filename)) end def add_setting(owner, name, options) s = @@owners[owner] || {} s[name] = Setting.new(owner, name, options) @@owners[owner] = s end def settings(owner = nil) if owner @@owners[owner] else @@owners.values.inject([]) { |memo, obj| memo.concat(obj.values) } end end alias_method :all, :settings alias_method :[], :settings def method_missing(sym) if sym.to_s =~ /[A-Z]/ # facet's capitalized? is buggy at the moment. Flexob.new(self[constant(sym)]) end end end end # Alias for the Configuration class (shorter). class Settings < Configuration end class Module # Defines a configuration setting. #-- # TODO: implement with annotations. #++ def setting(sym, options = {}) Configuration.add_setting(self, sym, options) module_eval %{ mattr_accessor sym, options[:default] def self.#{sym.id2name}=(obj) @@#{sym.id2name} = obj Configuration[#{self}][:#{sym}].value = obj end } end end # * George Moschovitis