class FoodCritic::ContextOutput

Display rule matches with surrounding context.

def ansi_print(text, fg, bg = nil, attr = nil)

Parameters:
  • attr (String) -- any formatting options
  • bg (String) -- background color
  • fg (String) -- foreground color
  • text (String) -- the string to format
def ansi_print(text, fg, bg = nil, attr = nil)
  unless @out.tty?
    puts text
    return
  end
  colors = %w{black red green yellow blue magenta cyan white}
  attrs = %w{reset bold dim underscore blink reverse hidden}
  escape = "\033[%sm"
  fmt = []
  fmt << 30 + colors.index(fg.to_s) if fg
  fmt << 40 + colors.index(bg.to_s) if bg
  fmt << attrs.index(attr.to_s) if attr
  if fmt
    puts "#{escape % fmt.join(";")}#{text}#{escape % 0}"
  else
    puts text
  end
end

def key_by_file_and_line(review)

Returns:
  • (Hash) - Nested hashes keyed by filename and line number.

Parameters:
  • review (Review) -- The review to convert.
def key_by_file_and_line(review)
  warn_hash = {}
  review.warnings.each do |warning|
    filename = Pathname.new(warning.match[:filename]).cleanpath.to_s
    line_num = warning.match[:line].to_i
    warn_hash[filename] = {} unless warn_hash.key?(filename)
    unless warn_hash[filename].key?(line_num)
      warn_hash[filename][line_num] = Set.new
    end
    warn_hash[filename][line_num] << warning.rule
  end
  warn_hash
end

def output(review)

Parameters:
  • review (Review) -- The review to output.
def output(review)
  unless review.respond_to?(:warnings)
    puts review; return
  end
  context = 3
  print_fn = lambda { |fn| ansi_print(fn, :red, nil, :bold) }
  print_rule = lambda { |warn| ansi_print(warn, :cyan, nil, :bold) }
  print_line = lambda { |line| ansi_print(line, nil, :red, :bold) }
  key_by_file_and_line(review).each do |fn, warnings|
    print_fn.call fn
    unless File.exist?(fn)
      print_rule.call warnings[1].to_a.join("\n")
      next
    end
    # Set of line numbers with warnings
    warn_lines = warnings.keys.to_set
    # Moving set of line numbers within the context of our position
    context_set = (0..context).to_set
    # The last line number we printed a warning for
    last_warn = -1
    File.open(fn) do |file|
      file.each do |line|
        context_set.add(file.lineno + context)
        context_set.delete(file.lineno - context - 1)
        # Find the first warning within our context
        context_warns = context_set & warn_lines
        next_warn = context_warns.min
        # We may need to interrupt the trailing context
        # of a previous warning
        next_warn = file.lineno if warn_lines.include? file.lineno
        # Display a warning
        if next_warn && next_warn > last_warn
          print_rule.call warnings[next_warn].to_a.join("\n")
          last_warn = next_warn
        end
        # Display any relevant lines
        if warn_lines.include? file.lineno
          print "%4i|" % file.lineno
          print_line.call line.chomp
        elsif not context_warns.empty?
          print "%4i|" % file.lineno
          puts line.chomp
        end
      end
    end
  end
end