Adding an item to a hierarchical data structure
Rubocop Report

Rubocop was able to correct a lot of style and layout offenses. 1 file inspected, 59 offenses detected, 53 offenses corrected.

The following offenses remain:


Metrics/LineLength: Line is too long. [112/80]
Metrics/AbcSize: Assignment Branch Condition size for update is too high. [24.1/15]
Style/MultipleComparison: Avoid comparing a variable with multiple items in a conditional, use Array#include? instead.
Metrics/LineLength: Line is too long. [99/80]
Style/NumericPredicate: Use range.index(target).zero? instead of range.index(target) == 0.
Metrics/LineLength: Line is too long. [85/80]


Fixing Offenses

LineLength and MultipleComparison offense:


# optimization for this:
id,range = old_state.to_a.select{ |entry| entry[1][0] == target || entry[1][1] == target }[0]



id, range = old_state.to_a.select do |entry|
  [entry[1][0], entry[1][1]].include?(target)[0]
end


LineLength + NumericPredicate offense:


state[id] = 
   range.index(target) == 0 ? range.map{|n| n + 2} : [range[0], range[1] + 2]



  state[id] =
    if range.index(target).zero?
      range.map { |n| n + 2 }
    else
      [range[0], range[1] + 2]


After refactoring, we get a new issue that our method got too big. The complexity is still too high.


Metrics/AbcSize: Assignment Branch Condition size for update is too high. [25.06/15]
Metrics/MethodLength: Method has too many lines. [15/10]


We are adviced to break up this method. It's doing a bit too much. So we'll put the next part in another method.


   state[id] =
      if range.index(target).zero?
        range.map { |n| n + 2 }
      else
        [range[0], range[1] + 2]
      end
    2.times do |i|
      update(old_state, state, range[i] + 1) if range[i] != state[id][i]
    end



  def update_range(old_state, state, target, id, range)
    state[id] =
      if range.index(target).zero?
        range.map { |n| n + 2 }
      else
        [range[0], range[1] + 2]
      end
    2.times do |i|
      update(old_state, state, range[i] + 1) if range[i] != state[id][i]
    end
  end


There are no offenses remaining and complexity is within bounds.

Refactored Code

# frozen_string_literal: true

# Nested set for comments, for making it easy to load all comments in a
# list, sorted according to their nesting, and for nesting to be indicated.
class Database
  def initialize
    @set = {}
    @largest = -1
  end

  def fetch
    @set.to_a.sort { |el1, el2| el1[1][0] &lt;=&gt; el2[1][0] }
  end

  def add(parent: nil, id: -1)
    if parent

      @set.merge!(
        update(@set, insert(parent, id), @set[parent][1] + 1)
      )
    else
      @set[id] = [@largest + 1, @largest + 2]
    end
    @largest += 2
    @set
  end

   private

  def insert(parent_id, id)
    parent_range = @set[parent_id]
    {
      parent_id =&gt; [parent_range[0], parent_range[1] + 2],
      id =&gt; [parent_range[1], parent_range[1] + 1]
    }
  end

  # O(n) * 2^n
  def update(old_state, state, target)
    id, range = old_state.to_a.select do |entry|
      [entry[1][0], entry[1][1]].include?(target)[0]
    end
    update_range(old_state, state, target, id, range) if range &amp;&amp; !state[id]
    state
  end

  def update_range(old_state, state, target, id, range)
    state[id] =
      if range.index(target).zero?
        range.map { |n| n + 2 }
      else
        [range[0], range[1] + 2]
      end
    2.times do |i|
      update(old_state, state, range[i] + 1) if range[i] != state[id][i]
    end
  end
 end