rubocop 0.84.0 → 0.85.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +33 -15
- data/lib/rubocop.rb +6 -0
- data/lib/rubocop/cli.rb +2 -2
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +2 -2
- data/lib/rubocop/comment_config.rb +1 -1
- data/lib/rubocop/config.rb +3 -1
- data/lib/rubocop/config_loader.rb +1 -1
- data/lib/rubocop/config_loader_resolver.rb +18 -2
- data/lib/rubocop/config_store.rb +12 -2
- data/lib/rubocop/cop/bundler/gem_comment.rb +70 -1
- data/lib/rubocop/cop/commissioner.rb +0 -21
- data/lib/rubocop/cop/cop.rb +14 -6
- data/lib/rubocop/cop/corrector.rb +3 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +3 -1
- data/lib/rubocop/cop/layout/case_indentation.rb +3 -3
- data/lib/rubocop/cop/layout/class_structure.rb +19 -16
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -2
- data/lib/rubocop/cop/layout/end_of_line.rb +2 -2
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/hash_alignment.rb +6 -6
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +19 -102
- data/lib/rubocop/cop/layout/line_length.rb +17 -17
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +3 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +3 -1
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +3 -1
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +2 -1
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +8 -4
- data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -1
- data/lib/rubocop/cop/lint/loop.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +62 -0
- data/lib/rubocop/cop/lint/nested_percent_literal.rb +1 -1
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +7 -7
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -1
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +3 -3
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
- data/lib/rubocop/cop/lint/suppressed_exception.rb +4 -2
- data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
- data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -1
- data/lib/rubocop/cop/migration/department_name.rb +9 -5
- data/lib/rubocop/cop/mixin/array_min_size.rb +3 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +3 -1
- data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -1
- data/lib/rubocop/cop/mixin/ignored_pattern.rb +1 -1
- data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +3 -1
- data/lib/rubocop/cop/mixin/regexp_literal_help.rb +16 -0
- data/lib/rubocop/cop/mixin/surrounding_space.rb +3 -1
- data/lib/rubocop/cop/mixin/uncommunicative_name.rb +1 -1
- data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +11 -1
- data/lib/rubocop/cop/naming/file_name.rb +26 -11
- data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
- data/lib/rubocop/cop/registry.rb +3 -1
- data/lib/rubocop/cop/style/array_join.rb +1 -1
- data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -1
- data/lib/rubocop/cop/style/copyright.rb +2 -2
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/exponential_notation.rb +3 -3
- data/lib/rubocop/cop/style/format_string_token.rb +2 -3
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -2
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +5 -3
- data/lib/rubocop/cop/style/inline_comment.rb +1 -1
- data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
- data/lib/rubocop/cop/style/negated_if.rb +3 -3
- data/lib/rubocop/cop/style/negated_unless.rb +3 -3
- data/lib/rubocop/cop/style/non_nil_check.rb +1 -1
- data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +89 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +130 -0
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +3 -3
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +3 -3
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +13 -13
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +3 -3
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
- data/lib/rubocop/cop/style/unless_else.rb +1 -1
- data/lib/rubocop/cop/style/when_then.rb +1 -1
- data/lib/rubocop/cop/team.rb +61 -25
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/branch.rb +3 -1
- data/lib/rubocop/formatter/junit_formatter.rb +14 -4
- data/lib/rubocop/magic_comment.rb +1 -1
- data/lib/rubocop/options.rb +17 -3
- data/lib/rubocop/result_cache.rb +4 -4
- data/lib/rubocop/rspec/cop_helper.rb +2 -23
- data/lib/rubocop/rspec/expect_offense.rb +42 -6
- data/lib/rubocop/rspec/shared_contexts.rb +2 -2
- data/lib/rubocop/runner.rb +14 -10
- data/lib/rubocop/target_finder.rb +3 -1
- data/lib/rubocop/target_ruby.rb +4 -1
- data/lib/rubocop/version.rb +1 -1
- metadata +21 -3
@@ -49,25 +49,36 @@ module RuboCop
|
|
49
49
|
|
50
50
|
def for_bad_filename(file_path)
|
51
51
|
basename = File.basename(file_path)
|
52
|
-
msg = if filename_good?(basename)
|
53
|
-
return if matching_definition?(file_path)
|
54
52
|
|
55
|
-
|
56
|
-
|
57
|
-
|
53
|
+
if filename_good?(basename)
|
54
|
+
msg = perform_class_and_module_naming_checks(file_path, basename)
|
55
|
+
else
|
56
|
+
msg = other_message(basename) unless bad_filename_allowed?
|
57
|
+
end
|
58
58
|
|
59
|
-
|
60
|
-
|
59
|
+
yield source_range(processed_source.buffer, 1, 0), msg if msg
|
60
|
+
end
|
61
61
|
|
62
|
-
|
62
|
+
def perform_class_and_module_naming_checks(file_path, basename)
|
63
|
+
return unless expect_matching_definition?
|
64
|
+
|
65
|
+
if check_definition_path_hierarchy? &&
|
66
|
+
!matching_definition?(file_path)
|
67
|
+
msg = no_definition_message(basename, file_path)
|
68
|
+
elsif !matching_class?(basename)
|
69
|
+
msg = no_definition_message(basename, basename)
|
70
|
+
end
|
71
|
+
msg
|
63
72
|
end
|
64
73
|
|
65
74
|
def matching_definition?(file_path)
|
66
|
-
return true unless expect_matching_definition?
|
67
|
-
|
68
75
|
find_class_or_module(processed_source.ast, to_namespace(file_path))
|
69
76
|
end
|
70
77
|
|
78
|
+
def matching_class?(file_name)
|
79
|
+
find_class_or_module(processed_source.ast, to_namespace(file_name))
|
80
|
+
end
|
81
|
+
|
71
82
|
def bad_filename_allowed?
|
72
83
|
ignore_executable_scripts? && processed_source.start_with?('#!')
|
73
84
|
end
|
@@ -94,6 +105,10 @@ module RuboCop
|
|
94
105
|
cop_config['ExpectMatchingDefinition']
|
95
106
|
end
|
96
107
|
|
108
|
+
def check_definition_path_hierarchy?
|
109
|
+
cop_config['CheckDefinitionPathHierarchy']
|
110
|
+
end
|
111
|
+
|
97
112
|
def regex
|
98
113
|
cop_config['Regex']
|
99
114
|
end
|
@@ -104,7 +119,7 @@ module RuboCop
|
|
104
119
|
|
105
120
|
def filename_good?(basename)
|
106
121
|
basename = basename.sub(/^\./, '')
|
107
|
-
basename = basename.sub(/\.[
|
122
|
+
basename = basename.sub(/\.[^.]+$/, '')
|
108
123
|
# special handling for Action Pack Variants file names like
|
109
124
|
# some_file.xlsx+mobile.axlsx
|
110
125
|
basename = basename.sub('+', '_')
|
@@ -67,7 +67,7 @@ module RuboCop
|
|
67
67
|
private
|
68
68
|
|
69
69
|
def allowed_method_name?(method_name, prefix)
|
70
|
-
!method_name.match(/^#{prefix}[^0-9]/) ||
|
70
|
+
!method_name.match?(/^#{prefix}[^0-9]/) ||
|
71
71
|
method_name == expected_name(method_name, prefix) ||
|
72
72
|
method_name.end_with?('=') ||
|
73
73
|
allowed_methods.include?(method_name)
|
data/lib/rubocop/cop/registry.rb
CHANGED
@@ -112,7 +112,9 @@ module RuboCop
|
|
112
112
|
|
113
113
|
def print_warning(name, path)
|
114
114
|
message = "#{path}: Warning: no department given for #{name}."
|
115
|
-
|
115
|
+
if path.end_with?('.rb')
|
116
|
+
message += ' Run `rubocop -a --only Migration/DepartmentName` to fix.'
|
117
|
+
end
|
116
118
|
warn message
|
117
119
|
end
|
118
120
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# This cop checks for uses of "
|
6
|
+
# This cop checks for uses of "*" as a substitute for _join_.
|
7
7
|
#
|
8
8
|
# Not all cases can reliably checked, due to Ruby's dynamic
|
9
9
|
# types, so we consider only cases when the first argument is an
|
@@ -8,8 +8,8 @@ module RuboCop
|
|
8
8
|
# The default regexp for an acceptable copyright notice can be found in
|
9
9
|
# config/default.yml. The default can be changed as follows:
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# Style/Copyright:
|
12
|
+
# Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc'
|
13
13
|
#
|
14
14
|
# This regex string is treated as an unanchored regex. For each file
|
15
15
|
# that RuboCop scans, a comment that matches this regex must be found or
|
@@ -8,7 +8,7 @@ module RuboCop
|
|
8
8
|
# line (compact style), but it can be configured to enforce the `end`
|
9
9
|
# to go on its own line (expanded style).
|
10
10
|
#
|
11
|
-
#
|
11
|
+
# NOTE: A method definition is not considered empty if it contains
|
12
12
|
# comments.
|
13
13
|
#
|
14
14
|
# @example EnforcedStyle: compact (default)
|
@@ -5,12 +5,12 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# This cop enforces consistency when using exponential notation
|
7
7
|
# for numbers in the code (eg 1.2e4). Different styles are supported:
|
8
|
-
#
|
8
|
+
# * `scientific` which enforces a mantissa between 1 (inclusive)
|
9
9
|
# and 10 (exclusive).
|
10
|
-
#
|
10
|
+
# * `engineering` which enforces the exponent to be a multiple of 3
|
11
11
|
# and the mantissa to be between 0.1 (inclusive)
|
12
12
|
# and 10 (exclusive).
|
13
|
-
#
|
13
|
+
# * `integral` which enforces the mantissa to always be a whole number
|
14
14
|
# without trailing zeroes.
|
15
15
|
#
|
16
16
|
# @example EnforcedStyle: scientific (default)
|
@@ -5,11 +5,10 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# Use a consistent style for named format string tokens.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
# `unannotated` style cop only works for strings
|
8
|
+
# NOTE: `unannotated` style cop only works for strings
|
10
9
|
# which are passed as arguments to those methods:
|
11
10
|
# `printf`, `sprintf`, `format`, `%`.
|
12
|
-
# The reason is that
|
11
|
+
# The reason is that _unannotated_ format is very similar
|
13
12
|
# to encoded URLs or Date/Time formatting strings.
|
14
13
|
#
|
15
14
|
# @example EnforcedStyle: annotated (default)
|
@@ -8,8 +8,7 @@ module RuboCop
|
|
8
8
|
# It will add the comment `# frozen_string_literal: true` to the top of
|
9
9
|
# files to enable frozen string literals. Frozen string literals may be
|
10
10
|
# default in future Ruby. The comment will be added below a shebang and
|
11
|
-
# encoding comment.
|
12
|
-
# Ruby 2.3+.
|
11
|
+
# encoding comment.
|
13
12
|
#
|
14
13
|
# Note that the cop will ignore files where the comment exists but is set
|
15
14
|
# to `false` instead of `true`.
|
@@ -5,7 +5,7 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# This cop checks for uses of `each_key` and `each_value` Hash methods.
|
7
7
|
#
|
8
|
-
#
|
8
|
+
# NOTE: If you have an array of two-element arrays, you can put
|
9
9
|
# parentheses around the block arguments to indicate that you're not
|
10
10
|
# working with a hash, and suppress RuboCop offenses.
|
11
11
|
#
|
@@ -13,11 +13,11 @@ module RuboCop
|
|
13
13
|
# The supported styles are:
|
14
14
|
#
|
15
15
|
# * ruby19 - forces use of the 1.9 syntax (e.g. `{a: 1}`) when hashes have
|
16
|
-
#
|
16
|
+
# all symbols for keys
|
17
17
|
# * hash_rockets - forces use of hash rockets for all hashes
|
18
18
|
# * no_mixed_keys - simply checks for hashes with mixed syntaxes
|
19
19
|
# * ruby19_no_mixed_keys - forces use of ruby 1.9 syntax and forbids mixed
|
20
|
-
#
|
20
|
+
# syntax hashes
|
21
21
|
#
|
22
22
|
# @example EnforcedStyle: ruby19 (default)
|
23
23
|
# # bad
|
@@ -178,7 +178,9 @@ module RuboCop
|
|
178
178
|
)
|
179
179
|
|
180
180
|
hash_node = pair_node.parent
|
181
|
-
|
181
|
+
return unless hash_node.parent&.return_type? && !hash_node.braces?
|
182
|
+
|
183
|
+
corrector.wrap(hash_node, '{', '}')
|
182
184
|
end
|
183
185
|
|
184
186
|
def range_for_autocorrect_ruby19(pair_node)
|
@@ -23,7 +23,7 @@ module RuboCop
|
|
23
23
|
def investigate(processed_source)
|
24
24
|
processed_source.each_comment do |comment|
|
25
25
|
next if comment_line?(processed_source[comment.loc.line - 1]) ||
|
26
|
-
comment.text.match(/\A# rubocop:(enable|disable)/)
|
26
|
+
comment.text.match?(/\A# rubocop:(enable|disable)/)
|
27
27
|
|
28
28
|
add_offense(comment)
|
29
29
|
end
|
@@ -6,9 +6,9 @@ module RuboCop
|
|
6
6
|
# Checks for uses of if with a negated condition. Only ifs
|
7
7
|
# without else are considered. There are three different styles:
|
8
8
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
9
|
+
# * both
|
10
|
+
# * prefix
|
11
|
+
# * postfix
|
12
12
|
#
|
13
13
|
# @example EnforcedStyle: both (default)
|
14
14
|
# # enforces `unless` for `prefix` and `postfix` conditionals
|
@@ -6,9 +6,9 @@ module RuboCop
|
|
6
6
|
# Checks for uses of unless with a negated condition. Only unless
|
7
7
|
# without else are considered. There are three different styles:
|
8
8
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
9
|
+
# * both
|
10
|
+
# * prefix
|
11
|
+
# * postfix
|
12
12
|
#
|
13
13
|
# @example EnforcedStyle: both (default)
|
14
14
|
# # enforces `if` for `prefix` and `postfix` conditionals
|
@@ -11,7 +11,7 @@ module RuboCop
|
|
11
11
|
#
|
12
12
|
# With `IncludeSemanticChanges` set to `true`, this cop reports offenses
|
13
13
|
# for `!x.nil?` and autocorrects that and `x != nil` to solely `x`, which
|
14
|
-
# is
|
14
|
+
# is *usually* OK, but might change behavior.
|
15
15
|
#
|
16
16
|
# @example
|
17
17
|
# # bad
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for unnecessary single-element Regexp character classes.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
# r = /[x]/
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# r = /x/
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# r = /[\s]/
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# r = /\s/
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# r = /[ab]/
|
24
|
+
class RedundantRegexpCharacterClass < Cop
|
25
|
+
include MatchRange
|
26
|
+
include RegexpLiteralHelp
|
27
|
+
|
28
|
+
MSG_REDUNDANT_CHARACTER_CLASS = 'Redundant single-element character class, ' \
|
29
|
+
'`%<char_class>s` can be replaced with `%<element>s`.'
|
30
|
+
|
31
|
+
PATTERN = /
|
32
|
+
(
|
33
|
+
(?<!\\) # No \-prefix (i.e. not escaped)
|
34
|
+
\[ # Literal [
|
35
|
+
(?!\#\{) # Not (the start of) an interpolation
|
36
|
+
(?: # Either...
|
37
|
+
\\. | # Any escaped character
|
38
|
+
[^.*+?{}()|$] | # or one that doesn't require escaping outside the character class
|
39
|
+
\\[upP]\{[^}]+\} # or a unicode code-point or property
|
40
|
+
)
|
41
|
+
\] # Literal ]
|
42
|
+
)
|
43
|
+
/x.freeze
|
44
|
+
|
45
|
+
def on_regexp(node)
|
46
|
+
each_redundant_character_class(node) do |loc|
|
47
|
+
next if whitespace_in_free_space_mode?(node, loc)
|
48
|
+
|
49
|
+
add_offense(
|
50
|
+
node,
|
51
|
+
location: loc,
|
52
|
+
message: format(
|
53
|
+
MSG_REDUNDANT_CHARACTER_CLASS,
|
54
|
+
char_class: loc.source,
|
55
|
+
element: without_character_class(loc)
|
56
|
+
)
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def autocorrect(node)
|
62
|
+
lambda do |corrector|
|
63
|
+
each_redundant_character_class(node) do |loc|
|
64
|
+
corrector.replace(loc, without_character_class(loc))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def each_redundant_character_class(node)
|
70
|
+
each_match_range(node.loc.expression, PATTERN) do |loc|
|
71
|
+
yield loc
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def without_character_class(loc)
|
78
|
+
loc.source[1..-2]
|
79
|
+
end
|
80
|
+
|
81
|
+
def whitespace_in_free_space_mode?(node, loc)
|
82
|
+
return false unless freespace_mode_regexp?(node)
|
83
|
+
|
84
|
+
/\[\s\]/.match?(loc.source)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for redundant escapes inside Regexp literals.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# %r{foo\/bar}
|
11
|
+
#
|
12
|
+
# # good
|
13
|
+
# %r{foo/bar}
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# /foo\/bar/
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# %r/foo\/bar/
|
20
|
+
#
|
21
|
+
# # bad
|
22
|
+
# /a\-b/
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# /a-b/
|
26
|
+
#
|
27
|
+
# # bad
|
28
|
+
# /[\+\-]\d/
|
29
|
+
#
|
30
|
+
# # good
|
31
|
+
# /[+\-]\d/
|
32
|
+
class RedundantRegexpEscape < Cop
|
33
|
+
include RangeHelp
|
34
|
+
include RegexpLiteralHelp
|
35
|
+
|
36
|
+
MSG_REDUNDANT_ESCAPE = 'Redundant escape inside regexp literal'
|
37
|
+
|
38
|
+
ALLOWED_ALWAYS_ESCAPES = ' []^\\#'.chars.freeze
|
39
|
+
ALLOWED_WITHIN_CHAR_CLASS_METACHAR_ESCAPES = '-'.chars.freeze
|
40
|
+
ALLOWED_OUTSIDE_CHAR_CLASS_METACHAR_ESCAPES = '.*+?{}()|$'.chars.freeze
|
41
|
+
|
42
|
+
def on_regexp(node)
|
43
|
+
each_escape(node) do |char, index, within_character_class|
|
44
|
+
next if allowed_escape?(node, char, within_character_class)
|
45
|
+
|
46
|
+
add_offense(
|
47
|
+
node,
|
48
|
+
location: escape_range_at_index(node, index),
|
49
|
+
message: MSG_REDUNDANT_ESCAPE
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def autocorrect(node)
|
55
|
+
lambda do |corrector|
|
56
|
+
each_escape(node) do |char, index, within_character_class|
|
57
|
+
next if allowed_escape?(node, char, within_character_class)
|
58
|
+
|
59
|
+
corrector.remove_leading(escape_range_at_index(node, index), 1)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def slash_literal?(node)
|
67
|
+
['/', '%r/'].include?(node.loc.begin.source)
|
68
|
+
end
|
69
|
+
|
70
|
+
def allowed_escape?(node, char, within_character_class)
|
71
|
+
# Strictly speaking a few single-letter metachars are currently
|
72
|
+
# unnecessary to "escape", e.g. g, i, E, F, but enumerating them is
|
73
|
+
# rather difficult, and their behaviour could change over time with
|
74
|
+
# different versions of Ruby so that e.g. /\g/ != /g/
|
75
|
+
return true if /[[:alnum:]]/.match?(char)
|
76
|
+
return true if ALLOWED_ALWAYS_ESCAPES.include?(char)
|
77
|
+
|
78
|
+
if char == '/'
|
79
|
+
slash_literal?(node)
|
80
|
+
elsif within_character_class
|
81
|
+
ALLOWED_WITHIN_CHAR_CLASS_METACHAR_ESCAPES.include?(char)
|
82
|
+
else
|
83
|
+
ALLOWED_OUTSIDE_CHAR_CLASS_METACHAR_ESCAPES.include?(char)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def each_escape(node)
|
88
|
+
pattern_source(node).each_char.with_index.reduce(
|
89
|
+
[nil, false]
|
90
|
+
) do |(previous, within_character_class), (current, index)|
|
91
|
+
if previous == '\\'
|
92
|
+
yield [current, index - 1, within_character_class]
|
93
|
+
|
94
|
+
[nil, within_character_class]
|
95
|
+
elsif previous == '[' && current != ':'
|
96
|
+
[current, true]
|
97
|
+
elsif previous != ':' && current == ']'
|
98
|
+
[current, false]
|
99
|
+
else
|
100
|
+
[current, within_character_class]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def escape_range_at_index(node, index)
|
106
|
+
regexp_begin = node.loc.begin.end_pos
|
107
|
+
|
108
|
+
start = regexp_begin + index
|
109
|
+
|
110
|
+
range_between(start, start + 2)
|
111
|
+
end
|
112
|
+
|
113
|
+
def pattern_source(node)
|
114
|
+
freespace_mode = freespace_mode_regexp?(node)
|
115
|
+
|
116
|
+
node.children.reject(&:regopt_type?).map do |child|
|
117
|
+
source = child.source
|
118
|
+
|
119
|
+
if freespace_mode
|
120
|
+
# Remove comments to avoid misleading results
|
121
|
+
source.sub(/(?<!\\)#.*/, '')
|
122
|
+
else
|
123
|
+
source
|
124
|
+
end
|
125
|
+
end.join
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|