# encoding: utf-8 require 'fedux_org_stdlib/require_files' require 'fedux_org_stdlib/file_finder/exceptions' require 'fedux_org_stdlib/logging/logger' require_library %w(json active_support/core_ext/string/inflections set active_support/core_ext/hash/slice active_support/core_ext/object/blank active_support/core_ext/hash/keys) module FeduxOrgStdlib # This class detects the file name for an config file. By default it will # look for a suitable config file in the given order: # # 1. $HOME/.config//.yaml # 2. $HOME/./.yaml # 2. $HOME/..yaml # 2. $HOME/.rc # 3. /etc/./.yaml # # Please keep in mind # # * application_name: Module of your class, e.g. "MyApplication" becomes # "my_application" # * config_file: Pluarized name of your class and "File" strip # off, e.g "ClientFile" becomes "client.yaml" # # Most conventions defined by me are implemented as separate methods. If one convention # is not suitable for your use case, just overwrite the method. # # If you prefer to use a different path to the config file or name of the # config file one of the following methods needs to be overwritten: # # * config_file # * config_name # * application_name # # If you want the class to look for your config file at a different place # overwrite the following method # # * allowed_config_file_paths # # Below you find some examples for the usage of the class: # # @example Create config with one writer and reader # module MyApplication # class ClientFile < FileFinder # end # end class FileFinder # Create a new instance of config # # It tries to find a suitable configuration file. If it doesn't find one # the config is empty and uses the defaults defined within a config class # # @param [String] file # Path where config file is stored. The file will be read by the # `config_engine`. # # @raise [Exceptions::FileFinderNotReadable] # If an avaiable config file could not be read by the config engine # # @return [FileFinder] # The config instance. If the resulting data structure created by the # config_engine does not respond to `:[]` an empty config object will be # created. attr_reader :file, :logger, :working_directory def initialize( file: nil, working_directory: Dir.getwd, logger: FeduxOrgStdlib::Logging::Logger.new ) @logger = logger @working_directory = working_directory @file ||= (file || _available_config_file) logger.debug "No configuration file found at #{_allowed_config_file_paths.to_list}, therefor I'm going to use an empty config object instead." unless file end # Return the path to the preferred configuration file # @return [String] # The path to the preferred configuration file def preferred_configuration_file _allowed_config_file_paths.first end private # The name of the config file # # @return [String] # The name of the config file. It defaults to `.yaml`. If # you want to use a different file name you need to overwrite this # method. def _config_file "#{_config_name}#{_config_file_suffix}" end # The suffix of the config file # # @return [String] # The suffix of the config file def _config_file_suffix '.yaml' end # The base name of the config # # @return [String] # This one returns the base name of the config file (without the file # extension). It uses the class name of the config class # # @example Determine the base name of the config # # class ClientFile; end # # This will result in `client` as base name for the config file. def _config_name unless (name = _class_name.sub(/File/, '').underscore).blank? return name end fail Exceptions::ClassNameIsMissing, JSON.dump(klass: _class_name) end # The name of your application # # @return [String] # This will strip of the class part of fully qualified class name and # converted it to a path. # # @example Determine application name # # class MyApplication::MyFile; end # # This will be converted to # # my_application def _application_name _module_name.underscore end # The paths where to look for the config file # # @return [Array] # A list of paths where the config object should look for its config # file. def _allowed_config_file_paths [ ::File.expand_path(::File.join('~', '.config', _application_name, _config_file)), ::File.expand_path(::File.join('~', format('.%s', _application_name), _config_file)), ::File.expand_path(::File.join('~', format('.%s', _config_file))), ::File.expand_path(::File.join('~', format('.%src', _config_name))), ::File.expand_path(::File.join('/etc', _application_name, _config_file)), ::File.expand_path(::File.join(working_directory, _config_file)) ] end def _class_name self.class.name.to_s.demodulize end def _module_name self.class.to_s.deconstantize end def _available_config_file _allowed_config_file_paths.find { |f| ::File.exist? f } end end end