require 'yaml' module Scide # Complete scide configuration as an object graph. class Config # The file from which the configuration is normally loaded. # This defaults to $HOME/.scide/config.yml. DEFAULT_CONFIG_FILE = File.join File.expand_path('~'), '.scide', 'config.yml' # The file from which this configuration will be loaded. attr_accessor :file # GNU Screen options. Accessible after calling {#load!}. attr_reader :screen # The global configuration. Accessible after calling {#load!}. attr_reader :global # The project definitions (windows, option overrides, etc). Accessible # after calling {#load!}. attr_reader :projects # Returns an empty configuration. # # == Arguments # * file - The file from which to load the configuration. If not # given, this defaults to {DEFAULT_CONFIG_FILE}. def initialize file = nil @file = file.try(:to_s) || DEFAULT_CONFIG_FILE end # Loads this configuration. This will read from {#file} and parse the contents # as YAML. Configuration elements can then be retrieved with #global, # #projects and #screen. # # == Errors # * config_not_found - {#file} does not exist. # * config_not_readable - {#file} cannot be read by the user running scide. # * malformed_config - {#file} contains malformed YAML. # * invalid_config - {#file} contains invalid configuration (see README). # * unexpected - {#file} could not be read. def load! check_config begin raw_config = load_config rescue StandardError => err Scide.fail :unexpected, "ERROR: could not read configuration #{@file}" end begin @config = parse_config raw_config rescue SyntaxError, ArgumentError => err Scide.fail :malformed_config, "ERROR: could not parse configuration #{@file}\n #{err}" end invalid_config 'configuration must be a hash' unless @config.kind_of? Hash # laziness @config = HashWithIndifferentAccess.new @config invalid_config 'screen configuration must be a hash' unless @config[:screen].nil? or @config[:screen].kind_of?(Hash) invalid_config 'projects configuration must be a hash' unless @config[:projects].nil? or @config[:projects].kind_of?(Hash) begin @screen = @config[:screen] || HashWithIndifferentAccess.new @global = Scide::Global.new @config[:global] @projects = (@config[:projects] || {}).inject(HashWithIndifferentAccess.new) do |memo,obj| memo[obj[0]] = Scide::Project.new @global, obj[0], obj[1]; memo end rescue ArgumentError => err invalid_config err end end private # Causes scide to fail with a config_not_found error if the configuration # file does not exist, or with a config_not_readable error if it is not # readable (see {Scide.fail}). def check_config Scide.fail :config_not_found, "ERROR: expected to find configuration at #{@file}" unless File.exists? @file Scide.fail :config_not_readable, "ERROR: configuration #{@file} is not readable" unless File.readable? @file end # Returns the contents of {#file}. def load_config File.open(@file, 'r').read end # Returns the parsed configuration. def parse_config raw YAML::load raw end # Causes scide to fail with an invalid_config error (see {Scide.fail}). # Builds a complete error message containing the full path to the # configuration file and the given message. def invalid_config msg Scide.fail :invalid_config, "ERROR: configuration #{@file} is invalid.\n #{msg}" end end end