lib/usmu/configuration.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'yaml'
require 'usmu/metadata_service'
require 'usmu/helpers/indexer'

module Usmu
  # This class is used to represent a configuration file. This file should be a YAML file and called `usmu.yml`
  # by default.
  class Configuration
    include Usmu::Helpers::Indexer

    @log = Logging.logger[self]

    indexer :@config

    # @!attribute [r] config_file
    # @return [String] the name of the file used to load the configuration.
    attr_reader :config_file
    # @!attribute [r] config_dir
    # @return [String] the folder that the configuration was loaded from.
    attr_reader :config_dir

    # Load a configuration from a YAML file on disk.
    #
    # @return [Usmu::Configuration]
    def self.from_file(filename)
      raise ArgumentError, "File not found: #{filename}" if filename.nil? || (not File.exist? filename)
      @log.debug("Loading configuration from #{filename}")
      new(YAML.load_file(filename), filename)
    end

    # Load a configuration from a hash.
    #
    # @return [Usmu::Configuration]
    def self.from_hash(hash, config_path = nil)
      new(hash, config_path)
    end

    # @!attribute [r] source_path
    # @return [String] the full path to the source folder
    def source_path
      get_path self['source'] || 'src'
    end

    # @!attribute [r] source_files
    # @return [Array<String>] a list of renderable files in the source folder
    def source_files
      get_files source_path
    end

    # @!attribute [r] source_metadata
    # @return [MetadataService] a metadata service for retrieving metadata about pages in #source_path
    def source_metadata
      @source_metadata ||= MetadataService.new(source_path)
    end

    # @!attribute [r] destination_path
    # @return [String] the full path to the destination folder
    def destination_path
      get_path self['destination'] || 'site'
    end

    # @!attribute [r] layouts_path
    # @return [String] the full path to the layouts folder
    def layouts_path
      get_path self['layouts'] || 'layouts'
    end

    # @!attribute [r] layouts_files
    # @return [Array<String>] a list of renderable files in the layouts folder
    def layouts_files
      get_files layouts_path
    end

    def layouts_metadata
      @layouts_metadata ||= MetadataService.new(layouts_path)
    end

    # @!attribute [r] layouts_path
    # @return [String] the full path to the layouts folder
    def includes_path
      get_path self['includes'] || 'includes'
    end

    # @!attribute [r] layouts_files
    # @return [Array<String>] a list of renderable files in the layouts folder
    def includes_files
      get_files includes_path
    end

    # @!attribute [r] includes_metadata
    # @return [MetadataService] a metadata service for retrieving metadata about includes
    def includes_metadata
      @includes_metadata ||= MetadataService.new(includes_path)
    end

    # Returns an array of exclusions
    #
    # @return [Array]
    def exclude
      self['exclude'] || []
    end

    # @return [Usmu::SiteGenerator]
    def generator
      SiteGenerator.new(self)
    end

    private

    attr_reader :log
    attr_reader :config

    # This class has a private constructor.
    #
    # @see Usmu::Configuration.from_file
    # @see Usmu::Configuration.from_hash
    def initialize(hash, config_path)
      @log = Logging.logger[self]
      @config = hash
      @config_file = config_path
      @config_dir = if config_path
                      File.dirname(config_path)
                    end
    end

    # Helper function to transform a relative path in the configuration file to a relative path from the current
    # working directory.
    #
    # @return [String]
    def get_path(path)
      if @config_dir.nil?
        path
      else
        File.join(@config_dir, path)
      end
    end

    # Helper to determine if a filename is excluded according to the exclude configuration parameter.
    #
    # @return [Boolean]
    def excluded?(filename)
      exclude.each do |f|
        f += '**/*' if f.end_with? '/'
        return true if File.fnmatch(f, filename, File::FNM_EXTGLOB | File::FNM_PATHNAME)
      end
      false
    end

    # Helper function to search a directory recursively and return a list of files that are renderable.
    #
    # @param [String] directory the directory to search
    # @return [Array<Usmu::Layout>, Array<Usmu::StaticFile>] Either an array of Layouts or StaticFiles in the directory
    def get_files(directory)
      Dir["#{directory}/**/{*,.??*}"].
          select {|f| not File.directory? f }.
          select {|f| !f.match(/[\.\/]meta\.yml$/) }.
          map {|f| f[directory.length + 1, f.length] }.
          select {|f| not excluded? f }
    end
  end
end