Al-un/ougai-formatters-customizable

View on GitHub
lib/ougai/formatters/colors/configuration.rb

Summary

Maintainability
A
25 mins
Test Coverage
# frozen_string_literal: true

require 'ougai/formatters/colors'

module Ougai
  module Formatters
    module Colors
      # Handle the colorization of output, mainly aimed at console formatting.
      # The configuration,split by subject such as +level+, +msg+,
      # or +datetime+ is basically a Hash: +config+ with the subject as key
      # and values. Values can be have three types:
      #
      # - +String+: the color escape sequence for the subject
      # - +Hash+: the color escape sequence per severity. If not all severities
      #   are defined, a +:default+ value must be defined
      # - +Symbol+: refers to another key and same coloring is applied
      class Configuration
        class << self
          # list default color configuration
          # @note 'any' severity label decided in 
          #       +Ougai::Logging::Severity#to_label+
          # @note values are copied from +Ougai::Formatters::Readable+ coloring
          #       values
          # @return [Hash] default color configuration is severities only
          def default_configuration
            {
              severity: {
                trace:  Ougai::Formatters::Colors::BLUE,
                debug:  Ougai::Formatters::Colors::WHITE,
                info:   Ougai::Formatters::Colors::CYAN,
                warn:   Ougai::Formatters::Colors::YELLOW,
                error:  Ougai::Formatters::Colors::RED,
                fatal:  Ougai::Formatters::Colors::PURPLE,
                any:    Ougai::Formatters::Colors::GREEN
              }
            }
          end
        end

        # Configuration accept following keys:
        # - +:load_default_config+ If true, then default configuration
        #   values is fetched to fill missing value from the provided 
        #   configuration. Default is true.
        # - any remaining key is considered to be color-related and is translated
        #   into a *subject => color rule* mapping
        #
        # @param [Hash] configuration color configuration. Cannot be nil
        def initialize(configuration = {})
          # check if loading or not from default configuration
          if configuration.fetch(:load_default_config) { true }
            @config = Configuration.default_configuration
          else
            @config = {}
          end

          configuration.each do |key, val|
            default_val = @config[key]
            # default value is a Hash AND input value is a Hash => merge
            if val.is_a?(Hash) && default_val.is_a?(Hash)
              @config[key] = default_val.merge(val)
            # Input value is assigned because one of the follow
            # 1) input value is not defined in default configuration
            # 2) input value is not a Hash which overrides the default value
            # 3) default value is not a Hash and input is a Hash => Arbitrary
            else
              @config[key] = val
            end
          end
        end

        # Convenience method to color a subject for a given log severity
        #
        # @param [Symbol] subject_key to fetch the color to color the text
        # @param [String] text to be colored text
        # @param [Symbol] severity log level
        #
        # @return [String] a colored text depending on the subject
        def color(subject_key, text, severity)
          color = get_color_for(subject_key, severity)
          Ougai::Formatters::Colors.color_text(color, text)
        end

        # Return the color for a given suject and a given severity. This color
        # can then be applied to any text via
        # +Ougai::Formatters::Colors.color_text+
        #
        # +get_color_for+ handles color inheritance: if a subject inherit color
        # from another subject, subject value is the symbol refering to the
        # other subject.
        #
        # @note !!WARNING!!: Circular references are not checked and lead to infinite
        # loop  
        #
        # @param [Symbol] subject_key to define the color to color the text
        # @param [Symbol] severity log level
        #
        # @return [String,nil] requested color String value or +nil+ if not colored
        def get_color_for(subject_key, severity)
          # no colorization
          return nil unless @config.key?(subject_key)

          # no severity dependence nor inheritance
          color = @config[subject_key]
          return color if color.is_a? String

          # inheritance from another subject
          return get_color_for(color, severity) if color.is_a? Symbol

          # severity dependent but not inherited value or return +nil+ if
          # configuration is incorrect
          severity = severity.downcase.to_sym
          color.fetch(severity) { color[:default] }
        end

      end

    end
  end
end