<commit_before>require "sensu/settings/validator"
require "multi_json"

module Sensu
  module Settings
    class Loader
      # @!attribute [r] warnings
      #   @return [Array] loader warnings.
      attr_reader :warnings

      # @!attribute [r] loaded_files
      #   @return [Array] loaded config files.
      attr_reader :loaded_files

      def initialize
        @warnings = []
        @settings = {
          :transport => {}
        }
        CATEGORIES.each do |category|
          @settings[category] = {}
        end
        @indifferent_access = false
        @loaded_files = []
        self.class.create_category_methods
      end

      # Create setting category accessors and methods to test the
      # existence of definitions. Called in initialize().
      def self.create_category_methods
        CATEGORIES.each do |category|
          define_method(category) do
            setting_category(category)
          end
          method_name = category.to_s.chop + "_exists?"
          define_method(method_name.to_sym) do |name|
            definition_exists?(category, name)
          end
        end
      end

      # Access settings as an indifferent hash.
      #
      # @return [Hash] settings.
      def to_hash
        unless @indifferent_access
          indifferent_access!
        end
        @settings
      end

      # Retrieve the setting object corresponding to a key, acting
      # like a Hash object.
      #
      # @param key [String, Symbol]
      # @return [Object] value for key.
      def [](key)
        to_hash[key]
      end

      # Load settings from the environment.
      # Loads: RABBITMQ_URL, REDIS_URL, REDISTOGO_URL, API_PORT, PORT
      def load_env
        if ENV["RABBITMQ_URL"]
          @settings[:rabbitmq] = ENV["RABBITMQ_URL"]
          warning("using rabbitmq url environment variable", :rabbitmq => @settings[:rabbitmq])
        end
        ENV["REDIS_URL"] ||= ENV["REDISTOGO_URL"]
        if ENV["REDIS_URL"]
          @settings[:redis] = ENV["REDIS_URL"]
          warning("using redis url environment variable", :redis => @settings[:redis])
        end
        ENV["API_PORT"] ||= ENV["PORT"]
        if ENV["API_PORT"]
          @settings[:api] ||= {}
          @settings[:api][:port] = ENV["API_PORT"].to_i
          warning("using api port environment variable", :api => @settings[:api])
        end
        @indifferent_access = false
      end

      # Load settings from a JSON file.
      #
      # @param [String] file path.
      def load_file(file)
        if File.file?(file) && File.readable?(file)
          begin
            warning("loading config file", :file => file)
            contents = IO.read(file)
            config = MultiJson.load(contents, :symbolize_keys => true)
            merged = deep_merge(@settings, config)
            unless @loaded_files.empty?
              changes = deep_diff(@settings, merged)
              warning("config file applied changes", {
                :file => file,
                :changes => changes
              })
            end
            @settings = merged
            @indifferent_access = false
            @loaded_files << file
          rescue MultiJson::ParseError => error
            warning("config file must be valid json", {
              :file => file,
              :error => error.to_s
            })
            warning("ignoring config file", :file => file)
          end
        else
          warning("config file does not exist or is not readable", :file => file)<commit_msg>[windows-bom] scrub bom and \r from config file contents before parsing<commit_after>require "sensu/settings/validator"
require "multi_json"

module Sensu
  module Settings
    class Loader
      # @!attribute [r] warnings
      #   @return [Array] loader warnings.
      attr_reader :warnings

      # @!attribute [r] loaded_files
      #   @return [Array] loaded config files.
      attr_reader :loaded_files

      def initialize
        @warnings = []
        @settings = {
          :transport => {}
        }
        CATEGORIES.each do |category|
          @settings[category] = {}
        end
        @indifferent_access = false
        @loaded_files = []
        self.class.create_category_methods
      end

      # Create setting category accessors and methods to test the
      # existence of definitions. Called in initialize().
      def self.create_category_methods
        CATEGORIES.each do |category|
          define_method(category) do
            setting_category(category)
          end
          method_name = category.to_s.chop + "_exists?"
          define_method(method_name.to_sym) do |name|
            definition_exists?(category, name)
          end
        end
      end

      # Access settings as an indifferent hash.
      #
      # @return [Hash] settings.
      def to_hash
        unless @indifferent_access
          indifferent_access!
        end
        @settings
      end

      # Retrieve the setting object corresponding to a key, acting
      # like a Hash object.
      #
      # @param key [String, Symbol]
      # @return [Object] value for key.
      def [](key)
        to_hash[key]
      end

      # Load settings from the environment.
      # Loads: RABBITMQ_URL, REDIS_URL, REDISTOGO_URL, API_PORT, PORT
      def load_env
        if ENV["RABBITMQ_URL"]
          @settings[:rabbitmq] = ENV["RABBITMQ_URL"]
          warning("using rabbitmq url environment variable", :rabbitmq => @settings[:rabbitmq])
        end
        ENV["REDIS_URL"] ||= ENV["REDISTOGO_URL"]
        if ENV["REDIS_URL"]
          @settings[:redis] = ENV["REDIS_URL"]
          warning("using redis url environment variable", :redis => @settings[:redis])
        end
        ENV["API_PORT"] ||= ENV["PORT"]
        if ENV["API_PORT"]
          @settings[:api] ||= {}
          @settings[:api][:port] = ENV["API_PORT"].to_i
          warning("using api port environment variable", :api => @settings[:api])
        end
        @indifferent_access = false
      end

      # Load settings from a JSON file.
      #
      # @param [String] file path.
      def load_file(file)
        if File.file?(file) && File.readable?(file)
          begin
            warning("loading config file", :file => file)
            raw_contents = IO.read(file)
            contents = raw_contents.sub("\xEF\xBB\xBF".force_encoding("UTF-8"), "").gsub("\r", "")
            config = MultiJson.load(contents, :symbolize_keys => true)
            merged = deep_merge(@settings, config)
            unless @loaded_files.empty?
              changes = deep_diff(@settings, merged)
              warning("config file applied changes", {
                :file => file,
                :changes => changes
              })
            end
            @settings = merged
            @indifferent_access = false
            @loaded_files << file
          rescue MultiJson::ParseError => error
            warning("config file must be valid json", {
              :file => file,
              :error => error.to_s
            })
            warning("ignoring config file", :file => file)
          end
        else
          warning("config file does not exist or is not readable", :file => file)
{'fraction_non_alphanumeric': 0.10181465576949716, 'fraction_numerical': 0.00013852334118298935, 'mean_word_length': 1.9089443996776794, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6618255', 'n_tokens_mistral': 2007, 'n_tokens_neox': 1963, 'n_words': 532}