<commit_before>require 'active_support/core_ext/string/inflections'

class ParamsDeserializer
  def initialize(params)
    @params = params
  end

  def deserialize
    deserialized_params = {}
    self.class.attrs.each do |attr|
      next unless instance_exec(&attr.present_if)
      deserialized_params[attr.name] = self.send(attr.name)
    end
    optionally_include_root_key(format_keys(deserialized_params))
  end

  private

  attr_reader :params

  def params_root
    @params_root ||= case self.class.root_key
                     when nil then params
                     else params[self.class.root_key]
                     end
  end

  def optionally_include_root_key(deserialized_params)
    return deserialized_params unless self.class.include_root_key?
    { to_key_format(self.class.root_key) => deserialized_params }
  end

  def format_keys(hash)
    return hash unless self.class.key_format
    Hash[hash.map { |k, v| [to_key_format(k), v] }]
  end

  def to_key_format(key)
    case self.class.key_format
    when :snake_case then key.to_s.underscore.to_sym
    when :camel_case then key.to_s.camelize.to_sym
    when :lower_camel then key.to_s.camelize(:lower).to_sym
    else key
    end
  end

  class << self
    attr_reader :root_key
    attr_accessor :key_format
    alias_method :format_keys, :key_format=

    def attrs
      @attrs ||= AttributeCollection.new
    end

    def attribute(attr, options = {})
      define_getter_method(attr, options) do
        params_root[attr]
      end
    end

    def attributes(*args)
      args.each do |attr|
        attribute(attr)
      end
    end

    def has_many(attr, options = {})
      define_getter_method(attr, options) do
        return params_root[attr] unless options[:each_deserializer]

        params_root[attr].map do |relation|
          options[:each_deserializer].new(relation).deserialize<commit_msg>Rename to_key_format() to format_key()<commit_after>require 'active_support/core_ext/string/inflections'

class ParamsDeserializer
  def initialize(params)
    @params = params
  end

  def deserialize
    deserialized_params = {}
    self.class.attrs.each do |attr|
      next unless instance_exec(&attr.present_if)
      deserialized_params[attr.name] = self.send(attr.name)
    end
    optionally_include_root_key(format_keys(deserialized_params))
  end

  private

  attr_reader :params

  def params_root
    @params_root ||= case self.class.root_key
                     when nil then params
                     else params[self.class.root_key]
                     end
  end

  def optionally_include_root_key(deserialized_params)
    return deserialized_params unless self.class.include_root_key?
    { format_key(self.class.root_key) => deserialized_params }
  end

  def format_key(key)
    case self.class.key_format
    when :snake_case then key.to_s.underscore.to_sym
    when :camel_case then key.to_s.camelize.to_sym
    when :lower_camel then key.to_s.camelize(:lower).to_sym
    else key
    end
  end

  def format_keys(hash)
    return hash unless self.class.key_format
    Hash[hash.map { |k, v| [format_key(k), v] }]
  end

  class << self
    attr_reader :root_key
    attr_accessor :key_format
    alias_method :format_keys, :key_format=

    def attrs
      @attrs ||= AttributeCollection.new
    end

    def attribute(attr, options = {})
      define_getter_method(attr, options) do
        params_root[attr]
      end
    end

    def attributes(*args)
      args.each do |attr|
        attribute(attr)
      end
    end

    def has_many(attr, options = {})
      define_getter_method(attr, options) do
        return params_root[attr] unless options[:each_deserializer]

        params_root[attr].map do |relation|
          options[:each_deserializer].new(relation).deserialize
{'fraction_non_alphanumeric': 0.08210526315789474, 'fraction_numerical': 0.0, 'mean_word_length': 2.959375, 'pattern_counts': {'":': 0, '<': 7, '<?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': '4708498', 'n_tokens_mistral': 1239, 'n_tokens_neox': 1210, 'n_words': 252}