class ElasticAPM::StacktraceBuilder

@api private

def build(backtrace, type:)

def build(backtrace, type:)
  Stacktrace.new.tap do |s|
    s.frames = backtrace[0...config.stack_trace_limit].map do |line|
      @cache[[line, type]]
    end
  end
end

def build_frame(cache, keys)

def build_frame(cache, keys)
  line, type = keys
  abs_path, lineno, function, _module_name = parse_line(line)
  frame = Stacktrace::Frame.new
  frame.abs_path = abs_path
  frame.filename = strip_load_path(abs_path)
  frame.function = function
  frame.lineno = lineno.to_i
  frame.library_frame = library_frame?(config, abs_path)
  line_count =
    context_lines_for(config, type, library_frame: frame.library_frame)
  frame.build_context line_count
  cache[[line, type]] = frame
end

def context_lines_for(config, type, library_frame:)

def context_lines_for(config, type, library_frame:)
  key = "source_lines_#{type}_#{library_frame ? 'library' : 'app'}_frames"
  config.send(key.to_sym)
end

def initialize(config)

def initialize(config)
  @config = config
  @cache = Util::LruCache.new(2048, &method(:build_frame))
end

def library_frame?(config, abs_path)

rubocop:disable Metrics/CyclomaticComplexity
def library_frame?(config, abs_path)
  return false unless abs_path
  return true if abs_path.start_with?(GEMS_PATH)
  if abs_path.start_with?(config.__root_path)
    return true if abs_path.start_with?(config.__root_path + '/vendor')
    return false
  end
  return true if abs_path.match(RUBY_VERS_REGEX)
  return true if abs_path.match(JRUBY_ORG_REGEX)
  false
end

def parse_line(line)

def parse_line(line)
  ruby_match = line.match(RUBY_FORMAT)
  if ruby_match
    _, file, number, method = ruby_match.to_a
    file.sub!(/\.class$/, '.rb')
    module_name = nil
  else
    java_match = line.match(JAVA_FORMAT)
    _, module_name, method, file, number = java_match.to_a
  end
  [file, number, method, module_name]
end

def strip_load_path(path)

def strip_load_path(path)
  return nil if path.nil?
  prefix =
    $LOAD_PATH
    .map(&:to_s)
    .select { |s| path.start_with?(s) }
    .max_by(&:length)
  prefix ? path[prefix.chomp(File::SEPARATOR).length + 1..-1] : path
end