lib/madvertise/ext/config.rb in madvertise-ext-0.2.2 vs lib/madvertise/ext/config.rb in madvertise-ext-0.3.0

- old
+ new

@@ -1,7 +1,10 @@ require 'yaml' +require 'set' + require 'madvertise/ext/hash' +require 'madvertise/ext/environment' ## # A {Configuration} consists of one or more Sections. A section is a hash-like # object that responds to all keys in the hash as if they were methods: # @@ -10,18 +13,28 @@ # => 2 # > s.nested.v2 # => 1 # class Section < Hash + class << self + # How to handle nil values in the configuration? + # + # Possible values are: + # - :nil, nil (return nil) + # - :raise (raise an exception) + # - :section (return a NilSection which can be chained) + # + attr_accessor :nil_action + # Create a new section from the given hash-like object. # # @param [Hash] hsh The hash to convert into a section. # @return [Section] The new {Section} object. def from_hash(hsh) - result = new.tap do |result| + new.tap do |result| hsh.each do |key, value| result[key.to_sym] = from_value(value) end end end @@ -40,32 +53,11 @@ end else value end end - end - # Mixin a configuration snippet into the current section. - # - # @param [Hash, String] value A hash to merge into the current - # configuration. If a string is given a filename - # is assumed and the given file is expected to - # contain a YAML hash. - # @return [void] - def mixin(value) - unless value.is_a?(Hash) - value = Section.from_hash(YAML.load(File.read(value))) - end - - self.deep_merge!(value[:default]) if value.has_key?(:default) - self.deep_merge!(value[:generic]) if value.has_key?(:generic) - - if value.has_key?(@mode) - self.deep_merge!(value[@mode]) - else - self.deep_merge!(value) - end end # Build the call chain including NilSections. # # @private @@ -73,11 +65,24 @@ if name.to_s =~ /(.*)=$/ self[$1.to_sym] = Section.from_value(args.first) else value = self[name] value = value.call if value.is_a?(Proc) - value = NilSection.new if value.nil? + + if value.nil? + case self.class.nil_action + when :nil, nil + # do nothing + when :raise + raise "value is nil for key #{name}" + when :section + value = NilSection.new if value.nil? + else + raise "unknown nil handling: #{self.class.nil_action}" + end + end + self[name] = value end end end @@ -90,12 +95,13 @@ # Create a new {Configuration} object. # # @param [Symbol] mode The mode to load from the configurtion file # (production, development, etc) # @yield [config] The new configuration object. - def initialize(mode = :development) - @mode = mode + def initialize + @mixins = Set.new + @callbacks = [] yield self if block_given? end # Load given mixins from +path+. # @@ -108,28 +114,55 @@ end.each do |mixin_file| mixin(mixin_file) end end - ## - # The {Helpers} module can be included in all classes that wish to load - # configuration file(s). In order to load custom configuration files the - # including class needs to set the +@config_file+ instance variable. + # Mixin a configuration snippet into the current section. # - module Helpers + # @param [Hash, String] value A hash to merge into the current + # configuration. If a string is given a filename + # is assumed and the given file is expected to + # contain a YAML hash. + # @return [void] + def mixin(value) + if value.is_a?(String) + @mixins << value + value = YAML.load(File.read(value)) + end - # Load the configuration. The default configuration is located at - # +lib/ganymed/config.yml+ inside the Ganymed source tree. - # - # @return [Configuration] The configuration object. See madvertise-ext gem - # for details. - def config - @config ||= Configuration.new(Env.mode) do |config| - config.mixin(@default_config_file) if @default_config_file - config.mixin(@config_file) if @config_file - end + value = Section.from_hash(value) + + self.deep_merge!(value[:default]) if value.has_key?(:default) + self.deep_merge!(value[:generic]) if value.has_key?(:generic) + + if value.has_key?(Env.to_sym) + self.deep_merge!(value[Env.to_sym]) + else + self.deep_merge!(value) end + + @callbacks.each do |callback| + callback.call + end end + + # Reload all mixins. + # + # @return [void] + def reload! + self.clear + @mixins.each do |file| + self.mixin(file) + end + end + + # Register a callback for config mixins. + # + # @return [void] + def callback(&block) + @callbacks << block + end + end ## # A NilSection is returned for all missing/empty values in the config file. This # allows for terse code when accessing values that have not been configured by