rubocop 0.26.1 → 0.27.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubocop might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +10 -6
- data/.travis.yml +2 -0
- data/CHANGELOG.md +30 -0
- data/README.md +9 -2
- data/assets/logo.png +0 -0
- data/assets/output.html.erb +68 -65
- data/config/default.yml +42 -7
- data/config/disabled.yml +5 -0
- data/config/enabled.yml +32 -7
- data/lib/rubocop.rb +10 -2
- data/lib/rubocop/comment_config.rb +11 -17
- data/lib/rubocop/config.rb +20 -16
- data/lib/rubocop/config_loader.rb +8 -12
- data/lib/rubocop/cop/cop.rb +13 -12
- data/lib/rubocop/cop/lint/block_alignment.rb +4 -6
- data/lib/rubocop/cop/lint/def_end_alignment.rb +2 -2
- data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -3
- data/lib/rubocop/cop/lint/useless_setter_call.rb +2 -2
- data/lib/rubocop/cop/metrics/abc_size.rb +27 -0
- data/lib/rubocop/cop/metrics/block_nesting.rb +2 -4
- data/lib/rubocop/cop/metrics/class_length.rb +1 -1
- data/lib/rubocop/cop/metrics/line_length.rb +2 -5
- data/lib/rubocop/cop/metrics/method_length.rb +2 -2
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +24 -15
- data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +15 -2
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +63 -0
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/if_node.rb +3 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +3 -3
- data/lib/rubocop/cop/mixin/{on_method.rb → on_method_def.rb} +3 -3
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +2 -2
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -2
- data/lib/rubocop/cop/mixin/string_literals_help.rb +28 -0
- data/lib/rubocop/cop/rails/delegate.rb +2 -2
- data/lib/rubocop/cop/style/access_modifier_indentation.rb +2 -2
- data/lib/rubocop/cop/style/accessor_method_name.rb +2 -2
- data/lib/rubocop/cop/style/align_hash.rb +16 -12
- data/lib/rubocop/cop/style/align_parameters.rb +1 -1
- data/lib/rubocop/cop/style/and_or.rb +14 -6
- data/lib/rubocop/cop/style/array_join.rb +1 -1
- data/lib/rubocop/cop/style/block_comments.rb +16 -8
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +6 -30
- data/lib/rubocop/cop/style/case_indentation.rb +20 -12
- data/lib/rubocop/cop/style/collection_methods.rb +4 -4
- data/lib/rubocop/cop/style/colon_method_call.rb +9 -0
- data/lib/rubocop/cop/style/comment_annotation.rb +1 -1
- data/lib/rubocop/cop/style/comment_indentation.rb +22 -22
- data/lib/rubocop/cop/style/def_with_parentheses.rb +2 -2
- data/lib/rubocop/cop/style/deprecated_hash_methods.rb +1 -1
- data/lib/rubocop/cop/style/double_negation.rb +6 -1
- data/lib/rubocop/cop/style/else_alignment.rb +93 -0
- data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -1
- data/lib/rubocop/cop/style/empty_lines.rb +1 -1
- data/lib/rubocop/cop/style/empty_lines_around_class_body.rb +34 -0
- data/lib/rubocop/cop/style/empty_lines_around_method_body.rb +37 -0
- data/lib/rubocop/cop/style/empty_lines_around_module_body.rb +30 -0
- data/lib/rubocop/cop/style/encoding.rb +1 -1
- data/lib/rubocop/cop/style/format_string.rb +4 -4
- data/lib/rubocop/cop/style/indent_array.rb +2 -2
- data/lib/rubocop/cop/style/indent_hash.rb +17 -12
- data/lib/rubocop/cop/style/indentation_width.rb +27 -19
- data/lib/rubocop/cop/style/method_call_parentheses.rb +3 -3
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +17 -11
- data/lib/rubocop/cop/style/method_name.rb +1 -1
- data/lib/rubocop/cop/style/multiline_operation_indentation.rb +174 -0
- data/lib/rubocop/cop/style/non_nil_check.rb +12 -15
- data/lib/rubocop/cop/style/not.rb +1 -1
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +12 -17
- data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
- data/lib/rubocop/cop/style/predicate_name.rb +2 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +2 -2
- data/lib/rubocop/cop/style/redundant_return.rb +3 -3
- data/lib/rubocop/cop/style/redundant_self.rb +3 -3
- data/lib/rubocop/cop/style/regexp_literal.rb +17 -13
- data/lib/rubocop/cop/style/rescue_modifier.rb +2 -2
- data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
- data/lib/rubocop/cop/style/space_after_method_name.rb +2 -2
- data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +17 -11
- data/lib/rubocop/cop/style/space_before_block_braces.rb +1 -1
- data/lib/rubocop/cop/style/space_inside_block_braces.rb +17 -14
- data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +10 -6
- data/lib/rubocop/cop/style/string_literals.rb +13 -16
- data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +41 -0
- data/lib/rubocop/cop/style/trailing_comma.rb +1 -3
- data/lib/rubocop/cop/style/trivial_accessors.rb +3 -3
- data/lib/rubocop/cop/style/unneeded_capital_w.rb +1 -1
- data/lib/rubocop/cop/style/unneeded_percent_q.rb +2 -2
- data/lib/rubocop/cop/style/word_array.rb +23 -19
- data/lib/rubocop/cop/team.rb +13 -26
- data/lib/rubocop/cop/util.rb +5 -0
- data/lib/rubocop/cop/variable_force/locatable.rb +7 -13
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- data/lib/rubocop/formatter/formatter_set.rb +9 -1
- data/lib/rubocop/formatter/html_formatter.rb +83 -55
- data/lib/rubocop/formatter/simple_text_formatter.rb +2 -2
- data/lib/rubocop/formatter/text_util.rb +25 -0
- data/lib/rubocop/options.rb +14 -7
- data/lib/rubocop/path_util.rb +11 -7
- data/lib/rubocop/runner.rb +7 -2
- data/lib/rubocop/version.rb +1 -1
- data/relnotes/v0.27.0.md +77 -0
- data/rubocop.gemspec +1 -1
- data/spec/fixtures/html_formatter/expected.html +495 -0
- data/spec/fixtures/html_formatter/project/app/controllers/application_controller.rb +5 -0
- data/spec/fixtures/html_formatter/project/app/controllers/books_controller.rb +74 -0
- data/spec/fixtures/html_formatter/project/app/models/book.rb +5 -0
- data/spec/rubocop/cli_spec.rb +56 -13
- data/spec/rubocop/cop/lint/invalid_character_literal_spec.rb +1 -1
- data/spec/rubocop/cop/metrics/abc_size_spec.rb +99 -0
- data/spec/rubocop/cop/rails/action_filter_spec.rb +1 -0
- data/spec/rubocop/cop/style/access_modifier_indentation_spec.rb +23 -1
- data/spec/rubocop/cop/style/align_hash_spec.rb +13 -0
- data/spec/rubocop/cop/style/align_parameters_spec.rb +44 -33
- data/spec/rubocop/cop/style/blocks_spec.rb +8 -0
- data/spec/rubocop/cop/style/braces_around_hash_parameters_spec.rb +9 -9
- data/spec/rubocop/cop/style/case_indentation_spec.rb +3 -2
- data/spec/rubocop/cop/style/colon_method_call_spec.rb +5 -0
- data/spec/rubocop/cop/style/comment_indentation_spec.rb +6 -1
- data/spec/rubocop/cop/style/else_alignment_spec.rb +437 -0
- data/spec/rubocop/cop/style/empty_lines_around_class_body_spec.rb +75 -0
- data/spec/rubocop/cop/style/{empty_lines_around_body_spec.rb → empty_lines_around_method_body_spec.rb} +9 -50
- data/spec/rubocop/cop/style/empty_lines_around_module_body_spec.rb +79 -0
- data/spec/rubocop/cop/style/file_name_spec.rb +1 -1
- data/spec/rubocop/cop/style/format_string_spec.rb +12 -0
- data/spec/rubocop/cop/style/indent_array_spec.rb +6 -1
- data/spec/rubocop/cop/style/indent_hash_spec.rb +2 -1
- data/spec/rubocop/cop/style/indentation_width_spec.rb +765 -722
- data/spec/rubocop/cop/style/multiline_operation_indentation_spec.rb +414 -0
- data/spec/rubocop/cop/style/non_nil_check_spec.rb +86 -55
- data/spec/rubocop/cop/style/single_line_methods_spec.rb +5 -1
- data/spec/rubocop/cop/style/space_before_block_braces_spec.rb +2 -1
- data/spec/rubocop/cop/style/space_inside_block_braces_spec.rb +2 -1
- data/spec/rubocop/cop/style/string_literals_in_interpolation_spec.rb +63 -0
- data/spec/rubocop/cop/style/string_literals_spec.rb +2 -2
- data/spec/rubocop/cop/style/word_array_spec.rb +15 -1
- data/spec/rubocop/formatter/base_formatter_spec.rb +1 -1
- data/spec/rubocop/formatter/disabled_lines_formatter_spec.rb +0 -1
- data/spec/rubocop/formatter/formatter_set_spec.rb +9 -0
- data/spec/rubocop/formatter/html_formatter_spec.rb +25 -122
- data/spec/rubocop/formatter/offense_count_formatter_spec.rb +0 -1
- data/spec/rubocop/runner_spec.rb +1 -1
- data/spec/spec_helper.rb +12 -130
- data/spec/support/cop_helper.rb +72 -0
- data/spec/support/coverage.rb +15 -0
- data/spec/support/{offenses_matcher.rb → custom_matchers.rb} +28 -0
- data/spec/support/jruby_workaround.rb +15 -0
- data/spec/support/{isolated_environment.rb → shared_contexts.rb} +19 -0
- metadata +49 -14
- data/lib/rubocop/cop/style/empty_lines_around_body.rb +0 -75
- data/spec/support/shared_context.rb +0 -20
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks if uses of quotes match the configured preference.
|
7
|
+
class StringLiteralsInInterpolation < Cop
|
8
|
+
include ConfigurableEnforcedStyle
|
9
|
+
include StringLiteralsHelp
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def message(*)
|
14
|
+
# single_quotes -> single-quoted
|
15
|
+
kind = style.to_s.sub(/_(.*)s/, '-\1d')
|
16
|
+
|
17
|
+
"Prefer #{kind} strings inside interpolations."
|
18
|
+
end
|
19
|
+
|
20
|
+
def offense?(node)
|
21
|
+
# If it's not a string within a dynamic string, i.e. part of an
|
22
|
+
# expression in an interpolation, then it's not an offense for this
|
23
|
+
# cop.
|
24
|
+
return false unless node.each_ancestor.find do |a|
|
25
|
+
a.type == :dstr && within_node?(node, a)
|
26
|
+
end
|
27
|
+
|
28
|
+
wrong_quotes?(node, style)
|
29
|
+
end
|
30
|
+
|
31
|
+
def autocorrect(node)
|
32
|
+
@corrections << lambda do |corrector|
|
33
|
+
replacement = node.loc.begin.is?('"') ? "'" : '"'
|
34
|
+
corrector.replace(node.loc.begin, replacement)
|
35
|
+
corrector.replace(node.loc.end, replacement)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -78,8 +78,6 @@ module RuboCop
|
|
78
78
|
unless should_have_comma
|
79
79
|
extra_info = if style == :comma
|
80
80
|
', unless each item is on its own line'
|
81
|
-
else
|
82
|
-
''
|
83
81
|
end
|
84
82
|
avoid_comma(kind, after_last_item.begin_pos + comma_offset, sb,
|
85
83
|
extra_info)
|
@@ -123,7 +121,7 @@ module RuboCop
|
|
123
121
|
article = kind =~ /array/ ? 'an' : 'a'
|
124
122
|
add_offense(range, range,
|
125
123
|
format(MSG, 'Avoid', format(kind, article)) +
|
126
|
-
extra_info
|
124
|
+
"#{extra_info}.")
|
127
125
|
end
|
128
126
|
|
129
127
|
def put_comma(items, kind, sb)
|
@@ -6,13 +6,13 @@ module RuboCop
|
|
6
6
|
# This cop looks for trivial reader/writer methods, that could
|
7
7
|
# have been created with the attr_* family of functions automatically.
|
8
8
|
class TrivialAccessors < Cop
|
9
|
-
include
|
9
|
+
include OnMethodDef
|
10
10
|
|
11
11
|
MSG = 'Use `attr_%s` to define trivial %s methods.'
|
12
12
|
|
13
13
|
private
|
14
14
|
|
15
|
-
def
|
15
|
+
def on_method_def(node, method_name, args, body)
|
16
16
|
kind = if trivial_reader?(method_name, args, body)
|
17
17
|
'reader'
|
18
18
|
elsif trivial_writer?(method_name, args, body)
|
@@ -91,7 +91,7 @@ module RuboCop
|
|
91
91
|
|
92
92
|
def trivial_accessor_kind(method_name, args, body)
|
93
93
|
if trivial_writer?(method_name, args, body) &&
|
94
|
-
|
94
|
+
!dsl_writer?(method_name)
|
95
95
|
'writer'
|
96
96
|
elsif trivial_reader?(method_name, args, body)
|
97
97
|
'reader'
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
def on_percent_literal(node)
|
20
20
|
node.children.each do |string|
|
21
21
|
if string.type == :dstr ||
|
22
|
-
|
22
|
+
string.loc.expression.source =~ StringHelp::ESCAPED_CHAR_REGEXP
|
23
23
|
return
|
24
24
|
end
|
25
25
|
end
|
@@ -33,11 +33,11 @@ module RuboCop
|
|
33
33
|
end
|
34
34
|
return if ignored_node?(node) || part_of_ignored_node?(node)
|
35
35
|
src = node.loc.expression.source
|
36
|
-
return unless src
|
36
|
+
return unless src.start_with?('%q') || src.start_with?('%Q')
|
37
37
|
return if src =~ /'/ && src =~ /"/
|
38
38
|
return if src =~ StringHelp::ESCAPED_CHAR_REGEXP
|
39
39
|
|
40
|
-
extra = if src
|
40
|
+
extra = if src.start_with?('%Q')
|
41
41
|
', or for dynamic strings that contain double quotes'
|
42
42
|
else
|
43
43
|
''
|
@@ -17,8 +17,8 @@ module RuboCop
|
|
17
17
|
def on_array(node)
|
18
18
|
array_elems = node.children
|
19
19
|
return unless array_of?(:str, node) &&
|
20
|
-
|
21
|
-
|
20
|
+
!complex_content?(array_elems) &&
|
21
|
+
array_elems.size > min_size && !comments_in_array?(node)
|
22
22
|
|
23
23
|
add_offense(node, :expression) { self.max = array_elems.size }
|
24
24
|
end
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
45
45
|
next if source.start_with?('?') # %W(\r \n) can replace [?\r, ?\n]
|
46
46
|
|
47
47
|
str_content = Util.strip_quotes(source)
|
48
|
-
return true unless str_content =~
|
48
|
+
return true unless str_content =~ word_regex
|
49
49
|
end
|
50
50
|
|
51
51
|
false
|
@@ -55,29 +55,33 @@ module RuboCop
|
|
55
55
|
cop_config['MinSize']
|
56
56
|
end
|
57
57
|
|
58
|
+
def word_regex
|
59
|
+
cop_config['WordRegex']
|
60
|
+
end
|
61
|
+
|
58
62
|
def autocorrect(node)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
contents = node.children.map do |n|
|
63
|
-
if character_literal?(n)
|
64
|
-
interpolated = true
|
65
|
-
begin_pos = n.loc.expression.begin_pos + '?'.length
|
66
|
-
end_pos = n.loc.expression.end_pos
|
67
|
-
else
|
68
|
-
begin_pos = n.loc.begin.end_pos
|
69
|
-
end_pos = n.loc.end.begin_pos
|
70
|
-
end
|
71
|
-
Parser::Source::Range.new(sb, begin_pos, end_pos).source
|
72
|
-
end.join(' ')
|
73
|
-
|
74
|
-
char = interpolated ? 'W' : 'w'
|
63
|
+
@interpolated = false
|
64
|
+
contents = node.children.map { |n| source_for(n) }.join(' ')
|
65
|
+
char = @interpolated ? 'W' : 'w'
|
75
66
|
|
76
67
|
@corrections << lambda do |corrector|
|
77
68
|
corrector.replace(node.loc.expression, "%#{char}(#{contents})")
|
78
69
|
end
|
79
70
|
end
|
80
71
|
|
72
|
+
def source_for(str_node)
|
73
|
+
if character_literal?(str_node)
|
74
|
+
@interpolated = true
|
75
|
+
begin_pos = str_node.loc.expression.begin_pos + '?'.length
|
76
|
+
end_pos = str_node.loc.expression.end_pos
|
77
|
+
else
|
78
|
+
begin_pos = str_node.loc.begin.end_pos
|
79
|
+
end_pos = str_node.loc.end.begin_pos
|
80
|
+
end
|
81
|
+
Parser::Source::Range.new(str_node.loc.expression.source_buffer,
|
82
|
+
begin_pos, end_pos).source
|
83
|
+
end
|
84
|
+
|
81
85
|
def character_literal?(node)
|
82
86
|
node.loc.end.nil?
|
83
87
|
end
|
data/lib/rubocop/cop/team.rb
CHANGED
@@ -62,26 +62,7 @@ module RuboCop
|
|
62
62
|
@updated_source_file = false
|
63
63
|
return unless autocorrect?
|
64
64
|
|
65
|
-
|
66
|
-
array.concat(cop.corrections) if cop.relevant_file?(buffer.name)
|
67
|
-
end
|
68
|
-
|
69
|
-
corrector = Corrector.new(buffer, corrections)
|
70
|
-
new_source = begin
|
71
|
-
# Corrector#rewrite can raise RangeError or RuntimeError
|
72
|
-
# for various error conditions including clobbering.
|
73
|
-
s = corrector.rewrite
|
74
|
-
# We raise RuntimeError ourselves if the rewritten code
|
75
|
-
# is not parsable ruby. We don't want to write that code
|
76
|
-
# to file.
|
77
|
-
fail unless ProcessedSource.new(s).valid_syntax?
|
78
|
-
s
|
79
|
-
rescue RangeError, RuntimeError
|
80
|
-
# Handle all errors by limiting the changes to one
|
81
|
-
# cop. The caller will parse the source again when the
|
82
|
-
# file has been updated.
|
83
|
-
autocorrect_one_cop(buffer, cops)
|
84
|
-
end
|
65
|
+
new_source = autocorrect_one_cop(buffer, cops)
|
85
66
|
|
86
67
|
return if new_source == buffer.source
|
87
68
|
|
@@ -90,13 +71,19 @@ module RuboCop
|
|
90
71
|
@updated_source_file = true
|
91
72
|
end
|
92
73
|
|
93
|
-
# Does
|
94
|
-
#
|
95
|
-
#
|
74
|
+
# Does an auto-correction run by correcting for just one cop. The
|
75
|
+
# re-running of auto-corrections will make sure that the full set of
|
76
|
+
# auto-corrections is tried again after this method has finished.
|
96
77
|
def autocorrect_one_cop(buffer, cops)
|
97
|
-
cop_with_corrections = cops.find
|
98
|
-
|
99
|
-
|
78
|
+
cop_with_corrections = cops.find do |cop|
|
79
|
+
cop.relevant_file?(buffer.name) && cop.corrections.any?
|
80
|
+
end
|
81
|
+
if cop_with_corrections
|
82
|
+
corrector = Corrector.new(buffer, cop_with_corrections.corrections)
|
83
|
+
corrector.rewrite
|
84
|
+
else
|
85
|
+
buffer.source
|
86
|
+
end
|
100
87
|
end
|
101
88
|
|
102
89
|
def process_commissioner_errors(file, file_errors)
|
data/lib/rubocop/cop/util.rb
CHANGED
@@ -158,6 +158,11 @@ module RuboCop
|
|
158
158
|
source_before_end =~ /\n\s*\Z/
|
159
159
|
end
|
160
160
|
|
161
|
+
def within_node?(inner, outer)
|
162
|
+
o, i = outer.loc.expression, inner.loc.expression
|
163
|
+
i.begin_pos >= o.begin_pos && i.end_pos <= o.end_pos
|
164
|
+
end
|
165
|
+
|
161
166
|
# Returns, for example, a bare `if` node if the given node is an `if`
|
162
167
|
# with calls chained to the end of it.
|
163
168
|
def first_part_of_call_chain(node)
|
@@ -39,7 +39,7 @@ module RuboCop
|
|
39
39
|
# # resbody
|
40
40
|
# end
|
41
41
|
if branch_point_node.type == :rescue &&
|
42
|
-
|
42
|
+
(branch_body_name == 'main' || other.branch_body_name == 'main')
|
43
43
|
return false
|
44
44
|
end
|
45
45
|
|
@@ -78,18 +78,12 @@ module RuboCop
|
|
78
78
|
|
79
79
|
def branch_body_name
|
80
80
|
case branch_point_node.type
|
81
|
-
when :if
|
82
|
-
|
83
|
-
when
|
84
|
-
|
85
|
-
when
|
86
|
-
|
87
|
-
when RESCUE_TYPE
|
88
|
-
rescue_body_name
|
89
|
-
when ENSURE_TYPE
|
90
|
-
ensure_body_name
|
91
|
-
else
|
92
|
-
fail InvalidBranchBodyError
|
81
|
+
when :if then if_body_name
|
82
|
+
when :case then case_body_name
|
83
|
+
when *LOGICAL_OPERATOR_TYPES then logical_operator_body_name
|
84
|
+
when RESCUE_TYPE then rescue_body_name
|
85
|
+
when ENSURE_TYPE then ensure_body_name
|
86
|
+
else fail InvalidBranchBodyError
|
93
87
|
end
|
94
88
|
rescue InvalidBranchBodyError
|
95
89
|
raise InvalidBranchBodyError,
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require 'fileutils'
|
4
|
+
|
3
5
|
module RuboCop
|
4
6
|
module Formatter
|
5
7
|
# This is a collection of formatters. A FormatterSet can hold multiple
|
@@ -37,7 +39,13 @@ module RuboCop
|
|
37
39
|
builtin_formatter_class(formatter_type)
|
38
40
|
end
|
39
41
|
|
40
|
-
|
42
|
+
if output_path
|
43
|
+
dir_path = File.dirname(output_path)
|
44
|
+
FileUtils.mkdir_p(dir_path) unless File.exist?(dir_path)
|
45
|
+
output = File.open(output_path, 'w')
|
46
|
+
else
|
47
|
+
output = $stdout
|
48
|
+
end
|
41
49
|
|
42
50
|
self << formatter_class.new(output)
|
43
51
|
end
|
@@ -1,89 +1,117 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'erb'
|
4
|
-
require '
|
4
|
+
require 'ostruct'
|
5
|
+
require 'base64'
|
6
|
+
require 'rubocop/formatter/text_util'
|
5
7
|
|
6
8
|
module RuboCop
|
7
9
|
module Formatter
|
8
10
|
# This formatter saves the output as a html file.
|
9
11
|
class HTMLFormatter < BaseFormatter
|
10
|
-
|
12
|
+
TEMPLATE_PATH =
|
13
|
+
File.expand_path('../../../../assets/output.html.erb', __FILE__)
|
11
14
|
|
12
|
-
attr_reader :
|
15
|
+
attr_reader :files, :summary
|
13
16
|
|
14
17
|
def initialize(output)
|
15
18
|
super
|
16
|
-
@
|
17
|
-
|
18
|
-
files: [],
|
19
|
-
summary: { offense_count: 0 }
|
20
|
-
}
|
19
|
+
@files = []
|
20
|
+
@summary = OpenStruct.new(offense_count: 0)
|
21
21
|
end
|
22
22
|
|
23
23
|
def started(target_files)
|
24
|
-
|
24
|
+
summary.target_files = target_files
|
25
25
|
end
|
26
26
|
|
27
27
|
def file_finished(file, offenses)
|
28
|
-
|
29
|
-
|
28
|
+
files << OpenStruct.new(path: file, offenses: offenses)
|
29
|
+
summary.offense_count += offenses.count
|
30
30
|
end
|
31
31
|
|
32
32
|
def finished(inspected_files)
|
33
|
-
|
34
|
-
template = File.read(File
|
35
|
-
.expand_path('../../../../assets/output.html.erb', __FILE__))
|
36
|
-
erb = ERB.new(template)
|
37
|
-
html_content = erb.result(binding)
|
38
|
-
output.write html_content
|
39
|
-
end
|
33
|
+
summary.inspected_files = inspected_files
|
40
34
|
|
41
|
-
|
42
|
-
{
|
43
|
-
rubocop_version: RuboCop::Version::STRING,
|
44
|
-
ruby_engine: RUBY_ENGINE,
|
45
|
-
ruby_version: RUBY_VERSION,
|
46
|
-
ruby_patchlevel: RUBY_PATCHLEVEL.to_s,
|
47
|
-
ruby_platform: RUBY_PLATFORM
|
48
|
-
}
|
35
|
+
render_html
|
49
36
|
end
|
50
37
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
38
|
+
def render_html
|
39
|
+
context = ERBContext.new(files, summary)
|
40
|
+
|
41
|
+
template = File.read(TEMPLATE_PATH)
|
42
|
+
erb = ERB.new(template, nil, '-')
|
43
|
+
html = erb.result(context.binding)
|
44
|
+
|
45
|
+
output.write html
|
56
46
|
end
|
57
47
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
48
|
+
Color = Struct.new(:red, :green, :blue, :alpha) do
|
49
|
+
def to_s
|
50
|
+
"rgba(#{values.join(', ')})"
|
51
|
+
end
|
52
|
+
|
53
|
+
def fade_out(amount)
|
54
|
+
dup.tap do |color|
|
55
|
+
color.alpha -= amount
|
56
|
+
end
|
57
|
+
end
|
66
58
|
end
|
67
59
|
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
60
|
+
# This class privides helper methods used in the ERB template.
|
61
|
+
class ERBContext
|
62
|
+
include PathUtil, TextUtil
|
63
|
+
|
64
|
+
SEVERITY_COLORS = {
|
65
|
+
refactor: Color.new(0xED, 0x9C, 0x28, 1.0),
|
66
|
+
convention: Color.new(0xED, 0x9C, 0x28, 1.0),
|
67
|
+
warning: Color.new(0x96, 0x28, 0xEF, 1.0),
|
68
|
+
error: Color.new(0xD2, 0x32, 0x2D, 1.0),
|
69
|
+
fatal: Color.new(0xD2, 0x32, 0x2D, 1.0)
|
76
70
|
}
|
77
|
-
end
|
78
71
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
72
|
+
LOGO_IMAGE_PATH =
|
73
|
+
File.expand_path('../../../../assets/logo.png', __FILE__)
|
74
|
+
|
75
|
+
attr_reader :files, :summary
|
76
|
+
|
77
|
+
def initialize(files, summary)
|
78
|
+
@files = files.sort_by(&:path)
|
79
|
+
@summary = summary
|
80
|
+
end
|
81
|
+
|
82
|
+
# Make Kernel#binding public.
|
83
|
+
def binding
|
84
|
+
super
|
85
|
+
end
|
86
|
+
|
87
|
+
def decorated_message(offense)
|
88
|
+
offense.message.gsub(/`(.+?)`/) do
|
89
|
+
"<code>#{Regexp.last_match(1)}</code>"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def highlighted_source_line(offense)
|
94
|
+
location = offense.location
|
95
|
+
|
96
|
+
column_range = if location.begin.line == location.end.line
|
97
|
+
location.column_range
|
98
|
+
else
|
99
|
+
location.column...location.source_line.length
|
100
|
+
end
|
101
|
+
|
102
|
+
source_line = location.source_line
|
103
|
+
|
104
|
+
source_line[0...column_range.begin] +
|
105
|
+
"<span class=\"highlight #{offense.severity}\">" +
|
106
|
+
source_line[column_range] +
|
107
|
+
'</span>' +
|
108
|
+
source_line[column_range.end..-1]
|
109
|
+
end
|
85
110
|
|
86
|
-
|
111
|
+
def base64_encoded_logo_image
|
112
|
+
image = File.read(LOGO_IMAGE_PATH, binmode: true)
|
113
|
+
Base64.encode64(image)
|
114
|
+
end
|
87
115
|
end
|
88
116
|
end
|
89
117
|
end
|