<commit_before>class GitStore

  class Tree
    include Enumerable

    attr_reader :store, :table
    attr_accessor :id, :data, :mode

    # Initialize a tree
    def initialize(store, id = nil, data = nil)
      @store = store
      @id = id
      @table = {}
      @mode = "040000"
      parse(data) if data
    end

    def ==(other)
      Tree === other and id == other.id
    end

    # Has this tree been modified?
    def modified?
      @modified or @table.values.any? { |entry| Tree === entry and entry.modified? }
    end

    # Find or create a subtree with specified name.
    def tree(name)
      get(name) or put(name, Tree.new(store))
    end

    # Read the contents of a raw git object.
    def parse(data)
      @table.clear

      while data.size > 0
        mode, data = data.split(" ", 2)
        name, data = data.split("\0", 2)
        id = data.slice!(0, 20).unpack("H*").first

        @table[name] = store.get(id)
      end
    end

    def dump
      @table.map { |k, v| "#{ v.mode } #{ k }\0#{ [v.write].pack("H*") }" }.join
    end

    # Write this treetree back to the git repository.
    #
    # Returns the object id of the tree.
    def write
      return id if not modified?
      @modified = false
      @id = store.put(self)
    end

    # Read entry with specified name.
    def get(name)
      entry = @table[name]

      case entry
      when Blob
        entry.object ||= handler_for(name).read(entry.data)

      when Tree
        entry
      end
    end

    def handler_for(name)
      store.handler_for(name)
    end

    # Write entry with specified name.
    def put(name, value)
      @modified = true

      if value.is_a?(Tree)
        @table[name] = value
      else
        @table[name] = Blob.new(store, nil, handler_for(name).write(value))
      end

      value
    end
<commit_msg>Mark tree modified only if data differs from previous value.<commit_after>class GitStore

  class Tree
    include Enumerable

    attr_reader :store, :table
    attr_accessor :id, :data, :mode

    # Initialize a tree
    def initialize(store, id = nil, data = nil)
      @store = store
      @id = id
      @table = {}
      @mode = "040000"
      parse(data) if data
    end

    def ==(other)
      Tree === other and id == other.id
    end

    # Has this tree been modified?
    def modified?
      @modified or @table.values.any? { |entry| Tree === entry and entry.modified? }
    end

    # Find or create a subtree with specified name.
    def tree(name)
      get(name) or put(name, Tree.new(store))
    end

    # Read the contents of a raw git object.
    def parse(data)
      @table.clear

      while data.size > 0
        mode, data = data.split(" ", 2)
        name, data = data.split("\0", 2)
        id = data.slice!(0, 20).unpack("H*").first

        @table[name] = store.get(id)
      end
    end

    def dump
      @table.map { |k, v| "#{ v.mode } #{ k }\0#{ [v.write].pack("H*") }" }.join
    end

    # Write this treetree back to the git repository.
    #
    # Returns the object id of the tree.
    def write
      return id if not modified?
      @modified = false
      @id = store.put(self)
    end

    # Read entry with specified name.
    def get(name)
      entry = @table[name]

      case entry
      when Blob
        entry.object ||= handler_for(name).read(entry.data)

      when Tree
        entry
      end
    end

    def handler_for(name)
      store.handler_for(name)
    end

    # Write entry with specified name.
    def put(name, value)
      if value.is_a?(Tree)
        @modified = true
        @table[name] = value
      else
        data = handler_for(name).write(value)
        if data != @table[name].data
          @modified = true
          @table[name] = Blob.new(store, nil, data)
        end
      end

      value
    end

{'fraction_non_alphanumeric': 0.1130298273155416, 'fraction_numerical': 0.007326007326007326, 'mean_word_length': 1.9138719512195121, 'pattern_counts': {'":': 0, '<': 3, '<?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': '620547', 'n_tokens_mistral': 1256, 'n_tokens_neox': 1203, 'n_words': 387}