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!
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
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
# 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