<commit_before>module Eternity
  class Commit

    attr_reader :id

    def initialize(id)
      @id = id
    end

    def time
      Time.parse(data['time']) if data['time']
    end

    def author
      data['author']
    end

    def message
      data['message']
    end

    def parent_ids
      data['parents'] || [nil]
    end

    def parents
      parent_ids.map { |id| Commit.new id }
    end

    def with_index
      index = data['index'] ? Index.read_blob(data['index']) : Index.new
      yield index
    ensure
      index.destroy if index
    end

    def delta
      data['delta'] ? Blob.read(:delta, data['delta']) : {}
    end

    def base
      Commit.new data['base']
    end

    def base_delta
      data['base_delta'] ? Blob.read(:delta, data['base_delta']) : {}
    end

    def fast_forward?(commit)
      return commit.id.nil? if first?
      parent_ids.any? { |id| id == commit.id } || parents.map { |c| c.fast_forward?(commit) }.inject(:|)
    end

    def base_history_at(commit)
      return [] unless commit
      history = [base]
      history += base.base_history_at commit unless base.id == commit.id
      raise "History not include commit #{commit.id}" unless history.map(&:id).include? commit.id
      history
    end

    def first?
      parent_ids.compact.empty?
    end

    def self.create(options)
      data = {
        time:       Time.now,
        author:     options.fetch(:author),
        message:    options.fetch(:message),
        parents:    options.fetch(:parents),
        index:      options.fetch(:index),
        delta:      options.fetch(:delta),
        base:       options[:parents].count == 2 ? options.fetch(:base) : options[:parents].first,
        base_delta: options[:parents].count == 2 ? options.fetch(:base_delta) : options.fetch(:delta)
      }

      new Blob.write(:commit, data)
    end<commit_msg>Validate presence of author and message<commit_after>module Eternity
  class Commit

    attr_reader :id

    def initialize(id)
      @id = id
    end

    def time
      Time.parse(data['time']) if data['time']
    end

    def author
      data['author']
    end

    def message
      data['message']
    end

    def parent_ids
      data['parents'] || [nil]
    end

    def parents
      parent_ids.map { |id| Commit.new id }
    end

    def with_index
      index = data['index'] ? Index.read_blob(data['index']) : Index.new
      yield index
    ensure
      index.destroy if index
    end

    def delta
      data['delta'] ? Blob.read(:delta, data['delta']) : {}
    end

    def base
      Commit.new data['base']
    end

    def base_delta
      data['base_delta'] ? Blob.read(:delta, data['base_delta']) : {}
    end

    def fast_forward?(commit)
      return commit.id.nil? if first?
      parent_ids.any? { |id| id == commit.id } || parents.map { |c| c.fast_forward?(commit) }.inject(:|)
    end

    def base_history_at(commit)
      return [] unless commit
      history = [base]
      history += base.base_history_at commit unless base.id == commit.id
      raise "History not include commit #{commit.id}" unless history.map(&:id).include? commit.id
      history
    end

    def first?
      parent_ids.compact.empty?
    end

    def self.create(options)
      data = {
        time:       Time.now,
        author:     options.fetch(:author),
        message:    options.fetch(:message),
        parents:    options.fetch(:parents),
        index:      options.fetch(:index),
        delta:      options.fetch(:delta),
        base:       options[:parents].count == 2 ? options.fetch(:base) : options[:parents].first,
        base_delta: options[:parents].count == 2 ? options.fetch(:base_delta) : options.fetch(:delta)
      }

      raise 'Author must be present' if data[:author].strip.empty?
      raise 'Message must be present' if data[:message].strip.empty?

      new Blob.write(:commit, data)
    end
{'fraction_non_alphanumeric': 0.12643972357307398, 'fraction_numerical': 0.0010238034297414896, 'mean_word_length': 2.264828738512949, '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': '1512949', 'n_tokens_mistral': 1201, 'n_tokens_neox': 1168, 'n_words': 296}