rubocop 0.59.1 → 0.59.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/config/default.yml +1 -0
- data/lib/rubocop.rb +2 -0
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +117 -0
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +19 -9
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +34 -10
- data/lib/rubocop/cop/lint/nested_percent_literal.rb +3 -2
- data/lib/rubocop/cop/metrics/block_length.rb +1 -0
- data/lib/rubocop/cop/metrics/class_length.rb +10 -0
- data/lib/rubocop/cop/metrics/line_length.rb +2 -2
- data/lib/rubocop/cop/metrics/method_length.rb +3 -0
- data/lib/rubocop/cop/metrics/module_length.rb +10 -0
- data/lib/rubocop/cop/mixin/code_length.rb +5 -1
- data/lib/rubocop/cop/mixin/percent_literal.rb +0 -113
- data/lib/rubocop/cop/mixin/preferred_delimiters.rb +53 -0
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/rails/delegate.rb +2 -2
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +12 -0
- data/lib/rubocop/cop/style/for.rb +27 -2
- data/lib/rubocop/cop/style/if_unless_modifier.rb +7 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +6 -0
- data/lib/rubocop/cop/style/semicolon.rb +5 -1
- data/lib/rubocop/cop/style/symbol_array.rb +3 -2
- data/lib/rubocop/cop/style/word_array.rb +3 -2
- data/lib/rubocop/cop/style/zero_length_predicate.rb +12 -0
- data/lib/rubocop/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28eeb813f59ba82f401cfac05daa5a118a1014af
|
4
|
+
data.tar.gz: 63b3201d008b9f790f93cc5a724c1a596bd75dd4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c79b61631cdc0e7fd9f0a8b17b0d04956827286239a7f65948e5a9cfec8f4a286dc1e6f062d9d0f5f2bdeaab06ff6dd2d2e10ddcd962dc6446f46ddd64bdbb5a
|
7
|
+
data.tar.gz: b348fe1df3db7a302023b32fd4fafa3ab2a4b09edd99efdfc55f3d8dba27ac18dd118eeeb008702467cd188c96104309b99800a428224de17758a6cd4d95c3eb
|
data/README.md
CHANGED
@@ -53,7 +53,7 @@ haven't reached version 1.0 yet). To prevent an unwanted RuboCop update you
|
|
53
53
|
might want to use a conservative version locking in your `Gemfile`:
|
54
54
|
|
55
55
|
```rb
|
56
|
-
gem 'rubocop', '~> 0.59.
|
56
|
+
gem 'rubocop', '~> 0.59.2', require: false
|
57
57
|
```
|
58
58
|
|
59
59
|
## Quickstart
|
@@ -67,7 +67,7 @@ $ rubocop
|
|
67
67
|
|
68
68
|
## Official manual
|
69
69
|
|
70
|
-
You can read a ton more about RuboCop in its [official manual](
|
70
|
+
You can read a ton more about RuboCop in its [official manual](https://docs.rubocop.org).
|
71
71
|
|
72
72
|
## Compatibility
|
73
73
|
|
data/config/default.yml
CHANGED
data/lib/rubocop.rb
CHANGED
@@ -130,6 +130,7 @@ require_relative 'rubocop/cop/mixin/parser_diagnostic'
|
|
130
130
|
require_relative 'rubocop/cop/mixin/percent_array'
|
131
131
|
require_relative 'rubocop/cop/mixin/percent_literal'
|
132
132
|
require_relative 'rubocop/cop/mixin/preceding_following_alignment'
|
133
|
+
require_relative 'rubocop/cop/mixin/preferred_delimiters'
|
133
134
|
require_relative 'rubocop/cop/mixin/rescue_node'
|
134
135
|
require_relative 'rubocop/cop/mixin/safe_assignment'
|
135
136
|
require_relative 'rubocop/cop/mixin/safe_mode'
|
@@ -154,6 +155,7 @@ require_relative 'rubocop/cop/correctors/line_break_corrector'
|
|
154
155
|
require_relative 'rubocop/cop/correctors/multiline_literal_brace_corrector'
|
155
156
|
require_relative 'rubocop/cop/correctors/ordered_gem_corrector'
|
156
157
|
require_relative 'rubocop/cop/correctors/parentheses_corrector'
|
158
|
+
require_relative 'rubocop/cop/correctors/percent_literal_corrector'
|
157
159
|
require_relative 'rubocop/cop/correctors/punctuation_corrector'
|
158
160
|
require_relative 'rubocop/cop/correctors/space_corrector'
|
159
161
|
require_relative 'rubocop/cop/correctors/string_literal_corrector'
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# This auto-corrects percent literals
|
6
|
+
class PercentLiteralCorrector
|
7
|
+
include Util
|
8
|
+
|
9
|
+
attr_reader :config, :preferred_delimiters
|
10
|
+
|
11
|
+
def initialize(config, preferred_delimiters)
|
12
|
+
@config = config
|
13
|
+
@preferred_delimiters = preferred_delimiters
|
14
|
+
end
|
15
|
+
|
16
|
+
def correct(node, char)
|
17
|
+
escape = escape_words?(node)
|
18
|
+
char = char.upcase if escape
|
19
|
+
delimiters = delimiters_for("%#{char}")
|
20
|
+
contents = new_contents(node, escape, delimiters)
|
21
|
+
wrap_contents(node, contents, char, delimiters)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def wrap_contents(node, contents, char, delimiters)
|
27
|
+
lambda do |corrector|
|
28
|
+
corrector.replace(
|
29
|
+
node.source_range,
|
30
|
+
"%#{char}#{delimiters[0]}#{contents}#{delimiters[1]}"
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def escape_words?(node)
|
36
|
+
node.children.any? { |w| needs_escaping?(w.children[0]) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def delimiters_for(type)
|
40
|
+
PreferredDelimiters
|
41
|
+
.new(type, config, preferred_delimiters)
|
42
|
+
.delimiters
|
43
|
+
end
|
44
|
+
|
45
|
+
def new_contents(node, escape, delimiters)
|
46
|
+
if node.multiline?
|
47
|
+
autocorrect_multiline_words(node, escape, delimiters)
|
48
|
+
else
|
49
|
+
autocorrect_words(node, escape, delimiters)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def autocorrect_multiline_words(node, escape, delimiters)
|
54
|
+
contents = process_multiline_words(node, escape, delimiters)
|
55
|
+
contents << end_content(node.source)
|
56
|
+
contents.join('')
|
57
|
+
end
|
58
|
+
|
59
|
+
def autocorrect_words(node, escape, delimiters)
|
60
|
+
node.children.map do |word_node|
|
61
|
+
fix_escaped_content(word_node, escape, delimiters)
|
62
|
+
end.join(' ')
|
63
|
+
end
|
64
|
+
|
65
|
+
def process_multiline_words(node, escape, delimiters)
|
66
|
+
base_line_num = node.first_line
|
67
|
+
prev_line_num = base_line_num
|
68
|
+
node.children.map.with_index do |word_node, index|
|
69
|
+
line_breaks = line_breaks(word_node,
|
70
|
+
node.source,
|
71
|
+
prev_line_num,
|
72
|
+
base_line_num,
|
73
|
+
index)
|
74
|
+
prev_line_num = word_node.first_line
|
75
|
+
content = fix_escaped_content(word_node, escape, delimiters)
|
76
|
+
line_breaks + content
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def line_breaks(node, source, previous_line_num, base_line_num, node_indx)
|
81
|
+
source_in_lines = source.split("\n")
|
82
|
+
if first_line?(node, previous_line_num)
|
83
|
+
node_indx.zero? && node.first_line == base_line_num ? '' : ' '
|
84
|
+
else
|
85
|
+
process_lines(node, previous_line_num, base_line_num, source_in_lines)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def first_line?(node, previous_line_num)
|
90
|
+
node.first_line == previous_line_num
|
91
|
+
end
|
92
|
+
|
93
|
+
def process_lines(node, previous_line_num, base_line_num, source_in_lines)
|
94
|
+
begin_line_num = previous_line_num - base_line_num + 1
|
95
|
+
end_line_num = node.first_line - base_line_num + 1
|
96
|
+
lines = source_in_lines[begin_line_num...end_line_num]
|
97
|
+
"\n" + lines.join("\n").split(node.source).first
|
98
|
+
end
|
99
|
+
|
100
|
+
def fix_escaped_content(word_node, escape, delimiters)
|
101
|
+
content = word_node.children.first.to_s
|
102
|
+
content = escape_string(content) if escape
|
103
|
+
substitute_escaped_delimiters(content, delimiters)
|
104
|
+
content
|
105
|
+
end
|
106
|
+
|
107
|
+
def substitute_escaped_delimiters(content, delimiters)
|
108
|
+
delimiters.each { |delim| content.gsub!(delim, "\\#{delim}") }
|
109
|
+
end
|
110
|
+
|
111
|
+
def end_content(source)
|
112
|
+
result = /\A(\s*)\]/.match(source.split("\n").last)
|
113
|
+
("\n" + result[1]) if result
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -44,22 +44,16 @@ module RuboCop
|
|
44
44
|
def on_if(node)
|
45
45
|
return if correct_style?(node)
|
46
46
|
|
47
|
-
if last_argument_is_heredoc?(node)
|
47
|
+
if node.modifier_form? && last_argument_is_heredoc?(node)
|
48
48
|
heredoc_node = last_argument(node)
|
49
49
|
|
50
|
-
|
51
|
-
num_of_heredoc_lines =
|
52
|
-
heredoc_body.last_line - heredoc_body.first_line
|
53
|
-
|
54
|
-
line = node.last_line + num_of_heredoc_lines + END_OF_HEREDOC_LINE
|
55
|
-
|
56
|
-
return if next_line_empty?(line)
|
50
|
+
return if next_line_empty?(heredoc_line(node, heredoc_node))
|
57
51
|
|
58
52
|
add_offense(heredoc_node, location: :heredoc_end)
|
59
53
|
else
|
60
54
|
return if next_line_empty?(node.last_line)
|
61
55
|
|
62
|
-
add_offense(node)
|
56
|
+
add_offense(node, location: offense_location(node))
|
63
57
|
end
|
64
58
|
end
|
65
59
|
|
@@ -126,6 +120,22 @@ module RuboCop
|
|
126
120
|
def last_argument(node)
|
127
121
|
node.if_branch.children.last
|
128
122
|
end
|
123
|
+
|
124
|
+
def heredoc_line(node, heredoc_node)
|
125
|
+
heredoc_body = heredoc_node.loc.heredoc_body
|
126
|
+
num_of_heredoc_lines =
|
127
|
+
heredoc_body.last_line - heredoc_body.first_line
|
128
|
+
|
129
|
+
node.last_line + num_of_heredoc_lines + END_OF_HEREDOC_LINE
|
130
|
+
end
|
131
|
+
|
132
|
+
def offense_location(node)
|
133
|
+
if node.loc && node.loc.end
|
134
|
+
:end
|
135
|
+
else
|
136
|
+
:expression
|
137
|
+
end
|
138
|
+
end
|
129
139
|
end
|
130
140
|
end
|
131
141
|
end
|
@@ -29,6 +29,26 @@ module RuboCop
|
|
29
29
|
MSG_BEFORE_AND_AFTER = 'Keep a blank line before and after ' \
|
30
30
|
'`%<modifier>s`.'.freeze
|
31
31
|
|
32
|
+
def on_class(node)
|
33
|
+
_name, superclass, _body = *node
|
34
|
+
|
35
|
+
@class_or_module_def_line = if superclass
|
36
|
+
superclass.first_line
|
37
|
+
else
|
38
|
+
node.source_range.first_line
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_module(node)
|
43
|
+
@class_or_module_def_line = node.source_range.first_line
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_sclass(node)
|
47
|
+
self_node, _body = *node
|
48
|
+
|
49
|
+
@class_or_module_def_line = self_node.source_range.first_line
|
50
|
+
end
|
51
|
+
|
32
52
|
def on_send(node)
|
33
53
|
return unless node.bare_access_modifier?
|
34
54
|
|
@@ -40,11 +60,10 @@ module RuboCop
|
|
40
60
|
def autocorrect(node)
|
41
61
|
lambda do |corrector|
|
42
62
|
send_line = node.first_line
|
43
|
-
previous_line = processed_source[send_line - 2]
|
44
63
|
next_line = processed_source[send_line]
|
45
64
|
line = range_by_whole_lines(node.source_range)
|
46
65
|
|
47
|
-
unless previous_line_empty?(
|
66
|
+
unless previous_line_empty?(send_line)
|
48
67
|
corrector.insert_before(line, "\n")
|
49
68
|
end
|
50
69
|
|
@@ -62,9 +81,12 @@ module RuboCop
|
|
62
81
|
end
|
63
82
|
end
|
64
83
|
|
65
|
-
def previous_line_empty?(
|
84
|
+
def previous_line_empty?(send_line)
|
85
|
+
previous_line = previous_line_ignoring_comments(processed_source,
|
86
|
+
send_line)
|
87
|
+
|
66
88
|
block_start?(previous_line) ||
|
67
|
-
class_def?(
|
89
|
+
class_def?(send_line) ||
|
68
90
|
previous_line.blank?
|
69
91
|
end
|
70
92
|
|
@@ -74,15 +96,16 @@ module RuboCop
|
|
74
96
|
|
75
97
|
def empty_lines_around?(node)
|
76
98
|
send_line = node.first_line
|
77
|
-
|
78
|
-
send_line)
|
99
|
+
|
79
100
|
next_line = processed_source[send_line]
|
80
101
|
|
81
|
-
previous_line_empty?(
|
102
|
+
previous_line_empty?(send_line) && next_line_empty?(next_line)
|
82
103
|
end
|
83
104
|
|
84
105
|
def class_def?(line)
|
85
|
-
|
106
|
+
return false unless @class_or_module_def_line
|
107
|
+
|
108
|
+
line == @class_or_module_def_line + 1
|
86
109
|
end
|
87
110
|
|
88
111
|
def block_start?(line)
|
@@ -94,10 +117,11 @@ module RuboCop
|
|
94
117
|
end
|
95
118
|
|
96
119
|
def message(node)
|
97
|
-
|
120
|
+
send_line = node.first_line
|
121
|
+
previous_line = processed_source[send_line - 2]
|
98
122
|
|
99
123
|
if block_start?(previous_line) ||
|
100
|
-
class_def?(
|
124
|
+
class_def?(send_line)
|
101
125
|
format(MSG_AFTER, modifier: node.loc.selector.source)
|
102
126
|
else
|
103
127
|
format(MSG_BEFORE_AND_AFTER, modifier: node.loc.selector.source)
|
@@ -24,12 +24,13 @@ module RuboCop
|
|
24
24
|
# The array of regular expressions representing percent literals that,
|
25
25
|
# if found within a percent literal expression, will cause a
|
26
26
|
# NestedPercentLiteral violation to be emitted.
|
27
|
-
|
27
|
+
PERCENT_LITERAL_TYPES = PreferredDelimiters::PERCENT_LITERAL_TYPES
|
28
|
+
REGEXES = PERCENT_LITERAL_TYPES.map do |percent_literal|
|
28
29
|
/\A#{percent_literal}\W/
|
29
30
|
end.freeze
|
30
31
|
|
31
32
|
def on_array(node)
|
32
|
-
process(node, *
|
33
|
+
process(node, *PERCENT_LITERAL_TYPES)
|
33
34
|
end
|
34
35
|
|
35
36
|
def on_percent_literal(node)
|
@@ -13,8 +13,18 @@ module RuboCop
|
|
13
13
|
check_code_length(node)
|
14
14
|
end
|
15
15
|
|
16
|
+
def on_casgn(node)
|
17
|
+
class_definition?(node) do
|
18
|
+
check_code_length(node)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
16
22
|
private
|
17
23
|
|
24
|
+
def_node_matcher :class_definition?, <<-PATTERN
|
25
|
+
(casgn nil? _ (block (send (const nil? :Class) :new) ...))
|
26
|
+
PATTERN
|
27
|
+
|
18
28
|
def message(length, max_length)
|
19
29
|
format('Class has too many lines. [%<length>d/%<max>d]',
|
20
30
|
length: length,
|
@@ -123,8 +123,8 @@ module RuboCop
|
|
123
123
|
|
124
124
|
def allowed_uri_position?(line, uri_range)
|
125
125
|
uri_range.begin < max &&
|
126
|
-
(uri_range.end ==
|
127
|
-
uri_range.end ==
|
126
|
+
(uri_range.end == line.length ||
|
127
|
+
uri_range.end == line.length - 1)
|
128
128
|
end
|
129
129
|
|
130
130
|
def find_excessive_uri_range(line)
|
@@ -13,8 +13,18 @@ module RuboCop
|
|
13
13
|
check_code_length(node)
|
14
14
|
end
|
15
15
|
|
16
|
+
def on_casgn(node)
|
17
|
+
module_definition?(node) do
|
18
|
+
check_code_length(node)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
16
22
|
private
|
17
23
|
|
24
|
+
def_node_matcher :module_definition?, <<-PATTERN
|
25
|
+
(casgn nil? _ (block (send (const nil? :Module) :new) ...))
|
26
|
+
PATTERN
|
27
|
+
|
18
28
|
def message(length, max_length)
|
19
29
|
format('Module has too many lines. [%<length>d/%<max>d]',
|
20
30
|
length: length,
|
@@ -18,9 +18,13 @@ module RuboCop
|
|
18
18
|
|
19
19
|
def check_code_length(node)
|
20
20
|
length = code_length(node)
|
21
|
+
|
21
22
|
return unless length > max_length
|
22
23
|
|
23
|
-
|
24
|
+
location = node.casgn_type? ? :name : :expression
|
25
|
+
|
26
|
+
add_offense(node, location: location,
|
27
|
+
message: message(length, max_length)) do
|
24
28
|
self.max = length
|
25
29
|
end
|
26
30
|
end
|
@@ -6,8 +6,6 @@ module RuboCop
|
|
6
6
|
module PercentLiteral
|
7
7
|
include RangeHelp
|
8
8
|
|
9
|
-
PERCENT_LITERAL_TYPES = %w[% %i %I %q %Q %r %s %w %W %x].freeze
|
10
|
-
|
11
9
|
private
|
12
10
|
|
13
11
|
def percent_literal?(node)
|
@@ -35,117 +33,6 @@ module RuboCop
|
|
35
33
|
def contents_range(node)
|
36
34
|
range_between(node.loc.begin.end_pos, node.loc.end.begin_pos)
|
37
35
|
end
|
38
|
-
|
39
|
-
# ['a', 'b', 'c'] => %w(a b c)
|
40
|
-
def correct_percent(node, char)
|
41
|
-
words = node.children
|
42
|
-
escape = words.any? { |w| needs_escaping?(w.children[0]) }
|
43
|
-
char = char.upcase if escape
|
44
|
-
delimiters = preferred_delimiters_for("%#{char}")
|
45
|
-
contents = new_contents(node, escape, delimiters)
|
46
|
-
|
47
|
-
lambda do |corrector|
|
48
|
-
corrector.replace(
|
49
|
-
node.source_range,
|
50
|
-
"%#{char}#{delimiters[0]}#{contents}#{delimiters[1]}"
|
51
|
-
)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def new_contents(node, escape, delimiters)
|
56
|
-
if node.multiline?
|
57
|
-
autocorrect_multiline_words(node, escape, delimiters)
|
58
|
-
else
|
59
|
-
autocorrect_words(node, escape, delimiters)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def autocorrect_multiline_words(node, escape, delimiters)
|
64
|
-
base_line_number = node.first_line
|
65
|
-
previous_line_number = base_line_number
|
66
|
-
contents = node.children.map.with_index do |word_node, index|
|
67
|
-
line_breaks = line_breaks(word_node,
|
68
|
-
node.source,
|
69
|
-
previous_line_number,
|
70
|
-
base_line_number,
|
71
|
-
index)
|
72
|
-
previous_line_number = word_node.first_line
|
73
|
-
content = escaped_content(word_node, escape, delimiters)
|
74
|
-
line_breaks + content
|
75
|
-
end
|
76
|
-
contents << end_content(node.source)
|
77
|
-
contents.join('')
|
78
|
-
end
|
79
|
-
|
80
|
-
def autocorrect_words(node, escape, delimiters)
|
81
|
-
node.children.map do |word_node|
|
82
|
-
content = word_node.children.first.to_s
|
83
|
-
content = escape ? escape_string(content) : content
|
84
|
-
delimiters.each do |delimiter|
|
85
|
-
content.gsub!(delimiter, "\\#{delimiter}")
|
86
|
-
end
|
87
|
-
content
|
88
|
-
end.join(' ')
|
89
|
-
end
|
90
|
-
|
91
|
-
def line_breaks(node, source, previous_line_num, base_line_num, node_idx)
|
92
|
-
source_in_lines = source.split("\n")
|
93
|
-
if node.first_line == previous_line_num
|
94
|
-
node_idx.zero? && node.first_line == base_line_num ? '' : ' '
|
95
|
-
else
|
96
|
-
begin_line_num = previous_line_num - base_line_num + 1
|
97
|
-
end_line_num = node.first_line - base_line_num + 1
|
98
|
-
lines = source_in_lines[begin_line_num...end_line_num]
|
99
|
-
"\n" + lines.join("\n").split(node.source).first
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def escaped_content(word_node, escape, delimiters)
|
104
|
-
content = word_node.children.first.to_s
|
105
|
-
content = escape_string(content) if escape
|
106
|
-
delimiters.each do |delimiter|
|
107
|
-
content.gsub!(delimiter, "\\#{delimiter}")
|
108
|
-
end
|
109
|
-
content
|
110
|
-
end
|
111
|
-
|
112
|
-
def end_content(source)
|
113
|
-
result = /\A(\s*)\]/.match(source.split("\n").last)
|
114
|
-
("\n" + result[1]) if result
|
115
|
-
end
|
116
|
-
|
117
|
-
def ensure_valid_preferred_delimiters
|
118
|
-
invalid = preferred_delimiters_config.keys -
|
119
|
-
(PERCENT_LITERAL_TYPES + %w[default])
|
120
|
-
return if invalid.empty?
|
121
|
-
|
122
|
-
raise ArgumentError,
|
123
|
-
"Invalid preferred delimiter config key: #{invalid.join(', ')}"
|
124
|
-
end
|
125
|
-
|
126
|
-
def preferred_delimiters
|
127
|
-
@preferred_delimiters ||=
|
128
|
-
begin
|
129
|
-
ensure_valid_preferred_delimiters
|
130
|
-
|
131
|
-
if preferred_delimiters_config.key?('default')
|
132
|
-
Hash[PERCENT_LITERAL_TYPES.map do |type|
|
133
|
-
[type, preferred_delimiters_config[type] ||
|
134
|
-
preferred_delimiters_config['default']]
|
135
|
-
end]
|
136
|
-
else
|
137
|
-
preferred_delimiters_config
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
def preferred_delimiters_config
|
143
|
-
@config.for_cop('Style/PercentLiteralDelimiters')['PreferredDelimiters']
|
144
|
-
end
|
145
|
-
|
146
|
-
def preferred_delimiters_for(type)
|
147
|
-
preferred_delimiters[type].split(//)
|
148
|
-
end
|
149
36
|
end
|
150
37
|
end
|
151
38
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for handling percent literal delimiters.
|
6
|
+
class PreferredDelimiters
|
7
|
+
attr_reader :type, :config
|
8
|
+
|
9
|
+
PERCENT_LITERAL_TYPES = %w[% %i %I %q %Q %r %s %w %W %x].freeze
|
10
|
+
|
11
|
+
def initialize(type, config, preferred_delimiters)
|
12
|
+
@type = type
|
13
|
+
@config = config
|
14
|
+
@preferred_delimiters = preferred_delimiters
|
15
|
+
end
|
16
|
+
|
17
|
+
def delimiters
|
18
|
+
preferred_delimiters[type].split(//)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def ensure_valid_preferred_delimiters
|
24
|
+
invalid = preferred_delimiters_config.keys -
|
25
|
+
(PERCENT_LITERAL_TYPES + %w[default])
|
26
|
+
return if invalid.empty?
|
27
|
+
|
28
|
+
raise ArgumentError,
|
29
|
+
"Invalid preferred delimiter config key: #{invalid.join(', ')}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def preferred_delimiters
|
33
|
+
@preferred_delimiters ||=
|
34
|
+
begin
|
35
|
+
ensure_valid_preferred_delimiters
|
36
|
+
|
37
|
+
if preferred_delimiters_config.key?('default')
|
38
|
+
Hash[PERCENT_LITERAL_TYPES.map do |type|
|
39
|
+
[type, preferred_delimiters_config[type] ||
|
40
|
+
preferred_delimiters_config['default']]
|
41
|
+
end]
|
42
|
+
else
|
43
|
+
preferred_delimiters_config
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def preferred_delimiters_config
|
49
|
+
config.for_cop('Style/PercentLiteralDelimiters')['PreferredDelimiters']
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
# @foo ||= calculate_expensive_thing(helper_variable)
|
44
44
|
# end
|
45
45
|
#
|
46
|
-
# @example EnforcedStyleForLeadingUnderscores
|
46
|
+
# @example EnforcedStyleForLeadingUnderscores: required
|
47
47
|
# # bad
|
48
48
|
# def foo
|
49
49
|
# @something ||= calculate_expensive_thing
|
@@ -35,7 +35,7 @@ module RuboCop
|
|
35
35
|
# foo.bar
|
36
36
|
# end
|
37
37
|
#
|
38
|
-
#
|
38
|
+
# @example EnforceForPrefixed: true (default)
|
39
39
|
# # bad
|
40
40
|
# def foo_bar
|
41
41
|
# foo.bar
|
@@ -44,7 +44,7 @@ module RuboCop
|
|
44
44
|
# # good
|
45
45
|
# delegate :bar, to: :foo, prefix: true
|
46
46
|
#
|
47
|
-
#
|
47
|
+
# @example EnforceForPrefixed: false
|
48
48
|
# # good
|
49
49
|
# def foo_bar
|
50
50
|
# foo.bar
|
@@ -23,6 +23,10 @@ module RuboCop
|
|
23
23
|
class HasManyOrHasOneDependent < Cop
|
24
24
|
MSG = 'Specify a `:dependent` option.'.freeze
|
25
25
|
|
26
|
+
def_node_search :active_resource_class?, <<-PATTERN
|
27
|
+
(const (const nil? :ActiveResource) :Base)
|
28
|
+
PATTERN
|
29
|
+
|
26
30
|
def_node_matcher :association_without_options?, <<-PATTERN
|
27
31
|
(send nil? {:has_many :has_one} _)
|
28
32
|
PATTERN
|
@@ -47,6 +51,8 @@ module RuboCop
|
|
47
51
|
PATTERN
|
48
52
|
|
49
53
|
def on_send(node)
|
54
|
+
return if active_resource?(node.parent)
|
55
|
+
|
50
56
|
unless association_without_options?(node)
|
51
57
|
return if valid_options?(association_with_options?(node))
|
52
58
|
end
|
@@ -88,6 +94,12 @@ module RuboCop
|
|
88
94
|
|
89
95
|
false
|
90
96
|
end
|
97
|
+
|
98
|
+
def active_resource?(node)
|
99
|
+
return false if node.nil?
|
100
|
+
|
101
|
+
active_resource_class?(node)
|
102
|
+
end
|
91
103
|
end
|
92
104
|
end
|
93
105
|
end
|
@@ -99,12 +99,37 @@ module RuboCop
|
|
99
99
|
|
100
100
|
def autocorrect_to_each(node)
|
101
101
|
item, enumerable = deconstruct_for(node)
|
102
|
-
replacement_range = replacement_range(node, node.loc.begin.end_pos)
|
103
|
-
correction = "#{enumerable.source}.each do |#{item.source}|"
|
104
102
|
|
103
|
+
end_pos = end_position(node, enumerable)
|
104
|
+
|
105
|
+
replacement_range = replacement_range(node, end_pos)
|
106
|
+
|
107
|
+
enum_source = enumerable_source(enumerable)
|
108
|
+
|
109
|
+
correction = "#{enum_source}.each do |#{item.source}|"
|
105
110
|
->(corrector) { corrector.replace(replacement_range, correction) }
|
106
111
|
end
|
107
112
|
|
113
|
+
def end_position(node, enumerable)
|
114
|
+
if node.do?
|
115
|
+
node.loc.begin.end_pos
|
116
|
+
elsif enumerable.begin_type?
|
117
|
+
enumerable.loc.end.end_pos
|
118
|
+
else
|
119
|
+
enumerable.loc.expression.end.end_pos
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def enumerable_source(enumerable)
|
124
|
+
return "(#{enumerable.source})" if wrap_into_parentheses?(enumerable)
|
125
|
+
|
126
|
+
enumerable.source
|
127
|
+
end
|
128
|
+
|
129
|
+
def wrap_into_parentheses?(enumerable)
|
130
|
+
enumerable.irange_type? || enumerable.erange_type?
|
131
|
+
end
|
132
|
+
|
108
133
|
def autocorrect_to_for(node)
|
109
134
|
enumerable, items = deconstruct_each(node)
|
110
135
|
variables = extract_variables(items)
|
@@ -31,8 +31,11 @@ module RuboCop
|
|
31
31
|
ASSIGNMENT_TYPES = %i[lvasgn casgn cvasgn
|
32
32
|
gvasgn ivasgn masgn].freeze
|
33
33
|
|
34
|
+
NAMED_CAPTURE = /\?<.+>/
|
35
|
+
|
34
36
|
def on_if(node)
|
35
37
|
return unless eligible_node?(node)
|
38
|
+
return if named_capture_in_condition?(node)
|
36
39
|
|
37
40
|
add_offense(node, location: :keyword,
|
38
41
|
message: format(MSG, keyword: node.keyword))
|
@@ -46,6 +49,10 @@ module RuboCop
|
|
46
49
|
|
47
50
|
private
|
48
51
|
|
52
|
+
def named_capture_in_condition?(node)
|
53
|
+
node.condition.match_with_lvasgn_type?
|
54
|
+
end
|
55
|
+
|
49
56
|
def eligible_node?(node)
|
50
57
|
!non_eligible_if?(node) && !node.chained? &&
|
51
58
|
!node.nested_conditional? && single_line_as_modifier?(node)
|
@@ -77,6 +77,12 @@ module RuboCop
|
|
77
77
|
add_offense(node)
|
78
78
|
end
|
79
79
|
|
80
|
+
def preferred_delimiters_for(type)
|
81
|
+
PreferredDelimiters
|
82
|
+
.new(type, @config, @preferred_delimiters)
|
83
|
+
.delimiters
|
84
|
+
end
|
85
|
+
|
80
86
|
def uses_preferred_delimiter?(node, type)
|
81
87
|
preferred_delimiters_for(type)[0] == begin_source(node)[-1]
|
82
88
|
end
|
@@ -39,14 +39,18 @@ module RuboCop
|
|
39
39
|
exprs_lines = exprs.map { |e| e.source_range.line }
|
40
40
|
lines = exprs_lines.group_by { |i| i }
|
41
41
|
|
42
|
-
# every line with more than 1 expression on it is an offense
|
43
42
|
lines.each do |line, expr_on_line|
|
43
|
+
# Every line with more than one expression on it is a
|
44
|
+
# potential offense
|
44
45
|
next unless expr_on_line.size > 1
|
45
46
|
|
46
47
|
# TODO: Find the correct position of the semicolon. We don't know
|
47
48
|
# if the first semicolon on the line is a separator of
|
48
49
|
# expressions. It's just a guess.
|
49
50
|
column = @processed_source[line - 1].index(';')
|
51
|
+
|
52
|
+
next unless column
|
53
|
+
|
50
54
|
convention_on(line, column, false)
|
51
55
|
end
|
52
56
|
end
|
@@ -31,7 +31,6 @@ module RuboCop
|
|
31
31
|
include ArrayMinSize
|
32
32
|
include ArraySyntax
|
33
33
|
include ConfigurableEnforcedStyle
|
34
|
-
include PercentLiteral
|
35
34
|
include PercentArray
|
36
35
|
|
37
36
|
PERCENT_MSG = 'Use `%i` or `%I` for an array of symbols.'.freeze
|
@@ -53,7 +52,9 @@ module RuboCop
|
|
53
52
|
|
54
53
|
def autocorrect(node)
|
55
54
|
if style == :percent
|
56
|
-
|
55
|
+
PercentLiteralCorrector
|
56
|
+
.new(@config, @preferred_delimiters)
|
57
|
+
.correct(node, 'i')
|
57
58
|
else
|
58
59
|
correct_bracketed(node)
|
59
60
|
end
|
@@ -32,7 +32,6 @@ module RuboCop
|
|
32
32
|
include ArraySyntax
|
33
33
|
include ConfigurableEnforcedStyle
|
34
34
|
include PercentArray
|
35
|
-
include PercentLiteral
|
36
35
|
|
37
36
|
PERCENT_MSG = 'Use `%w` or `%W` for an array of words.'.freeze
|
38
37
|
ARRAY_MSG = 'Use `[]` for an array of words.'.freeze
|
@@ -53,7 +52,9 @@ module RuboCop
|
|
53
52
|
|
54
53
|
def autocorrect(node)
|
55
54
|
if style == :percent
|
56
|
-
|
55
|
+
PercentLiteralCorrector
|
56
|
+
.new(@config, @preferred_delimiters)
|
57
|
+
.correct(node, 'w')
|
57
58
|
else
|
58
59
|
correct_bracketed(node)
|
59
60
|
end
|
@@ -50,6 +50,8 @@ module RuboCop
|
|
50
50
|
|
51
51
|
lhs, opr, rhs = zero_length_predicate
|
52
52
|
|
53
|
+
return if non_polymorphic_collection?(node)
|
54
|
+
|
53
55
|
add_offense(
|
54
56
|
node,
|
55
57
|
message: format(ZERO_MSG, lhs: lhs, opr: opr, rhs: rhs)
|
@@ -63,6 +65,8 @@ module RuboCop
|
|
63
65
|
|
64
66
|
lhs, opr, rhs = nonzero_length_predicate
|
65
67
|
|
68
|
+
return if non_polymorphic_collection?(node)
|
69
|
+
|
66
70
|
add_offense(
|
67
71
|
node,
|
68
72
|
message: format(NONZERO_MSG, lhs: lhs, opr: opr, rhs: rhs)
|
@@ -99,6 +103,14 @@ module RuboCop
|
|
99
103
|
{(send (send $_ _) _ _)
|
100
104
|
(send _ _ (send $_ _))}
|
101
105
|
PATTERN
|
106
|
+
|
107
|
+
# Some collection like objects in the Ruby standard library
|
108
|
+
# implement `#size`, but not `#empty`. We ignore those to
|
109
|
+
# reduce false positives.
|
110
|
+
def_node_matcher :non_polymorphic_collection?, <<-PATTERN
|
111
|
+
{(send (send (send (const nil? :File) :stat _) ...) ...)
|
112
|
+
(send (send (send (const nil? {:Tempfile :StringIO}) {:new :open} ...) ...) ...)}
|
113
|
+
PATTERN
|
102
114
|
end
|
103
115
|
end
|
104
116
|
end
|
data/lib/rubocop/version.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
# This module holds the RuboCop version information.
|
5
5
|
module Version
|
6
|
-
STRING = '0.59.
|
6
|
+
STRING = '0.59.2'.freeze
|
7
7
|
|
8
8
|
MSG = '%<version>s (using Parser %<parser_version>s, running on ' \
|
9
9
|
'%<ruby_engine>s %<ruby_version>s %<ruby_platform>s)'.freeze
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.59.
|
4
|
+
version: 0.59.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2018-09-
|
13
|
+
date: 2018-09-24 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: jaro_winkler
|
@@ -239,6 +239,7 @@ files:
|
|
239
239
|
- lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb
|
240
240
|
- lib/rubocop/cop/correctors/ordered_gem_corrector.rb
|
241
241
|
- lib/rubocop/cop/correctors/parentheses_corrector.rb
|
242
|
+
- lib/rubocop/cop/correctors/percent_literal_corrector.rb
|
242
243
|
- lib/rubocop/cop/correctors/punctuation_corrector.rb
|
243
244
|
- lib/rubocop/cop/correctors/space_corrector.rb
|
244
245
|
- lib/rubocop/cop/correctors/string_literal_corrector.rb
|
@@ -466,6 +467,7 @@ files:
|
|
466
467
|
- lib/rubocop/cop/mixin/percent_array.rb
|
467
468
|
- lib/rubocop/cop/mixin/percent_literal.rb
|
468
469
|
- lib/rubocop/cop/mixin/preceding_following_alignment.rb
|
470
|
+
- lib/rubocop/cop/mixin/preferred_delimiters.rb
|
469
471
|
- lib/rubocop/cop/mixin/range_help.rb
|
470
472
|
- lib/rubocop/cop/mixin/rescue_node.rb
|
471
473
|
- lib/rubocop/cop/mixin/safe_assignment.rb
|
@@ -799,10 +801,10 @@ homepage: https://github.com/rubocop-hq/rubocop
|
|
799
801
|
licenses:
|
800
802
|
- MIT
|
801
803
|
metadata:
|
802
|
-
homepage_uri:
|
804
|
+
homepage_uri: https://www.rubocop.org/
|
803
805
|
changelog_uri: https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md
|
804
806
|
source_code_uri: https://github.com/rubocop-hq/rubocop/
|
805
|
-
documentation_uri:
|
807
|
+
documentation_uri: https://docs.rubocop.org/
|
806
808
|
bug_tracker_uri: https://github.com/rubocop-hq/rubocop/issues
|
807
809
|
post_install_message:
|
808
810
|
rdoc_options: []
|