rubocop 0.11.1 → 0.12.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/CHANGELOG.md +32 -1
- data/README.md +28 -3
- data/config/default.yml +14 -12
- data/config/disabled.yml +1 -1
- data/config/enabled.yml +190 -118
- data/lib/rubocop.rb +9 -1
- data/lib/rubocop/cli.rb +49 -13
- data/lib/rubocop/config.rb +5 -5
- data/lib/rubocop/cop/cop.rb +34 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +47 -0
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
- data/lib/rubocop/cop/lint/useless_assignment.rb +39 -11
- data/lib/rubocop/cop/lint/useless_comparison.rb +2 -4
- data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +20 -0
- data/lib/rubocop/cop/rails/read_attribute.rb +28 -0
- data/lib/rubocop/cop/style/access_control.rb +12 -1
- data/lib/rubocop/cop/style/attr.rb +7 -0
- data/lib/rubocop/cop/style/collection_methods.rb +13 -1
- data/lib/rubocop/cop/style/constant_name.rb +1 -1
- data/lib/rubocop/cop/style/def_parentheses.rb +18 -0
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/empty_literal.rb +14 -0
- data/lib/rubocop/cop/style/even_odd.rb +56 -0
- data/lib/rubocop/cop/style/favor_modifier.rb +2 -2
- data/lib/rubocop/cop/style/hash_methods.rb +40 -0
- data/lib/rubocop/cop/style/indentation_width.rb +148 -0
- data/lib/rubocop/cop/style/method_and_variable_snake_case.rb +40 -25
- data/lib/rubocop/cop/style/method_call_parentheses.rb +8 -0
- data/lib/rubocop/cop/style/multiline_if_then.rb +1 -1
- data/lib/rubocop/cop/style/nil_comparison.rb +38 -0
- data/lib/rubocop/cop/style/signal_exception.rb +11 -0
- data/lib/rubocop/cop/style/space_after_method_name.rb +34 -0
- data/lib/rubocop/cop/util.rb +17 -0
- data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -2
- data/lib/rubocop/formatter/file_list_formatter.rb +3 -2
- data/lib/rubocop/formatter/formatter_set.rb +3 -11
- data/lib/rubocop/formatter/offence_count_formatter.rb +50 -0
- data/lib/rubocop/formatter/progress_formatter.rb +0 -2
- data/lib/rubocop/formatter/simple_text_formatter.rb +1 -6
- data/lib/rubocop/version.rb +1 -1
- data/spec/project_spec.rb +7 -0
- data/spec/rubocop/cli_spec.rb +119 -57
- data/spec/rubocop/config_spec.rb +23 -17
- data/spec/rubocop/cop/commissioner_spec.rb +8 -8
- data/spec/rubocop/cop/cop_spec.rb +80 -0
- data/spec/rubocop/cop/lint/parentheses_as_grouped_expression_spec.rb +63 -0
- data/spec/rubocop/cop/lint/useless_assignment_spec.rb +59 -0
- data/spec/rubocop/cop/rails/has_and_belongs_to_many_spec.rb +19 -0
- data/spec/rubocop/cop/rails/read_attribute_spec.rb +19 -0
- data/spec/rubocop/cop/rails/validation_spec.rb +5 -5
- data/spec/rubocop/cop/style/access_control_spec.rb +28 -0
- data/spec/rubocop/cop/style/attr_spec.rb +6 -1
- data/spec/rubocop/cop/style/collection_methods_spec.rb +5 -0
- data/spec/rubocop/cop/style/constant_name_spec.rb +9 -0
- data/spec/rubocop/cop/style/def_with_parentheses_spec.rb +14 -9
- data/spec/rubocop/cop/style/def_without_parentheses_spec.rb +12 -7
- data/spec/rubocop/cop/style/empty_literal_spec.rb +42 -27
- data/spec/rubocop/cop/style/even_odd_spec.rb +47 -0
- data/spec/rubocop/cop/style/favor_modifier_spec.rb +15 -14
- data/spec/rubocop/cop/style/hash_methods_spec.rb +51 -0
- data/spec/rubocop/cop/style/indentation_width_spec.rb +390 -0
- data/spec/rubocop/cop/style/method_and_variable_snake_case_spec.rb +58 -50
- data/spec/rubocop/cop/style/method_call_parentheses_spec.rb +6 -1
- data/spec/rubocop/cop/style/nil_comparison_spec.rb +31 -0
- data/spec/rubocop/cop/style/signal_exception_spec.rb +28 -0
- data/spec/rubocop/cop/style/space_after_method_name_spec.rb +61 -0
- data/spec/rubocop/formatter/emacs_style_formatter_spec.rb +9 -2
- data/spec/rubocop/formatter/file_list_formatter_spec.rb +3 -3
- data/spec/rubocop/formatter/offence_count_formatter_spec.rb +52 -0
- data/spec/rubocop/formatter/progress_formatter_spec.rb +70 -84
- data/spec/rubocop/source_parser_spec.rb +1 -1
- metadata +29 -5
- data/lib/rubocop/cop/style/line_continuation.rb +0 -27
- data/spec/rubocop/cop/style/line_continuation_spec.rb +0 -26
data/lib/rubocop.rb
CHANGED
@@ -24,6 +24,7 @@ require 'rubocop/cop/lint/eval'
|
|
24
24
|
require 'rubocop/cop/lint/handle_exceptions'
|
25
25
|
require 'rubocop/cop/lint/literal_in_condition'
|
26
26
|
require 'rubocop/cop/lint/loop'
|
27
|
+
require 'rubocop/cop/lint/parentheses_as_grouped_expression'
|
27
28
|
require 'rubocop/cop/lint/rescue_exception'
|
28
29
|
require 'rubocop/cop/lint/shadowing_outer_local_variable'
|
29
30
|
require 'rubocop/cop/lint/unreachable_code'
|
@@ -66,23 +67,26 @@ require 'rubocop/cop/style/empty_literal'
|
|
66
67
|
require 'rubocop/cop/style/encoding'
|
67
68
|
require 'rubocop/cop/style/end_block'
|
68
69
|
require 'rubocop/cop/style/end_of_line'
|
70
|
+
require 'rubocop/cop/style/even_odd'
|
69
71
|
require 'rubocop/cop/style/favor_join'
|
70
72
|
require 'rubocop/cop/style/favor_modifier'
|
71
73
|
require 'rubocop/cop/style/favor_sprintf'
|
72
74
|
require 'rubocop/cop/style/favor_unless_over_negated_if'
|
75
|
+
require 'rubocop/cop/style/hash_methods'
|
73
76
|
require 'rubocop/cop/style/hash_syntax'
|
74
77
|
require 'rubocop/cop/style/if_then_else'
|
75
78
|
require 'rubocop/cop/style/if_with_semicolon'
|
79
|
+
require 'rubocop/cop/style/indentation_width'
|
76
80
|
require 'rubocop/cop/style/multiline_if_then'
|
77
81
|
require 'rubocop/cop/style/one_line_conditional'
|
78
82
|
require 'rubocop/cop/style/lambda'
|
79
83
|
require 'rubocop/cop/style/leading_comment_space'
|
80
|
-
require 'rubocop/cop/style/line_continuation'
|
81
84
|
require 'rubocop/cop/style/line_length'
|
82
85
|
require 'rubocop/cop/style/method_and_variable_snake_case'
|
83
86
|
require 'rubocop/cop/style/method_call_parentheses'
|
84
87
|
require 'rubocop/cop/style/method_length'
|
85
88
|
require 'rubocop/cop/style/module_function'
|
89
|
+
require 'rubocop/cop/style/nil_comparison'
|
86
90
|
require 'rubocop/cop/style/not'
|
87
91
|
require 'rubocop/cop/style/numeric_literals'
|
88
92
|
require 'rubocop/cop/style/op_method'
|
@@ -100,6 +104,7 @@ require 'rubocop/cop/style/signal_exception'
|
|
100
104
|
require 'rubocop/cop/style/single_line_methods'
|
101
105
|
require 'rubocop/cop/style/space_after_comma_etc'
|
102
106
|
require 'rubocop/cop/style/space_after_control_keyword'
|
107
|
+
require 'rubocop/cop/style/space_after_method_name'
|
103
108
|
require 'rubocop/cop/style/string_literals'
|
104
109
|
require 'rubocop/cop/style/surrounding_space'
|
105
110
|
require 'rubocop/cop/style/symbol_array'
|
@@ -114,6 +119,8 @@ require 'rubocop/cop/style/when_then'
|
|
114
119
|
require 'rubocop/cop/style/while_until_do'
|
115
120
|
require 'rubocop/cop/style/word_array'
|
116
121
|
|
122
|
+
require 'rubocop/cop/rails/has_and_belongs_to_many'
|
123
|
+
require 'rubocop/cop/rails/read_attribute'
|
117
124
|
require 'rubocop/cop/rails/validation'
|
118
125
|
|
119
126
|
require 'rubocop/formatter/base_formatter'
|
@@ -124,6 +131,7 @@ require 'rubocop/formatter/clang_style_formatter'
|
|
124
131
|
require 'rubocop/formatter/progress_formatter'
|
125
132
|
require 'rubocop/formatter/json_formatter'
|
126
133
|
require 'rubocop/formatter/file_list_formatter'
|
134
|
+
require 'rubocop/formatter/offence_count_formatter'
|
127
135
|
require 'rubocop/formatter/formatter_set'
|
128
136
|
|
129
137
|
require 'rubocop/config'
|
data/lib/rubocop/cli.rb
CHANGED
@@ -62,7 +62,7 @@ module Rubocop
|
|
62
62
|
formatter_set.finished(inspected_files.freeze)
|
63
63
|
formatter_set.close_output_files
|
64
64
|
|
65
|
-
display_error_summary(@errors)
|
65
|
+
display_error_summary(@errors)
|
66
66
|
|
67
67
|
!any_failed && !wants_to_quit ? 0 : 1
|
68
68
|
rescue => e
|
@@ -83,6 +83,27 @@ module Rubocop
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
+
def print_available_cops
|
87
|
+
puts "Available cops (#{@cops.length}) + config for #{Dir.pwd.to_s}: "
|
88
|
+
dirconf = @config_store.for(Dir.pwd.to_s)
|
89
|
+
@cops.types.sort!.each do |type|
|
90
|
+
coptypes = @cops.with_type(type).sort_by!(&:cop_name)
|
91
|
+
puts "Type '#{type.to_s.capitalize}' (#{coptypes.size}):"
|
92
|
+
coptypes.each do |cop|
|
93
|
+
name = cop.cop_name
|
94
|
+
puts " - #{name}"
|
95
|
+
cnf = dirconf.for_cop(name).dup
|
96
|
+
print_conf_option('Description',
|
97
|
+
cnf.delete('Description') { 'None' })
|
98
|
+
cnf.each { |k, v| print_conf_option(k, v) }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def print_conf_option(option, value)
|
104
|
+
puts " - #{option}: #{value}"
|
105
|
+
end
|
106
|
+
|
86
107
|
def inspect_file(file)
|
87
108
|
begin
|
88
109
|
processed_source = SourceParser.parse_file(file)
|
@@ -160,7 +181,8 @@ module Rubocop
|
|
160
181
|
|
161
182
|
# rubocop:disable MethodLength
|
162
183
|
def parse_options(args)
|
163
|
-
|
184
|
+
ignore_dropped_options(args)
|
185
|
+
convert_deprecated_options(args)
|
164
186
|
|
165
187
|
OptionParser.new do |opts|
|
166
188
|
opts.banner = 'Usage: rubocop [options] [file1, file2, ...]'
|
@@ -186,6 +208,12 @@ module Rubocop
|
|
186
208
|
]
|
187
209
|
validate_auto_gen_config_option(args)
|
188
210
|
end
|
211
|
+
opts.on('--show-cops',
|
212
|
+
'Shows cops and their config for the',
|
213
|
+
'current directory.') do
|
214
|
+
print_available_cops
|
215
|
+
exit(0)
|
216
|
+
end
|
189
217
|
opts.on('-f', '--format FORMATTER',
|
190
218
|
'Choose an output formatter. This option',
|
191
219
|
'can be specified multiple times to enable',
|
@@ -196,6 +224,7 @@ module Rubocop
|
|
196
224
|
' [e]macs',
|
197
225
|
' [j]son',
|
198
226
|
' [f]iles',
|
227
|
+
' [o]ffences',
|
199
228
|
' custom formatter class name') do |key|
|
200
229
|
@options[:formatters] ||= []
|
201
230
|
@options[:formatters] << [key]
|
@@ -220,9 +249,6 @@ module Rubocop
|
|
220
249
|
opts.on('-a', '--auto-correct', 'Auto-correct offences.') do |a|
|
221
250
|
@options[:autocorrect] = a
|
222
251
|
end
|
223
|
-
opts.on('-s', '--silent', 'Silence summary.') do |s|
|
224
|
-
@options[:silent] = s
|
225
|
-
end
|
226
252
|
opts.on('-n', '--no-color', 'Disable color output.') do |s|
|
227
253
|
Sickill::Rainbow.enabled = false
|
228
254
|
end
|
@@ -238,7 +264,17 @@ module Rubocop
|
|
238
264
|
end
|
239
265
|
# rubocop:enable MethodLength
|
240
266
|
|
241
|
-
def
|
267
|
+
def ignore_dropped_options(args)
|
268
|
+
# Currently we don't make -s/--silent option raise error
|
269
|
+
# since those are mostly used by external tools.
|
270
|
+
rejected = args.reject! { |a| %w(-s --silent).include?(a) }
|
271
|
+
if rejected
|
272
|
+
warn '-s/--silent options is dropped. ' +
|
273
|
+
'`emacs` and `files` formatters no longer display summary.'
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def convert_deprecated_options(args)
|
242
278
|
args.map! do |arg|
|
243
279
|
case arg
|
244
280
|
when '-e', '--emacs'
|
@@ -262,12 +298,12 @@ module Rubocop
|
|
262
298
|
def display_error_summary(errors)
|
263
299
|
return if errors.empty?
|
264
300
|
plural = errors.count > 1 ? 's' : ''
|
265
|
-
|
266
|
-
errors.each { |error|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
301
|
+
warn "\n#{errors.count} error#{plural} occurred:".color(:red)
|
302
|
+
errors.each { |error| warn error }
|
303
|
+
warn 'Errors are usually caused by RuboCop bugs.'
|
304
|
+
warn 'Please, report your problems to RuboCop\'s issue tracker.'
|
305
|
+
warn 'Mention the following information in the issue report:'
|
306
|
+
warn Rubocop::Version.version(true)
|
271
307
|
end
|
272
308
|
|
273
309
|
def autocorrect(buffer, cops)
|
@@ -295,7 +331,7 @@ module Rubocop
|
|
295
331
|
|
296
332
|
def formatter_set
|
297
333
|
@formatter_set ||= begin
|
298
|
-
set = Formatter::FormatterSet.new
|
334
|
+
set = Formatter::FormatterSet.new
|
299
335
|
pairs = @options[:formatters] || [[DEFAULT_FORMATTER]]
|
300
336
|
pairs.each do |formatter_key, output_path|
|
301
337
|
set.add_formatter(formatter_key, output_path)
|
data/lib/rubocop/config.rb
CHANGED
@@ -37,7 +37,7 @@ module Rubocop
|
|
37
37
|
end
|
38
38
|
base_config.each do |key, value|
|
39
39
|
if value.is_a?(Hash)
|
40
|
-
hash[key] = hash.
|
40
|
+
hash[key] = hash.key?(key) ? merge(value, hash[key]) : value
|
41
41
|
end
|
42
42
|
end
|
43
43
|
if base_config.loaded_path.include?(AUTO_GENERATED_FILE)
|
@@ -75,7 +75,7 @@ module Rubocop
|
|
75
75
|
def merge(base_hash, derived_hash)
|
76
76
|
result = {}
|
77
77
|
base_hash.each do |key, value|
|
78
|
-
result[key] = if derived_hash.
|
78
|
+
result[key] = if derived_hash.key?(key)
|
79
79
|
if value.is_a?(Hash)
|
80
80
|
value.merge(derived_hash[key])
|
81
81
|
else
|
@@ -86,7 +86,7 @@ module Rubocop
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
derived_hash.each do |key, value|
|
89
|
-
result[key] = value unless base_hash.
|
89
|
+
result[key] = value unless base_hash.key?(key)
|
90
90
|
end
|
91
91
|
result
|
92
92
|
end
|
@@ -200,7 +200,7 @@ module Rubocop
|
|
200
200
|
default_config = self.class.default_configuration
|
201
201
|
|
202
202
|
valid_cop_names, invalid_cop_names = @hash.keys.partition do |key|
|
203
|
-
default_config.
|
203
|
+
default_config.key?(key)
|
204
204
|
end
|
205
205
|
|
206
206
|
invalid_cop_names.each do |name|
|
@@ -210,7 +210,7 @@ module Rubocop
|
|
210
210
|
|
211
211
|
valid_cop_names.each do |name|
|
212
212
|
@hash[name].each_key do |param|
|
213
|
-
unless default_config[name].
|
213
|
+
unless default_config[name].key?(param)
|
214
214
|
fail ValidationError,
|
215
215
|
"unrecognized parameter #{name}:#{param} found " +
|
216
216
|
"in #{loaded_path || self}"
|
data/lib/rubocop/cop/cop.rb
CHANGED
@@ -2,6 +2,21 @@
|
|
2
2
|
|
3
3
|
module Rubocop
|
4
4
|
module Cop
|
5
|
+
# Store for all cops with helper functions
|
6
|
+
class CopStore < ::Array
|
7
|
+
|
8
|
+
# @return [Array<String>] list of types for current cops.
|
9
|
+
def types
|
10
|
+
@types = map(&:cop_type).uniq! unless defined? @types
|
11
|
+
@types
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Array<Cop>] Cops for that specific type.
|
15
|
+
def with_type(type)
|
16
|
+
select { |c| c.cop_type == type }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
5
20
|
# A scaffold for concrete cops.
|
6
21
|
#
|
7
22
|
# The Cop class is meant to be extended.
|
@@ -24,13 +39,20 @@ module Rubocop
|
|
24
39
|
class Cop
|
25
40
|
extend AST::Sexp
|
26
41
|
|
42
|
+
# http://phrogz.net/programmingruby/language.html#table_18.4
|
43
|
+
# Backtick is added last just to help editors parse this code.
|
44
|
+
OPERATOR_METHODS = %w(
|
45
|
+
| ^ & <=> == === =~ > >= < <= << >>
|
46
|
+
+ - * / % ** ~ +@ -@ [] []= ! != !~
|
47
|
+
).map(&:to_sym) + [:'`']
|
48
|
+
|
27
49
|
attr_accessor :offences
|
28
50
|
attr_accessor :debug
|
29
51
|
attr_accessor :autocorrect
|
30
52
|
attr_writer :disabled_lines
|
31
53
|
attr_reader :corrections
|
32
54
|
|
33
|
-
@all =
|
55
|
+
@all = CopStore.new
|
34
56
|
@config = {}
|
35
57
|
|
36
58
|
class << self
|
@@ -61,6 +83,17 @@ module Rubocop
|
|
61
83
|
cop_type == :lint
|
62
84
|
end
|
63
85
|
|
86
|
+
# Extracts the first line out of the description
|
87
|
+
def self.short_description
|
88
|
+
desc = full_description
|
89
|
+
desc ? desc.lines.first.strip : ''
|
90
|
+
end
|
91
|
+
|
92
|
+
# Gets the full description of the cop or nil if no description is set.
|
93
|
+
def self.full_description
|
94
|
+
config['Description']
|
95
|
+
end
|
96
|
+
|
64
97
|
def self.rails?
|
65
98
|
cop_type == :rails
|
66
99
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for space between a the name of a called method and a left
|
7
|
+
# parenthesis.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# puts (x + y)
|
12
|
+
class ParenthesesAsGroupedExpression < Cop
|
13
|
+
MSG = '(...) interpreted as grouped expression.'
|
14
|
+
|
15
|
+
def on_send(node)
|
16
|
+
receiver, method_name, args = *node
|
17
|
+
if OPERATOR_METHODS.include?(method_name) ||
|
18
|
+
method_name.to_s.end_with?('=')
|
19
|
+
return
|
20
|
+
end
|
21
|
+
if args && args.loc.expression.source.start_with?('(')
|
22
|
+
receiver_length = if receiver
|
23
|
+
receiver.loc.expression.source.length
|
24
|
+
else
|
25
|
+
0
|
26
|
+
end
|
27
|
+
without_receiver = node.loc.expression.source[receiver_length..-1]
|
28
|
+
|
29
|
+
# Escape question mark if any.
|
30
|
+
method_regexp = Regexp.escape(method_name)
|
31
|
+
|
32
|
+
if (match =
|
33
|
+
without_receiver.match(/^\s*\.?\s*#{method_regexp}(\s+)\(/))
|
34
|
+
expr = args.loc.expression
|
35
|
+
space_length = match.captures[0].length
|
36
|
+
space_range =
|
37
|
+
Parser::Source::Range.new(expr.source_buffer,
|
38
|
+
expr.begin_pos - space_length,
|
39
|
+
expr.begin_pos)
|
40
|
+
add_offence(:warning, space_range, MSG)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -16,10 +16,7 @@ module Rubocop
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def targets_exception?(rescue_arg_node)
|
19
|
-
|
20
|
-
namespace, klass_name = *rescue_arg_node
|
21
|
-
return false unless namespace.nil? || namespace.type == :cbase
|
22
|
-
klass_name == :Exception
|
19
|
+
Util.const_name(rescue_arg_node) == 'Exception'
|
23
20
|
end
|
24
21
|
end
|
25
22
|
end
|
@@ -20,20 +20,20 @@ module Rubocop
|
|
20
20
|
MSG = 'Useless assignment to local variable %s.'
|
21
21
|
|
22
22
|
def on_def(node)
|
23
|
-
_name,
|
23
|
+
_name, args, body = *node
|
24
24
|
|
25
|
-
check_for_useless_assignment(body)
|
25
|
+
check_for_useless_assignment(body, args)
|
26
26
|
end
|
27
27
|
|
28
28
|
def on_defs(node)
|
29
|
-
_target, _name,
|
29
|
+
_target, _name, args, body = *node
|
30
30
|
|
31
|
-
check_for_useless_assignment(body)
|
31
|
+
check_for_useless_assignment(body, args)
|
32
32
|
end
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
-
def check_for_useless_assignment(body)
|
36
|
+
def check_for_useless_assignment(body, args)
|
37
37
|
return unless body
|
38
38
|
|
39
39
|
if body.type == :begin
|
@@ -43,19 +43,47 @@ module Rubocop
|
|
43
43
|
end
|
44
44
|
|
45
45
|
last_expr = expression.is_a?(Array) ? expression.last : expression
|
46
|
+
return unless last_expr
|
46
47
|
|
47
|
-
|
48
|
+
case last_expr.type
|
49
|
+
when :lvasgn
|
48
50
|
var_name, = *last_expr
|
49
51
|
add_offence(:warning, last_expr.loc.name, MSG.format(var_name))
|
50
|
-
|
52
|
+
when :send
|
51
53
|
receiver, method, _args = *last_expr
|
54
|
+
return unless receiver
|
55
|
+
return unless receiver.type == :lvar
|
56
|
+
return unless method =~ /\w=$/
|
52
57
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
58
|
+
var_name, = *receiver
|
59
|
+
return if contains_object_passed_as_argument?(var_name, body, args)
|
60
|
+
|
61
|
+
add_offence(:warning,
|
62
|
+
receiver.loc.name,
|
63
|
+
MSG.format(receiver.loc.name.source))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def contains_object_passed_as_argument?(lvar_name, body, args)
|
68
|
+
variable_table = {}
|
69
|
+
|
70
|
+
args.children.each do |arg_node|
|
71
|
+
arg_name, = *arg_node
|
72
|
+
variable_table[arg_name] = true
|
73
|
+
end
|
74
|
+
|
75
|
+
on_node([:lvasgn, :ivasgn, :cvasgn, :gvasgn], body) do |asgn_node|
|
76
|
+
lhs_var_name, rhs_node = *asgn_node
|
77
|
+
|
78
|
+
if [:lvar, :ivar, :cvar, :gvar].include?(rhs_node.type)
|
79
|
+
rhs_var_name, = *rhs_node
|
80
|
+
variable_table[lhs_var_name] = variable_table[rhs_var_name]
|
81
|
+
else
|
82
|
+
variable_table[lhs_var_name] = false
|
57
83
|
end
|
58
84
|
end
|
85
|
+
|
86
|
+
variable_table[lvar_name]
|
59
87
|
end
|
60
88
|
end
|
61
89
|
end
|
@@ -17,11 +17,9 @@ module Rubocop
|
|
17
17
|
op = node.loc.selector.source
|
18
18
|
|
19
19
|
if OPS.include?(op)
|
20
|
-
receiver, _method,
|
20
|
+
receiver, _method, args = *node
|
21
21
|
|
22
|
-
if receiver ==
|
23
|
-
add_offence(:warning, node.loc.selector, MSG)
|
24
|
-
end
|
22
|
+
add_offence(:warning, node.loc.selector, MSG) if receiver == args
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks for the use of the has_and_belongs_to_many macro.
|
7
|
+
class HasAndBelongsToMany < Cop
|
8
|
+
MSG = 'Prefer has_many :through to has_and_belongs_to_many.'
|
9
|
+
|
10
|
+
def on_send(node)
|
11
|
+
receiver, method_name, *_args = *node
|
12
|
+
|
13
|
+
if receiver.nil? && method_name == :has_and_belongs_to_many
|
14
|
+
add_offence(:convention, node.loc.selector, MSG)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|