<commit_before>require 'data_rail/object_hasher'

module DataRail
  module Operation

    class UpdateRecord

      def initialize(active_record, options = {})
        @active_record = active_record
        @logger = options.fetch(:logger) { Logger.new(nil) }

        @fields = options[:fields] || {}
        @fields[:key] ||= ObjectHasher.new
      end

      def call(object)
        record = corresponding_record(object)
        attributes = attributes_for_object(object)
        assign_supported_attributes(record, attributes)

        record
      end

      private

      def attributes_for_object(object)
        object.attributes.merge(fields).merge fields_for_object(object)
      end

      def fields_for_object(object)
        Hash[ fields.map{ |k, v| [ k, v.respond_to?(:call) ? v.call(object) : v ] } ]
      end

      def assign_supported_attributes(record, attributes)
        attributes.each do |name, value|
          attr_writer = "#{name}="
          record.public_send(attr_writer, value) if record.respond_to?(attr_writer)
        end
      end

      def corresponding_record(object)
        active_record.where(key: key_for_object(object)).first_or_initialize
      end

      def key_for_object(object)
        fields[:key].call(object)
      end

      attr_reader :active_record, :fields, :logger

    end

  end
end<commit_msg>set default hash to be the identity (just fetch key)<commit_after>require 'data_rail/object_hasher'

module DataRail
  module Operation

    class UpdateRecord

      def initialize(active_record, options = {})
        @active_record = active_record
        @logger = options.fetch(:logger) { Logger.new(nil) }

        @fields = options[:fields] || {}
        @fields[:key] ||= lambda { |o| o.key }
      end

      def call(object)
        record = corresponding_record(object)
        attributes = attributes_for_object(object)
        assign_supported_attributes(record, attributes)

        record
      end

      private

      def attributes_for_object(object)
        object.attributes.merge(fields).merge fields_for_object(object)
      end

      def fields_for_object(object)
        Hash[ fields.map{ |k, v| [ k, v.respond_to?(:call) ? v.call(object) : v ] } ]
      end

      def assign_supported_attributes(record, attributes)
        attributes.each do |name, value|
          attr_writer = "#{name}="
          record.public_send(attr_writer, value) if record.respond_to?(attr_writer)
        end
      end

      def corresponding_record(object)
        active_record.where(key: key_for_object(object)).first_or_initialize
      end

      def key_for_object(object)
        fields[:key].call(object)
      end

      attr_reader :active_record, :fields, :logger

    end

  end
end
{'fraction_non_alphanumeric': 0.09568684305907937, 'fraction_numerical': 0.0, 'mean_word_length': 2.68, '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': '6122021', 'n_tokens_mistral': 816, 'n_tokens_neox': 786, 'n_words': 168}