<commit_before>module ActiveInteraction
  class HashFilter < Filter
    include MethodMissing

    # @param value [Object]
    #
    # @return [Hash{Symbol => Object}]
    #
    # @raise (see Filter#cast)
    def cast(value)
      case value
      when Hash
        filters.reduce({}) do |h, f|
          k = f.name
          h[k] = f.clean(value[k])
          h
        end
      else
        super
      end
    end

    private

    def method_missing(*args, &block)
      super do |klass, names, options|
        raise InvalidFilter.new('no name') if names.empty?

        names.each do |name|
          @filters << klass.new(name, options, &block)
        end
      end
    end
  end
end<commit_msg>Force hash defaults to be either `nil` or `{}`<commit_after>module ActiveInteraction
  class HashFilter < Filter
    include MethodMissing

    # @param value [Object]
    #
    # @return [Hash{Symbol => Object}]
    #
    # @raise (see Filter#cast)
    def cast(value)
      case value
      when Hash
        filters.reduce({}) do |h, f|
          k = f.name
          h[k] = f.clean(value[k])
          h
        end
      else
        super
      end
    end

    def default
      case @options[:default]
      when Hash
        if @options[:default].empty?
          cast({})
        else
          raise InvalidDefault.new(name)
        end
      when NilClass
        cast(nil)
      else
        super
      end
    end

    private

    def method_missing(*args, &block)
      super do |klass, names, options|
        raise InvalidFilter.new('no name') if names.empty?

        names.each do |name|
          @filters << klass.new(name, options, &block)
        end
      end
    end
  end
end
{'fraction_non_alphanumeric': 0.09783245459871119, 'fraction_numerical': 0.0, 'mean_word_length': 1.677115987460815, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 5, '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': '1450958', 'n_tokens_mistral': 515, 'n_tokens_neox': 508, 'n_words': 151}