lib/ztk/config.rb

Summary

Maintainability
A
0 mins
Test Coverage
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