rubocop-rails 2.29.0 → 2.31.0
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 +9 -7
- data/config/default.yml +18 -2
- data/lib/rubocop/cop/mixin/active_record_helper.rb +2 -2
- data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +2 -2
- data/lib/rubocop/cop/mixin/database_type_resolvable.rb +2 -2
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +6 -1
- data/lib/rubocop/cop/mixin/index_method.rb +66 -65
- data/lib/rubocop/cop/rails/arel_star.rb +5 -5
- data/lib/rubocop/cop/rails/belongs_to.rb +1 -1
- data/lib/rubocop/cop/rails/blank.rb +1 -1
- data/lib/rubocop/cop/rails/content_tag.rb +1 -1
- data/lib/rubocop/cop/rails/delegate.rb +53 -7
- data/lib/rubocop/cop/rails/duplicate_association.rb +8 -4
- data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +1 -3
- data/lib/rubocop/cop/rails/file_path.rb +58 -9
- data/lib/rubocop/cop/rails/index_by.rb +9 -0
- data/lib/rubocop/cop/rails/index_with.rb +9 -0
- data/lib/rubocop/cop/rails/inquiry.rb +1 -1
- data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +11 -1
- data/lib/rubocop/cop/rails/output.rb +1 -2
- data/lib/rubocop/cop/rails/pluck.rb +11 -5
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -1
- data/lib/rubocop/cop/rails/presence.rb +1 -1
- data/lib/rubocop/cop/rails/present.rb +1 -1
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +6 -1
- data/lib/rubocop/cop/rails/reflection_class_name.rb +2 -2
- data/lib/rubocop/cop/rails/relative_date_constant.rb +1 -1
- data/lib/rubocop/cop/rails/reversible_migration.rb +2 -1
- data/lib/rubocop/cop/rails/root_pathname_methods.rb +6 -1
- data/lib/rubocop/cop/rails/save_bang.rb +7 -6
- data/lib/rubocop/cop/rails/schema_comment.rb +1 -1
- data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -1
- data/lib/rubocop/cop/rails/strip_heredoc.rb +1 -1
- data/lib/rubocop/cop/rails/strong_parameters_expect.rb +2 -2
- data/lib/rubocop/cop/rails/transaction_exit_statement.rb +2 -2
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +10 -33
- data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -1
- data/lib/rubocop/rails/plugin.rb +48 -0
- data/lib/rubocop/rails/version.rb +1 -1
- data/lib/rubocop/rails.rb +1 -7
- data/lib/rubocop-rails.rb +1 -5
- metadata +23 -8
- data/lib/rubocop/rails/inject.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba4876948bedd432dc186a3c060c26c3808f1c7126b8fe69072e056a5f160d94
|
4
|
+
data.tar.gz: 7f890ec180a125abe4a40ad146661e71c088596eb093eacf12d322135c7f6907
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 719fd043fd8ae7738eebb0c78abba01a23f2bc30c6d8c9825c89c7cbcc6cd48fd0077918e9bc84c9c471afecd62b69597d3f046c757606ecaec4af9daf8ef183
|
7
|
+
data.tar.gz: b7173eeaf159ee8673fe2f2c16a1c92bcbb55601d1202db18e5b48d09d1d1ef0207c17a182dcfb2b39c6e686d2b82871b191d5f90c4416a1af7d7b038a12c218
|
data/README.md
CHANGED
@@ -5,7 +5,8 @@
|
|
5
5
|
|
6
6
|
A [RuboCop](https://github.com/rubocop/rubocop) extension focused on enforcing Rails best practices and coding conventions.
|
7
7
|
|
8
|
-
|
8
|
+
> [!IMPORTANT]
|
9
|
+
> This repository manages rubocop-rails gem (>= 2.0.0). rubocop-rails gem (<= 1.5.0) has been renamed to [rubocop-rails_config](https://rubygems.org/gems/rubocop-rails_config) gem.
|
9
10
|
|
10
11
|
## Installation
|
11
12
|
|
@@ -31,13 +32,13 @@ ways to do this:
|
|
31
32
|
Put this into your `.rubocop.yml`.
|
32
33
|
|
33
34
|
```yaml
|
34
|
-
|
35
|
+
plugins: rubocop-rails
|
35
36
|
```
|
36
37
|
|
37
38
|
Alternatively, use the following array notation when specifying multiple extensions.
|
38
39
|
|
39
40
|
```yaml
|
40
|
-
|
41
|
+
plugins:
|
41
42
|
- rubocop-other-extension
|
42
43
|
- rubocop-rails
|
43
44
|
```
|
@@ -45,21 +46,22 @@ require:
|
|
45
46
|
Now you can run `rubocop` and it will automatically load the RuboCop Rails
|
46
47
|
cops together with the standard cops.
|
47
48
|
|
49
|
+
> [!NOTE]
|
50
|
+
> The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`.
|
51
|
+
|
48
52
|
### Command line
|
49
53
|
|
50
54
|
```sh
|
51
|
-
$ rubocop --
|
55
|
+
$ rubocop --plugin rubocop-rails
|
52
56
|
```
|
53
57
|
|
54
|
-
Note: `--rails` option is required while `rubocop` command supports `--rails` option.
|
55
|
-
|
56
58
|
### Rake task
|
57
59
|
|
58
60
|
```ruby
|
59
61
|
require 'rubocop/rake_task'
|
60
62
|
|
61
63
|
RuboCop::RakeTask.new do |task|
|
62
|
-
task.
|
64
|
+
task.plugins << 'rubocop-rails'
|
63
65
|
end
|
64
66
|
```
|
65
67
|
|
data/config/default.yml
CHANGED
@@ -28,7 +28,7 @@ AllCops:
|
|
28
28
|
# By specifying `MigratedSchemaVersion` option, migration files that have been migrated can be ignored.
|
29
29
|
# When `MigratedSchemaVersion: '20241231000000'` is set. Migration files lower than or equal to '20250101000000' will be ignored.
|
30
30
|
# For example, this is the timestamp in db/migrate/20250101000000_create_articles.rb.
|
31
|
-
MigratedSchemaVersion:
|
31
|
+
MigratedSchemaVersion: '19700101000000' # NOTE: Used as a sentinel value for the UNIX epoch time.
|
32
32
|
|
33
33
|
Lint/NumberConversion:
|
34
34
|
# Add Rails' duration methods to the ignore list for `Lint/NumberConversion`
|
@@ -77,6 +77,20 @@ Lint/SafeNavigationChain:
|
|
77
77
|
- try!
|
78
78
|
- in?
|
79
79
|
|
80
|
+
Lint/UselessAccessModifier:
|
81
|
+
# Add methods from `ActiveSupport::Concern` and `Module::Concerning`:
|
82
|
+
# https://api.rubyonrails.org/classes/ActiveSupport/Concern.html
|
83
|
+
# https://api.rubyonrails.org/classes/Module/Concerning
|
84
|
+
inherit_mode:
|
85
|
+
merge:
|
86
|
+
- ContextCreatingMethods
|
87
|
+
ContextCreatingMethods:
|
88
|
+
- class_methods
|
89
|
+
- included
|
90
|
+
- prepended
|
91
|
+
- concern
|
92
|
+
- concerning
|
93
|
+
|
80
94
|
Rails:
|
81
95
|
Enabled: true
|
82
96
|
DocumentationBaseURL: https://docs.rubocop.org/rubocop-rails
|
@@ -353,11 +367,13 @@ Rails/Delegate:
|
|
353
367
|
Description: 'Prefer delegate method for delegations.'
|
354
368
|
Enabled: true
|
355
369
|
VersionAdded: '0.21'
|
356
|
-
VersionChanged: '
|
370
|
+
VersionChanged: '2.30'
|
357
371
|
# When set to true, using the target object as a prefix of the
|
358
372
|
# method name without using the `delegate` method will be a
|
359
373
|
# violation. When set to false, this case is legal.
|
360
374
|
EnforceForPrefixed: true
|
375
|
+
Exclude:
|
376
|
+
- app/controllers/**/*.rb
|
361
377
|
|
362
378
|
Rails/DelegateAllowBlank:
|
363
379
|
Description: 'Do not use allow_blank as an option to delegate.'
|
@@ -87,7 +87,7 @@ module RuboCop
|
|
87
87
|
|
88
88
|
options.each_pair.find do |pair|
|
89
89
|
next unless pair.key.sym_type? && pair.key.value == :foreign_key
|
90
|
-
next unless pair.value.
|
90
|
+
next unless pair.value.type?(:sym, :str)
|
91
91
|
|
92
92
|
break pair.value.value.to_s
|
93
93
|
end
|
@@ -103,7 +103,7 @@ module RuboCop
|
|
103
103
|
end
|
104
104
|
|
105
105
|
def in_where?(node)
|
106
|
-
send_node = node.each_ancestor(:
|
106
|
+
send_node = node.each_ancestor(:call).first
|
107
107
|
return false unless send_node
|
108
108
|
|
109
109
|
return true if WHERE_METHODS.include?(send_node.method_name)
|
@@ -1,7 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RuboCop
|
4
|
-
module Cop
|
4
|
+
module Cop # rubocop:disable Style/Documentation
|
5
|
+
# The EnforceSuperclass module is also defined in `rubocop` (for backwards
|
6
|
+
# compatibility), so here we remove it before (re)defining it, to avoid
|
7
|
+
# warnings about methods in the module being redefined.
|
8
|
+
remove_const(:EnforceSuperclass) if defined?(EnforceSuperclass)
|
9
|
+
|
5
10
|
# Common functionality for enforcing a specific superclass.
|
6
11
|
module EnforceSuperclass
|
7
12
|
def self.included(base)
|
@@ -6,6 +6,71 @@ module RuboCop
|
|
6
6
|
module IndexMethod # rubocop:disable Metrics/ModuleLength
|
7
7
|
RESTRICT_ON_SEND = %i[each_with_object to_h map collect []].freeze
|
8
8
|
|
9
|
+
# Internal helper class to hold match data
|
10
|
+
Captures = ::Struct.new(
|
11
|
+
:transformed_argname,
|
12
|
+
:transforming_body_expr
|
13
|
+
) do
|
14
|
+
def noop_transformation?
|
15
|
+
transforming_body_expr.lvar_type? && transforming_body_expr.children == [transformed_argname]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Internal helper class to hold autocorrect data
|
20
|
+
Autocorrection = ::Struct.new(:match, :block_node, :leading, :trailing) do
|
21
|
+
def self.from_each_with_object(node, match)
|
22
|
+
new(match, node, 0, 0)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.from_to_h(node, match)
|
26
|
+
new(match, node, 0, 0)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.from_map_to_h(node, match)
|
30
|
+
if node.block_literal?
|
31
|
+
strip_trailing_chars = 0
|
32
|
+
else
|
33
|
+
map_range = node.children.first.source_range
|
34
|
+
node_range = node.source_range
|
35
|
+
strip_trailing_chars = node_range.end_pos - map_range.end_pos
|
36
|
+
end
|
37
|
+
|
38
|
+
new(match, node.children.first, 0, strip_trailing_chars)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.from_hash_brackets_map(node, match)
|
42
|
+
new(match, node.children.last, "#{node.receiver.source}[".length, ']'.length)
|
43
|
+
end
|
44
|
+
|
45
|
+
def strip_prefix_and_suffix(node, corrector)
|
46
|
+
expression = node.source_range
|
47
|
+
corrector.remove_leading(expression, leading)
|
48
|
+
corrector.remove_trailing(expression, trailing)
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_new_method_name(new_method_name, corrector)
|
52
|
+
range = block_node.send_node.loc.selector
|
53
|
+
if (send_end = block_node.send_node.loc.end)
|
54
|
+
# If there are arguments (only true in the `each_with_object` case)
|
55
|
+
range = range.begin.join(send_end)
|
56
|
+
end
|
57
|
+
corrector.replace(range, new_method_name)
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_new_arg_name(transformed_argname, corrector)
|
61
|
+
return unless block_node.block_type?
|
62
|
+
|
63
|
+
corrector.replace(block_node.arguments, "|#{transformed_argname}|")
|
64
|
+
end
|
65
|
+
|
66
|
+
def set_new_body_expression(transforming_body_expr, corrector)
|
67
|
+
body_source = transforming_body_expr.source
|
68
|
+
body_source = "{ #{body_source} }" if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
|
69
|
+
|
70
|
+
corrector.replace(block_node.body, body_source)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
9
74
|
def on_block(node)
|
10
75
|
on_bad_each_with_object(node) do |*match|
|
11
76
|
handle_possible_offense(node, match, 'each_with_object')
|
@@ -19,6 +84,7 @@ module RuboCop
|
|
19
84
|
end
|
20
85
|
|
21
86
|
alias on_numblock on_block
|
87
|
+
alias on_itblock on_block
|
22
88
|
|
23
89
|
def on_send(node)
|
24
90
|
on_bad_map_to_h(node) do |*match|
|
@@ -102,71 +168,6 @@ module RuboCop
|
|
102
168
|
correction.set_new_arg_name(captures.transformed_argname, corrector)
|
103
169
|
correction.set_new_body_expression(captures.transforming_body_expr, corrector)
|
104
170
|
end
|
105
|
-
|
106
|
-
# Internal helper class to hold match data
|
107
|
-
Captures = ::Struct.new(
|
108
|
-
:transformed_argname,
|
109
|
-
:transforming_body_expr
|
110
|
-
) do
|
111
|
-
def noop_transformation?
|
112
|
-
transforming_body_expr.lvar_type? && transforming_body_expr.children == [transformed_argname]
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# Internal helper class to hold autocorrect data
|
117
|
-
Autocorrection = ::Struct.new(:match, :block_node, :leading, :trailing) do
|
118
|
-
def self.from_each_with_object(node, match)
|
119
|
-
new(match, node, 0, 0)
|
120
|
-
end
|
121
|
-
|
122
|
-
def self.from_to_h(node, match)
|
123
|
-
new(match, node, 0, 0)
|
124
|
-
end
|
125
|
-
|
126
|
-
def self.from_map_to_h(node, match)
|
127
|
-
if node.block_literal?
|
128
|
-
strip_trailing_chars = 0
|
129
|
-
else
|
130
|
-
map_range = node.children.first.source_range
|
131
|
-
node_range = node.source_range
|
132
|
-
strip_trailing_chars = node_range.end_pos - map_range.end_pos
|
133
|
-
end
|
134
|
-
|
135
|
-
new(match, node.children.first, 0, strip_trailing_chars)
|
136
|
-
end
|
137
|
-
|
138
|
-
def self.from_hash_brackets_map(node, match)
|
139
|
-
new(match, node.children.last, "#{node.receiver.source}[".length, ']'.length)
|
140
|
-
end
|
141
|
-
|
142
|
-
def strip_prefix_and_suffix(node, corrector)
|
143
|
-
expression = node.source_range
|
144
|
-
corrector.remove_leading(expression, leading)
|
145
|
-
corrector.remove_trailing(expression, trailing)
|
146
|
-
end
|
147
|
-
|
148
|
-
def set_new_method_name(new_method_name, corrector)
|
149
|
-
range = block_node.send_node.loc.selector
|
150
|
-
if (send_end = block_node.send_node.loc.end)
|
151
|
-
# If there are arguments (only true in the `each_with_object` case)
|
152
|
-
range = range.begin.join(send_end)
|
153
|
-
end
|
154
|
-
corrector.replace(range, new_method_name)
|
155
|
-
end
|
156
|
-
|
157
|
-
def set_new_arg_name(transformed_argname, corrector)
|
158
|
-
return if block_node.numblock_type?
|
159
|
-
|
160
|
-
corrector.replace(block_node.arguments, "|#{transformed_argname}|")
|
161
|
-
end
|
162
|
-
|
163
|
-
def set_new_body_expression(transforming_body_expr, corrector)
|
164
|
-
body_source = transforming_body_expr.source
|
165
|
-
body_source = "{ #{body_source} }" if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
|
166
|
-
|
167
|
-
corrector.replace(block_node.body, body_source)
|
168
|
-
end
|
169
|
-
end
|
170
171
|
end
|
171
172
|
end
|
172
173
|
end
|
@@ -5,14 +5,14 @@ module RuboCop
|
|
5
5
|
module Rails
|
6
6
|
# Prevents usage of `"*"` on an Arel::Table column reference.
|
7
7
|
#
|
8
|
-
# Using `arel_table["
|
9
|
-
# quoted asterisk (e.g.
|
10
|
-
# database to look for a column named
|
8
|
+
# Using `arel_table["\*"]` causes the outputted string to be a literal
|
9
|
+
# quoted asterisk (e.g. `my_model`.`*`). This causes the
|
10
|
+
# database to look for a column named `\*` (or `"*"`) as opposed
|
11
11
|
# to expanding the column list as one would likely expect.
|
12
12
|
#
|
13
13
|
# @safety
|
14
|
-
# This cop's autocorrection is unsafe because it turns a quoted
|
15
|
-
# an SQL `*`, unquoted.
|
14
|
+
# This cop's autocorrection is unsafe because it turns a quoted `\*` into
|
15
|
+
# an SQL `*`, unquoted. `\*` is a valid column name in certain databases
|
16
16
|
# supported by Rails, and even though it is usually a mistake,
|
17
17
|
# it might denote legitimate access to a column named `*`.
|
18
18
|
#
|
@@ -123,7 +123,7 @@ module RuboCop
|
|
123
123
|
def on_if(node)
|
124
124
|
return unless cop_config['UnlessPresent']
|
125
125
|
return unless node.unless?
|
126
|
-
return if node.else? && config.
|
126
|
+
return if node.else? && config.cop_enabled?('Style/UnlessElse')
|
127
127
|
|
128
128
|
unless_present?(node) do |method_call, receiver|
|
129
129
|
range = unless_condition(node, method_call)
|
@@ -15,6 +15,9 @@ module RuboCop
|
|
15
15
|
# without using the `delegate` method will be a violation.
|
16
16
|
# When set to `false`, this case is legal.
|
17
17
|
#
|
18
|
+
# It is disabled for controllers in order to keep controller actions
|
19
|
+
# explicitly defined.
|
20
|
+
#
|
18
21
|
# @example
|
19
22
|
# # bad
|
20
23
|
# def bar
|
@@ -68,12 +71,13 @@ module RuboCop
|
|
68
71
|
|
69
72
|
def_node_matcher :delegate?, <<~PATTERN
|
70
73
|
(def _method_name _args
|
71
|
-
(send {(send nil? _) (self)} _ ...))
|
74
|
+
(send {(send nil? _) (self) (send (self) :class) ({cvar gvar ivar} _) (const _ _)} _ ...))
|
72
75
|
PATTERN
|
73
76
|
|
74
77
|
def on_def(node)
|
75
78
|
return unless trivial_delegate?(node)
|
76
79
|
return if private_or_protected_delegation(node)
|
80
|
+
return if module_function_declared?(node)
|
77
81
|
|
78
82
|
register_offense(node)
|
79
83
|
end
|
@@ -82,15 +86,40 @@ module RuboCop
|
|
82
86
|
|
83
87
|
def register_offense(node)
|
84
88
|
add_offense(node.loc.keyword) do |corrector|
|
85
|
-
|
89
|
+
receiver = determine_register_offense_receiver(node.body.receiver)
|
90
|
+
delegation = build_delegation(node, receiver)
|
86
91
|
|
87
|
-
|
92
|
+
corrector.replace(node, delegation)
|
93
|
+
end
|
94
|
+
end
|
88
95
|
|
89
|
-
|
90
|
-
|
96
|
+
def determine_register_offense_receiver(receiver)
|
97
|
+
case receiver.type
|
98
|
+
when :self
|
99
|
+
'self'
|
100
|
+
when :const
|
101
|
+
full_name = full_const_name(receiver)
|
102
|
+
full_name.include?('::') ? ":'#{full_name}'" : ":#{full_name}"
|
103
|
+
when :cvar, :gvar, :ivar
|
104
|
+
":#{receiver.source}"
|
105
|
+
else
|
106
|
+
":#{receiver.method_name}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def build_delegation(node, receiver)
|
111
|
+
delegation = ["delegate :#{node.body.method_name}", "to: #{receiver}"]
|
112
|
+
delegation << ['prefix: true'] if node.method?(prefixed_method_name(node.body))
|
113
|
+
delegation.join(', ')
|
114
|
+
end
|
91
115
|
|
92
|
-
|
116
|
+
def full_const_name(node)
|
117
|
+
return unless node.const_type?
|
118
|
+
unless node.namespace
|
119
|
+
return node.absolute? ? "::#{node.source}" : node.source
|
93
120
|
end
|
121
|
+
|
122
|
+
"#{full_const_name(node.namespace)}::#{node.short_name}"
|
94
123
|
end
|
95
124
|
|
96
125
|
def trivial_delegate?(def_node)
|
@@ -120,13 +149,30 @@ module RuboCop
|
|
120
149
|
def prefixed_method_name(body)
|
121
150
|
return '' if body.receiver.self_type?
|
122
151
|
|
123
|
-
[body.receiver
|
152
|
+
[determine_prefixed_method_receiver_name(body.receiver), body.method_name].join('_').to_sym
|
153
|
+
end
|
154
|
+
|
155
|
+
def determine_prefixed_method_receiver_name(receiver)
|
156
|
+
case receiver.type
|
157
|
+
when :cvar, :gvar, :ivar
|
158
|
+
receiver.source
|
159
|
+
when :const
|
160
|
+
full_const_name(receiver)
|
161
|
+
else
|
162
|
+
receiver.method_name.to_s
|
163
|
+
end
|
124
164
|
end
|
125
165
|
|
126
166
|
def private_or_protected_delegation(node)
|
127
167
|
private_or_protected_inline(node) || node_visibility(node) != :public
|
128
168
|
end
|
129
169
|
|
170
|
+
def module_function_declared?(node)
|
171
|
+
node.each_ancestor(:module, :begin).any? do |ancestor|
|
172
|
+
ancestor.children.any? { |child| child.send_type? && child.method?(:module_function) }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
130
176
|
def private_or_protected_inline(node)
|
131
177
|
processed_source[node.first_line - 1].strip.match?(/\A(private )|(protected )/)
|
132
178
|
end
|
@@ -63,11 +63,15 @@ module RuboCop
|
|
63
63
|
private
|
64
64
|
|
65
65
|
def register_offense(name, nodes, message_template)
|
66
|
-
nodes.
|
67
|
-
add_offense(node, message: format(message_template, name: name)) do |corrector|
|
68
|
-
next if same_line?(nodes.last, node)
|
66
|
+
last_node = nodes.last
|
69
67
|
|
70
|
-
|
68
|
+
nodes.each_with_index do |node, index|
|
69
|
+
add_offense(node, message: format(message_template, name: name)) do |corrector|
|
70
|
+
if index.zero?
|
71
|
+
corrector.replace(node, last_node.source)
|
72
|
+
else
|
73
|
+
corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true))
|
74
|
+
end
|
71
75
|
end
|
72
76
|
end
|
73
77
|
end
|
@@ -45,12 +45,10 @@ module RuboCop
|
|
45
45
|
return if node.parent&.block_type?
|
46
46
|
|
47
47
|
interpolated_string_passed_to_debug(node) do |arguments|
|
48
|
-
message = format(MSG)
|
49
|
-
|
50
48
|
range = replacement_range(node)
|
51
49
|
replacement = replacement_source(node, arguments)
|
52
50
|
|
53
|
-
add_offense(range
|
51
|
+
add_offense(range) do |corrector|
|
54
52
|
corrector.replace(range, replacement)
|
55
53
|
end
|
56
54
|
end
|
@@ -6,6 +6,9 @@ module RuboCop
|
|
6
6
|
# Identifies usages of file path joining process to use `Rails.root.join` clause.
|
7
7
|
# It is used to add uniformity when joining paths.
|
8
8
|
#
|
9
|
+
# NOTE: This cop ignores leading slashes in string literal arguments for `Rails.root.join`
|
10
|
+
# and multiple slashes in string literal arguments for `Rails.root.join` and `File.join`.
|
11
|
+
#
|
9
12
|
# @example EnforcedStyle: slashes (default)
|
10
13
|
# # bad
|
11
14
|
# Rails.root.join('app', 'models', 'goober')
|
@@ -97,7 +100,7 @@ module RuboCop
|
|
97
100
|
|
98
101
|
def check_for_file_join_with_rails_root(node)
|
99
102
|
return unless file_join_nodes?(node)
|
100
|
-
return unless node.arguments
|
103
|
+
return unless valid_arguments_for_file_join_with_rails_root?(node.arguments)
|
101
104
|
|
102
105
|
register_offense(node, require_to_s: true) do |corrector|
|
103
106
|
autocorrect_file_join(corrector, node) unless node.first_argument.array_type?
|
@@ -108,8 +111,7 @@ module RuboCop
|
|
108
111
|
return unless style == :slashes
|
109
112
|
return unless rails_root_nodes?(node)
|
110
113
|
return unless rails_root_join_nodes?(node)
|
111
|
-
return unless node.arguments
|
112
|
-
return unless node.arguments.all?(&:str_type?)
|
114
|
+
return unless valid_string_arguments_for_rails_root_join?(node.arguments)
|
113
115
|
|
114
116
|
register_offense(node, require_to_s: false) do |corrector|
|
115
117
|
autocorrect_rails_root_join_with_string_arguments(corrector, node)
|
@@ -120,15 +122,42 @@ module RuboCop
|
|
120
122
|
return unless style == :arguments
|
121
123
|
return unless rails_root_nodes?(node)
|
122
124
|
return unless rails_root_join_nodes?(node)
|
123
|
-
return unless node.arguments
|
125
|
+
return unless valid_slash_separated_path_for_rails_root_join?(node.arguments)
|
124
126
|
|
125
127
|
register_offense(node, require_to_s: false) do |corrector|
|
126
128
|
autocorrect_rails_root_join_with_slash_separated_path(corrector, node)
|
127
129
|
end
|
128
130
|
end
|
129
131
|
|
130
|
-
def
|
131
|
-
|
132
|
+
def valid_arguments_for_file_join_with_rails_root?(arguments)
|
133
|
+
return false unless arguments.any? { |arg| rails_root_nodes?(arg) }
|
134
|
+
|
135
|
+
arguments.none? { |arg| arg.variable? || arg.const_type? || string_contains_multiple_slashes?(arg) }
|
136
|
+
end
|
137
|
+
|
138
|
+
def valid_string_arguments_for_rails_root_join?(arguments)
|
139
|
+
return false unless arguments.size > 1
|
140
|
+
return false unless arguments.all?(&:str_type?)
|
141
|
+
|
142
|
+
arguments.none? { |arg| string_with_leading_slash?(arg) || string_contains_multiple_slashes?(arg) }
|
143
|
+
end
|
144
|
+
|
145
|
+
def valid_slash_separated_path_for_rails_root_join?(arguments)
|
146
|
+
return false unless arguments.any? { |arg| string_contains_slash?(arg) }
|
147
|
+
|
148
|
+
arguments.none? { |arg| string_with_leading_slash?(arg) || string_contains_multiple_slashes?(arg) }
|
149
|
+
end
|
150
|
+
|
151
|
+
def string_contains_slash?(node)
|
152
|
+
node.str_type? && node.value.include?(File::SEPARATOR)
|
153
|
+
end
|
154
|
+
|
155
|
+
def string_contains_multiple_slashes?(node)
|
156
|
+
node.str_type? && node.value.include?('//')
|
157
|
+
end
|
158
|
+
|
159
|
+
def string_with_leading_slash?(node)
|
160
|
+
node.str_type? && node.value.start_with?(File::SEPARATOR)
|
132
161
|
end
|
133
162
|
|
134
163
|
def register_offense(node, require_to_s:, &block)
|
@@ -173,7 +202,17 @@ module RuboCop
|
|
173
202
|
end
|
174
203
|
|
175
204
|
def autocorrect_file_join(corrector, node)
|
205
|
+
replace_receiver_with_rails_root(corrector, node)
|
206
|
+
remove_first_argument_with_comma(corrector, node)
|
207
|
+
process_arguments(corrector, node.arguments)
|
208
|
+
append_to_string_conversion(corrector, node)
|
209
|
+
end
|
210
|
+
|
211
|
+
def replace_receiver_with_rails_root(corrector, node)
|
176
212
|
corrector.replace(node.receiver, 'Rails.root')
|
213
|
+
end
|
214
|
+
|
215
|
+
def remove_first_argument_with_comma(corrector, node)
|
177
216
|
corrector.remove(
|
178
217
|
range_with_surrounding_space(
|
179
218
|
range_with_surrounding_comma(
|
@@ -183,9 +222,19 @@ module RuboCop
|
|
183
222
|
side: :right
|
184
223
|
)
|
185
224
|
)
|
186
|
-
|
187
|
-
|
225
|
+
end
|
226
|
+
|
227
|
+
def process_arguments(corrector, arguments)
|
228
|
+
arguments.each do |argument|
|
229
|
+
if argument.str_type?
|
230
|
+
corrector.replace(argument, argument.value.delete_prefix('/').inspect)
|
231
|
+
elsif argument.array_type?
|
232
|
+
corrector.replace(argument, "*#{argument.source}")
|
233
|
+
end
|
188
234
|
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def append_to_string_conversion(corrector, node)
|
189
238
|
corrector.insert_after(node, '.to_s')
|
190
239
|
end
|
191
240
|
|
@@ -206,7 +255,7 @@ module RuboCop
|
|
206
255
|
|
207
256
|
def autocorrect_rails_root_join_with_slash_separated_path(corrector, node)
|
208
257
|
node.arguments.each do |argument|
|
209
|
-
next unless
|
258
|
+
next unless string_contains_slash?(argument)
|
210
259
|
|
211
260
|
index = argument.source.index(File::SEPARATOR)
|
212
261
|
rest = inner_range_of(argument).adjust(begin_pos: index - 1)
|
@@ -37,6 +37,9 @@ module RuboCop
|
|
37
37
|
(numblock
|
38
38
|
(call _ :to_h) $1
|
39
39
|
(array $_ (lvar :_1)))
|
40
|
+
(itblock
|
41
|
+
(call _ :to_h) $:it
|
42
|
+
(array $_ (lvar :it)))
|
40
43
|
}
|
41
44
|
PATTERN
|
42
45
|
|
@@ -50,6 +53,9 @@ module RuboCop
|
|
50
53
|
(numblock
|
51
54
|
(call _ {:map :collect}) $1
|
52
55
|
(array $_ (lvar :_1)))
|
56
|
+
(itblock
|
57
|
+
(call _ {:map :collect}) $:it
|
58
|
+
(array $_ (lvar :it)))
|
53
59
|
}
|
54
60
|
:to_h)
|
55
61
|
PATTERN
|
@@ -66,6 +72,9 @@ module RuboCop
|
|
66
72
|
(numblock
|
67
73
|
(call _ {:map :collect}) $1
|
68
74
|
(array $_ (lvar :_1)))
|
75
|
+
(itblock
|
76
|
+
(call _ {:map :collect}) $:it
|
77
|
+
(array $_ (lvar :it)))
|
69
78
|
}
|
70
79
|
)
|
71
80
|
PATTERN
|