def trace(path_segments, enum, resolved_path = [], nesting_level = 0)
      Enumpath.logger.level = nesting_level
      if path_segments.any?
        Enumpath.log('Applying') { { operator: path_segments, to: enum } }
        apply_segments(path_segments, enum, resolved_path, nesting_level)
      else
        Enumpath.log('Storing') { { resolved_path: resolved_path, enum: enum } }
        results.store(resolved_path, enum)
      end
      Enumpath.logger.level = nesting_level
    end
def trace(path_segments, enum, resolved_path = [], nesting_level = 0)
      Enumpath.logger.level = nesting_level
      if path_segments.any?
        Enumpath.log('Applying') { { operator: path_segments, to: enum } }
        apply_segments(path_segments, enum, resolved_path, nesting_level)
      else
        Enumpath.log('Storing') { { resolved_path: resolved_path, enum: enum } }
        results.store(resolved_path, enum)
      end
      Enumpath.logger.level = nesting_level
    end
Applies the next normalized path segment to enumerable and keeps track of resolved path segments. This method
 recursively yields to itself via each Operator subclass's {#apply} method. If there are no remaining path
 segments then it stores a new result in the results array effectively ending processing on that branch of the
 original enumerator.

 @param path_segments [Array] an array containing the normalized path segments to be resolved
 @param enum [Enumerable] the object to apply the next normalized path segment to
 @param resolved_path [Array] an array containing the static path segments that have been resolved so far
 @param nesting_level [Integer] used to set the indentation level for {Enumpath::Logger}
 @return [void]