-
-
Notifications
You must be signed in to change notification settings - Fork 3k
/
html_formatter.rb
134 lines (107 loc) · 3.53 KB
/
html_formatter.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# frozen_string_literal: true
require 'cgi'
require 'erb'
require 'ostruct'
require 'base64'
require 'rubocop/formatter/text_util'
module RuboCop
module Formatter
# This formatter saves the output as an html file.
class HTMLFormatter < BaseFormatter
ELLIPSES = '<span class="extra-code">...</span>'.freeze
TEMPLATE_PATH =
File.expand_path('../../../../assets/output.html.erb', __FILE__)
Color = Struct.new(:red, :green, :blue, :alpha) do
def to_s
"rgba(#{values.join(', ')})"
end
def fade_out(amount)
dup.tap do |color|
color.alpha -= amount
end
end
end
attr_reader :files, :summary
def initialize(output, options = {})
super
@files = []
@summary = OpenStruct.new(offense_count: 0)
end
def started(target_files)
summary.target_files = target_files
end
def file_finished(file, offenses)
files << OpenStruct.new(path: file, offenses: offenses)
summary.offense_count += offenses.count
end
def finished(inspected_files)
summary.inspected_files = inspected_files
render_html
end
def render_html
context = ERBContext.new(files, summary)
template = File.read(TEMPLATE_PATH, encoding: Encoding::UTF_8)
erb = ERB.new(template, nil, '-')
html = erb.result(context.binding)
output.write html
end
# This class provides helper methods used in the ERB template.
class ERBContext
include PathUtil
include TextUtil
SEVERITY_COLORS = {
refactor: Color.new(0xED, 0x9C, 0x28, 1.0),
convention: Color.new(0xED, 0x9C, 0x28, 1.0),
warning: Color.new(0x96, 0x28, 0xEF, 1.0),
error: Color.new(0xD2, 0x32, 0x2D, 1.0),
fatal: Color.new(0xD2, 0x32, 0x2D, 1.0)
}.freeze
LOGO_IMAGE_PATH =
File.expand_path('../../../../assets/logo.png', __FILE__)
attr_reader :files, :summary
def initialize(files, summary)
@files = files.sort_by(&:path)
@summary = summary
end
# Make Kernel#binding public.
def binding
super
end
def decorated_message(offense)
offense.message.gsub(/`(.+?)`/) do
"<code>#{Regexp.last_match(1)}</code>"
end
end
def highlighted_source_line(offense)
source_before_highlight(offense) +
hightlight_source_tag(offense) +
source_after_highlight(offense) +
possible_ellipses(offense.location)
end
def hightlight_source_tag(offense)
"<span class=\"highlight #{offense.severity}\">" \
"#{escape(offense.highlighted_area.source)}" \
'</span>'
end
def source_before_highlight(offense)
source_line = offense.location.source_line
escape(source_line[0...offense.highlighted_area.begin_pos])
end
def source_after_highlight(offense)
source_line = offense.location.source_line
escape(source_line[offense.highlighted_area.end_pos..-1])
end
def possible_ellipses(location)
location.first_line == location.last_line ? '' : " #{ELLIPSES}"
end
def escape(s)
CGI.escapeHTML(s)
end
def base64_encoded_logo_image
image = File.read(LOGO_IMAGE_PATH, binmode: true)
Base64.encode64(image)
end
end
end
end
end