rubocop-rails 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.md +73 -0
  4. data/bin/setup +7 -0
  5. data/config/default.yml +466 -0
  6. data/lib/rubocop-rails.rb +12 -0
  7. data/lib/rubocop/cop/mixin/target_rails_version.rb +16 -0
  8. data/lib/rubocop/cop/rails/action_filter.rb +117 -0
  9. data/lib/rubocop/cop/rails/active_record_aliases.rb +48 -0
  10. data/lib/rubocop/cop/rails/active_record_override.rb +82 -0
  11. data/lib/rubocop/cop/rails/active_support_aliases.rb +69 -0
  12. data/lib/rubocop/cop/rails/application_job.rb +40 -0
  13. data/lib/rubocop/cop/rails/application_record.rb +40 -0
  14. data/lib/rubocop/cop/rails/assert_not.rb +44 -0
  15. data/lib/rubocop/cop/rails/belongs_to.rb +102 -0
  16. data/lib/rubocop/cop/rails/blank.rb +164 -0
  17. data/lib/rubocop/cop/rails/bulk_change_table.rb +289 -0
  18. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +91 -0
  19. data/lib/rubocop/cop/rails/date.rb +161 -0
  20. data/lib/rubocop/cop/rails/delegate.rb +132 -0
  21. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +37 -0
  22. data/lib/rubocop/cop/rails/dynamic_find_by.rb +91 -0
  23. data/lib/rubocop/cop/rails/enum_uniqueness.rb +45 -0
  24. data/lib/rubocop/cop/rails/environment_comparison.rb +68 -0
  25. data/lib/rubocop/cop/rails/exit.rb +67 -0
  26. data/lib/rubocop/cop/rails/file_path.rb +108 -0
  27. data/lib/rubocop/cop/rails/find_by.rb +55 -0
  28. data/lib/rubocop/cop/rails/find_each.rb +51 -0
  29. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +25 -0
  30. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +106 -0
  31. data/lib/rubocop/cop/rails/helper_instance_variable.rb +39 -0
  32. data/lib/rubocop/cop/rails/http_positional_arguments.rb +117 -0
  33. data/lib/rubocop/cop/rails/http_status.rb +160 -0
  34. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +94 -0
  35. data/lib/rubocop/cop/rails/inverse_of.rb +246 -0
  36. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +175 -0
  37. data/lib/rubocop/cop/rails/link_to_blank.rb +98 -0
  38. data/lib/rubocop/cop/rails/not_null_column.rb +67 -0
  39. data/lib/rubocop/cop/rails/output.rb +49 -0
  40. data/lib/rubocop/cop/rails/output_safety.rb +99 -0
  41. data/lib/rubocop/cop/rails/pluralization_grammar.rb +107 -0
  42. data/lib/rubocop/cop/rails/presence.rb +124 -0
  43. data/lib/rubocop/cop/rails/present.rb +153 -0
  44. data/lib/rubocop/cop/rails/read_write_attribute.rb +74 -0
  45. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +111 -0
  46. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +136 -0
  47. data/lib/rubocop/cop/rails/reflection_class_name.rb +37 -0
  48. data/lib/rubocop/cop/rails/refute_methods.rb +76 -0
  49. data/lib/rubocop/cop/rails/relative_date_constant.rb +93 -0
  50. data/lib/rubocop/cop/rails/request_referer.rb +56 -0
  51. data/lib/rubocop/cop/rails/reversible_migration.rb +286 -0
  52. data/lib/rubocop/cop/rails/safe_navigation.rb +87 -0
  53. data/lib/rubocop/cop/rails/save_bang.rb +316 -0
  54. data/lib/rubocop/cop/rails/scope_args.rb +29 -0
  55. data/lib/rubocop/cop/rails/skips_model_validations.rb +87 -0
  56. data/lib/rubocop/cop/rails/time_zone.rb +238 -0
  57. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +105 -0
  58. data/lib/rubocop/cop/rails/unknown_env.rb +63 -0
  59. data/lib/rubocop/cop/rails/validation.rb +109 -0
  60. data/lib/rubocop/cop/rails_cops.rb +64 -0
  61. data/lib/rubocop/rails.rb +12 -0
  62. data/lib/rubocop/rails/inject.rb +18 -0
  63. data/lib/rubocop/rails/version.rb +10 -0
  64. metadata +143 -0
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop checks for correct grammar when using ActiveSupport's
7
+ # core extensions to the numeric classes.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # 3.day.ago
12
+ # 1.months.ago
13
+ #
14
+ # # good
15
+ # 3.days.ago
16
+ # 1.month.ago
17
+ class PluralizationGrammar < Cop
18
+ SINGULAR_DURATION_METHODS = { second: :seconds,
19
+ minute: :minutes,
20
+ hour: :hours,
21
+ day: :days,
22
+ week: :weeks,
23
+ fortnight: :fortnights,
24
+ month: :months,
25
+ year: :years }.freeze
26
+
27
+ PLURAL_DURATION_METHODS = SINGULAR_DURATION_METHODS.invert.freeze
28
+
29
+ MSG = 'Prefer `%<number>s.%<correct>s`.'
30
+
31
+ def on_send(node)
32
+ return unless duration_method?(node.method_name)
33
+ return unless literal_number?(node.receiver)
34
+
35
+ return unless offense?(node)
36
+
37
+ add_offense(node)
38
+ end
39
+
40
+ def autocorrect(node)
41
+ lambda do |corrector|
42
+ method_name = node.loc.selector.source
43
+
44
+ corrector.replace(node.loc.selector, correct_method(method_name))
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def message(node)
51
+ number, = *node.receiver
52
+
53
+ format(MSG, number: number,
54
+ correct: correct_method(node.method_name.to_s))
55
+ end
56
+
57
+ def correct_method(method_name)
58
+ if plural_method?(method_name)
59
+ singularize(method_name)
60
+ else
61
+ pluralize(method_name)
62
+ end
63
+ end
64
+
65
+ def offense?(node)
66
+ number, = *node.receiver
67
+
68
+ singular_receiver?(number) && plural_method?(node.method_name) ||
69
+ plural_receiver?(number) && singular_method?(node.method_name)
70
+ end
71
+
72
+ def plural_method?(method_name)
73
+ method_name.to_s.end_with?('s')
74
+ end
75
+
76
+ def singular_method?(method_name)
77
+ !plural_method?(method_name)
78
+ end
79
+
80
+ def singular_receiver?(number)
81
+ number.abs == 1
82
+ end
83
+
84
+ def plural_receiver?(number)
85
+ !singular_receiver?(number)
86
+ end
87
+
88
+ def literal_number?(node)
89
+ node && (node.int_type? || node.float_type?)
90
+ end
91
+
92
+ def pluralize(method_name)
93
+ SINGULAR_DURATION_METHODS.fetch(method_name.to_sym).to_s
94
+ end
95
+
96
+ def singularize(method_name)
97
+ PLURAL_DURATION_METHODS.fetch(method_name.to_sym).to_s
98
+ end
99
+
100
+ def duration_method?(method_name)
101
+ SINGULAR_DURATION_METHODS.key?(method_name) ||
102
+ PLURAL_DURATION_METHODS.key?(method_name)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop checks code that can be written more easily using
7
+ # `Object#presence` defined by Active Support.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # a.present? ? a : nil
12
+ #
13
+ # # bad
14
+ # !a.present? ? nil : a
15
+ #
16
+ # # bad
17
+ # a.blank? ? nil : a
18
+ #
19
+ # # bad
20
+ # !a.blank? ? a : nil
21
+ #
22
+ # # good
23
+ # a.presence
24
+ #
25
+ # @example
26
+ # # bad
27
+ # a.present? ? a : b
28
+ #
29
+ # # bad
30
+ # !a.present? ? b : a
31
+ #
32
+ # # bad
33
+ # a.blank? ? b : a
34
+ #
35
+ # # bad
36
+ # !a.blank? ? a : b
37
+ #
38
+ # # good
39
+ # a.presence || b
40
+ class Presence < Cop
41
+ MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
42
+
43
+ def_node_matcher :redundant_receiver_and_other, <<-PATTERN
44
+ {
45
+ (if
46
+ (send $_recv :present?)
47
+ _recv
48
+ $!begin
49
+ )
50
+ (if
51
+ (send $_recv :blank?)
52
+ $!begin
53
+ _recv
54
+ )
55
+ }
56
+ PATTERN
57
+
58
+ def_node_matcher :redundant_negative_receiver_and_other, <<-PATTERN
59
+ {
60
+ (if
61
+ (send (send $_recv :present?) :!)
62
+ $!begin
63
+ _recv
64
+ )
65
+ (if
66
+ (send (send $_recv :blank?) :!)
67
+ _recv
68
+ $!begin
69
+ )
70
+ }
71
+ PATTERN
72
+
73
+ def on_if(node)
74
+ return if ignore_if_node?(node)
75
+
76
+ redundant_receiver_and_other(node) do |receiver, other|
77
+ unless ignore_other_node?(other) || receiver.nil?
78
+ add_offense(node, message: message(node, receiver, other))
79
+ end
80
+ end
81
+
82
+ redundant_negative_receiver_and_other(node) do |receiver, other|
83
+ unless ignore_other_node?(other) || receiver.nil?
84
+ add_offense(node, message: message(node, receiver, other))
85
+ end
86
+ end
87
+ end
88
+
89
+ def autocorrect(node)
90
+ lambda do |corrector|
91
+ redundant_receiver_and_other(node) do |receiver, other|
92
+ corrector.replace(node.source_range, replacement(receiver, other))
93
+ end
94
+
95
+ redundant_negative_receiver_and_other(node) do |receiver, other|
96
+ corrector.replace(node.source_range, replacement(receiver, other))
97
+ end
98
+ end
99
+ end
100
+
101
+ private
102
+
103
+ def ignore_if_node?(node)
104
+ node.elsif?
105
+ end
106
+
107
+ def ignore_other_node?(node)
108
+ node && (node.if_type? || node.rescue_type? || node.while_type?)
109
+ end
110
+
111
+ def message(node, receiver, other)
112
+ format(MSG,
113
+ prefer: replacement(receiver, other),
114
+ current: node.source)
115
+ end
116
+
117
+ def replacement(receiver, other)
118
+ or_source = other.nil? || other.nil_type? ? '' : " || #{other.source}"
119
+ "#{receiver.source}.presence" + or_source
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop checks for code that can be written with simpler conditionals
7
+ # using `Object#present?` defined by Active Support.
8
+ #
9
+ # Interaction with `Style/UnlessElse`:
10
+ # The configuration of `NotBlank` will not produce an offense in the
11
+ # context of `unless else` if `Style/UnlessElse` is inabled. This is
12
+ # to prevent interference between the auto-correction of the two cops.
13
+ #
14
+ # @example NotNilAndNotEmpty: true (default)
15
+ # # Converts usages of `!nil? && !empty?` to `present?`
16
+ #
17
+ # # bad
18
+ # !foo.nil? && !foo.empty?
19
+ #
20
+ # # bad
21
+ # foo != nil && !foo.empty?
22
+ #
23
+ # # good
24
+ # foo.present?
25
+ #
26
+ # @example NotBlank: true (default)
27
+ # # Converts usages of `!blank?` to `present?`
28
+ #
29
+ # # bad
30
+ # !foo.blank?
31
+ #
32
+ # # bad
33
+ # not foo.blank?
34
+ #
35
+ # # good
36
+ # foo.present?
37
+ #
38
+ # @example UnlessBlank: true (default)
39
+ # # Converts usages of `unless blank?` to `if present?`
40
+ #
41
+ # # bad
42
+ # something unless foo.blank?
43
+ #
44
+ # # good
45
+ # something if foo.present?
46
+ class Present < Cop
47
+ MSG_NOT_BLANK = 'Use `%<prefer>s` instead of `%<current>s`.'
48
+ MSG_EXISTS_AND_NOT_EMPTY = 'Use `%<prefer>s` instead of ' \
49
+ '`%<current>s`.'
50
+ MSG_UNLESS_BLANK = 'Use `if %<prefer>s` instead of ' \
51
+ '`%<current>s`.'
52
+
53
+ def_node_matcher :exists_and_not_empty?, <<-PATTERN
54
+ (and
55
+ {
56
+ (send (send $_ :nil?) :!)
57
+ (send (send $_ :!) :!)
58
+ (send $_ :!= nil)
59
+ $_
60
+ }
61
+ {
62
+ (send (send $_ :empty?) :!)
63
+ }
64
+ )
65
+ PATTERN
66
+
67
+ def_node_matcher :not_blank?, '(send (send $_ :blank?) :!)'
68
+
69
+ def_node_matcher :unless_blank?, <<-PATTERN
70
+ (:if $(send $_ :blank?) {nil? (...)} ...)
71
+ PATTERN
72
+
73
+ def on_send(node)
74
+ return unless cop_config['NotBlank']
75
+
76
+ not_blank?(node) do |receiver|
77
+ add_offense(node,
78
+ message: format(MSG_NOT_BLANK,
79
+ prefer: replacement(receiver),
80
+ current: node.source))
81
+ end
82
+ end
83
+
84
+ def on_and(node)
85
+ return unless cop_config['NotNilAndNotEmpty']
86
+
87
+ exists_and_not_empty?(node) do |var1, var2|
88
+ return unless var1 == var2
89
+
90
+ add_offense(node,
91
+ message: format(MSG_EXISTS_AND_NOT_EMPTY,
92
+ prefer: replacement(var1),
93
+ current: node.source))
94
+ end
95
+ end
96
+
97
+ def on_or(node)
98
+ return unless cop_config['NilOrEmpty']
99
+
100
+ exists_and_not_empty?(node) do |var1, var2|
101
+ return unless var1 == var2
102
+
103
+ add_offense(node, message: MSG_EXISTS_AND_NOT_EMPTY)
104
+ end
105
+ end
106
+
107
+ def on_if(node)
108
+ return unless cop_config['UnlessBlank']
109
+ return unless node.unless?
110
+ return if node.else? && config.for_cop('Style/UnlessElse')['Enabled']
111
+
112
+ unless_blank?(node) do |method_call, receiver|
113
+ range = unless_condition(node, method_call)
114
+ msg = format(MSG_UNLESS_BLANK, prefer: replacement(receiver),
115
+ current: range.source)
116
+ add_offense(node, location: range, message: msg)
117
+ end
118
+ end
119
+
120
+ def autocorrect(node)
121
+ lambda do |corrector|
122
+ method_call, variable1 = unless_blank?(node)
123
+
124
+ if method_call
125
+ corrector.replace(node.loc.keyword, 'if')
126
+ range = method_call.loc.expression
127
+ else
128
+ variable1, _variable2 =
129
+ exists_and_not_empty?(node) || not_blank?(node)
130
+ range = node.loc.expression
131
+ end
132
+
133
+ corrector.replace(range, replacement(variable1))
134
+ end
135
+ end
136
+
137
+ private
138
+
139
+ def unless_condition(node, method_call)
140
+ if node.modifier_form?
141
+ node.loc.keyword.join(node.loc.expression.end)
142
+ else
143
+ node.loc.expression.begin.join(method_call.loc.expression)
144
+ end
145
+ end
146
+
147
+ def replacement(node)
148
+ node.respond_to?(:source) ? "#{node.source}.present?" : 'present?'
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop checks for the use of the `read_attribute` or `write_attribute`
7
+ # methods and recommends square brackets instead.
8
+ #
9
+ # If an attribute is missing from the instance (for example, when
10
+ # initialized by a partial `select`) then `read_attribute`
11
+ # will return nil, but square brackets will raise
12
+ # an `ActiveModel::MissingAttributeError`.
13
+ #
14
+ # Explicitly raising an error in this situation is preferable, and that
15
+ # is why rubocop recommends using square brackets.
16
+ #
17
+ # @example
18
+ #
19
+ # # bad
20
+ # x = read_attribute(:attr)
21
+ # write_attribute(:attr, val)
22
+ #
23
+ # # good
24
+ # x = self[:attr]
25
+ # self[:attr] = val
26
+ class ReadWriteAttribute < Cop
27
+ MSG = 'Prefer `%<prefer>s` over `%<current>s`.'
28
+
29
+ def_node_matcher :read_write_attribute?, <<-PATTERN
30
+ {
31
+ (send nil? :read_attribute _)
32
+ (send nil? :write_attribute _ _)
33
+ }
34
+ PATTERN
35
+
36
+ def on_send(node)
37
+ return unless read_write_attribute?(node)
38
+
39
+ add_offense(node, location: :selector)
40
+ end
41
+
42
+ def autocorrect(node)
43
+ case node.method_name
44
+ when :read_attribute
45
+ replacement = read_attribute_replacement(node)
46
+ when :write_attribute
47
+ replacement = write_attribute_replacement(node)
48
+ end
49
+
50
+ ->(corrector) { corrector.replace(node.source_range, replacement) }
51
+ end
52
+
53
+ private
54
+
55
+ def message(node)
56
+ if node.method?(:read_attribute)
57
+ format(MSG, prefer: 'self[:attr]', current: 'read_attribute(:attr)')
58
+ else
59
+ format(MSG, prefer: 'self[:attr] = val',
60
+ current: 'write_attribute(:attr, val)')
61
+ end
62
+ end
63
+
64
+ def read_attribute_replacement(node)
65
+ "self[#{node.first_argument.source}]"
66
+ end
67
+
68
+ def write_attribute_replacement(node)
69
+ "self[#{node.first_argument.source}] = #{node.last_argument.source}"
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end