3scale/config_for

View on GitHub
lib/config_for/config.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'erb'
require 'yaml'
require 'forwardable'
require 'monitor'
require 'pathname'

require 'active_support/hash_with_indifferent_access'
# HashWithIndifferentAccess needs this core extension to be loaded
require 'active_support/core_ext/hash/indifferent_access'

module ConfigFor
  # @api private
  class Config
    extend Forwardable

    CONFIG_CLASS = ActiveSupport::HashWithIndifferentAccess

    def initialize(path, name)
      @path = path
      @name = name
      @monitor = Monitor.new
      @pathname = Pathname("#{name}.yml").expand_path(path)
    end

    def self.empty
      CONFIG_CLASS.new
    end

    def environments
      config.keys
    end

    def fetch(key, &block)
      config.fetch(key, &block)
    rescue KeyError
      raise ConfigFor::MissingEnvironmentError, "#{@pathname} contains just #{environments}, not #{key}"
    end

    private

    def config
      @monitor.synchronize do
        if instance_variable_defined?(:@config)
          @config
        else
          @config = convert(parse)
        end
      end
    end

    def convert(hash)
      CONFIG_CLASS.new(hash)
    end

    def read
      @pathname.read
    rescue => error
      raise ConfigFor::ReadError, error.message
    end

    def parse
      content = read
      erb = ::ERB.new(content)
      erb.filename = @pathname.to_s
      ::YAML.load(erb.result, @pathname)
    rescue ::Psych::SyntaxError => e
      fail ConfigFor::InvalidConfigError, "YAML syntax error occurred while parsing #{content}. Error: #{e.message}"
    end
  end
end