<commit_before>module ReportsKit
  module Reports
    class Measure
      attr_accessor :properties, :filters, :context_record

      def initialize(properties, context_record: nil)
        properties = { key: properties } if properties.is_a?(String)
        raise ArgumentError.new("Measure properties must be a String or Hash, not a #{properties.class.name}: #{properties.inspect}") unless properties.is_a?(Hash)
        properties = properties.deep_symbolize_keys
        filter_hashes = properties.delete(:filters) || []
        filter_hashes = filter_hashes.values if filter_hashes.is_a?(Hash) && filter_hashes.key?(:'0')

        self.properties = properties
        self.filters = filter_hashes.map { |filter_hash| Filter.new(filter_hash, measure: self) }
        self.context_record = context_record
      end

      def key
        properties[:key]
      end

      def label
        key.pluralize.titleize
      end

      def aggregate_function
        :count
      end

      def conditions
        nil
      end

      def base_relation
        return context_record.public_send(key.pluralize) if context_record
        model_class
      end

      def model_class
        key.camelize.constantize
      end

      def filtered_relation
        relation = base_relation
        filters.each do |filter|
          relation = filter.apply(relation)
        end
        relation
      end

      def properties_with_filters
        all_properties = properties
        all_properties[:filters] = filters.map(&:properties)
        all_properties
      end
    end
  end
end<commit_msg>Improve normalization of measure keys<commit_after>module ReportsKit
  module Reports
    class Measure
      attr_accessor :properties, :filters, :context_record

      def initialize(properties, context_record: nil)
        properties = { key: properties } if properties.is_a?(String)
        raise ArgumentError.new("Measure properties must be a String or Hash, not a #{properties.class.name}: #{properties.inspect}") unless properties.is_a?(Hash)
        properties = properties.deep_symbolize_keys
        filter_hashes = properties.delete(:filters) || []
        filter_hashes = filter_hashes.values if filter_hashes.is_a?(Hash) && filter_hashes.key?(:'0')

        self.properties = properties
        self.filters = filter_hashes.map { |filter_hash| Filter.new(filter_hash, measure: self) }
        self.context_record = context_record
      end

      def key
        properties[:key].underscore
      end

      def label
        key.pluralize.titleize
      end

      def relation_name
        key.tableize
      end

      def aggregate_function
        :count
      end

      def conditions
        nil
      end

      def base_relation
        return context_record.public_send(relation_name) if context_record
        model_class
      end

      def model_class
        key.camelize.constantize
      end

      def filtered_relation
        relation = base_relation
        filters.each do |filter|
          relation = filter.apply(relation)
        end
        relation
      end

      def properties_with_filters
        all_properties = properties
        all_properties[:filters] = filters.map(&:properties)
        all_properties
      end
    end
  end
end
{'fraction_non_alphanumeric': 0.068660360085444, 'fraction_numerical': 0.0006103143118706134, 'mean_word_length': 2.3828689370485034, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '1061024', 'n_tokens_mistral': 887, 'n_tokens_neox': 864, 'n_words': 217}