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,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+ require 'rack/utils'
5
+
6
+ require_relative 'rubocop/rails'
7
+ require_relative 'rubocop/rails/version'
8
+ require_relative 'rubocop/rails/inject'
9
+
10
+ RuboCop::Rails::Inject.defaults!
11
+
12
+ require_relative 'rubocop/cop/rails_cops'
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common functionality for checking target rails version.
6
+ module TargetRailsVersion
7
+ def minimum_target_rails_version(version)
8
+ @minimum_target_rails_version = version
9
+ end
10
+
11
+ def support_target_rails_version?(version)
12
+ @minimum_target_rails_version <= version
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop enforces the consistent use of action filter methods.
7
+ #
8
+ # The cop is configurable and can enforce the use of the older
9
+ # something_filter methods or the newer something_action methods.
10
+ #
11
+ # If the TargetRailsVersion is set to less than 4.0, the cop will enforce
12
+ # the use of filter methods.
13
+ #
14
+ # @example EnforcedStyle: action (default)
15
+ # # bad
16
+ # after_filter :do_stuff
17
+ # append_around_filter :do_stuff
18
+ # skip_after_filter :do_stuff
19
+ #
20
+ # # good
21
+ # after_action :do_stuff
22
+ # append_around_action :do_stuff
23
+ # skip_after_action :do_stuff
24
+ #
25
+ # @example EnforcedStyle: filter
26
+ # # bad
27
+ # after_action :do_stuff
28
+ # append_around_action :do_stuff
29
+ # skip_after_action :do_stuff
30
+ #
31
+ # # good
32
+ # after_filter :do_stuff
33
+ # append_around_filter :do_stuff
34
+ # skip_after_filter :do_stuff
35
+ class ActionFilter < Cop
36
+ extend TargetRailsVersion
37
+ include ConfigurableEnforcedStyle
38
+
39
+ MSG = 'Prefer `%<prefer>s` over `%<current>s`.'
40
+
41
+ FILTER_METHODS = %i[
42
+ after_filter
43
+ append_after_filter
44
+ append_around_filter
45
+ append_before_filter
46
+ around_filter
47
+ before_filter
48
+ prepend_after_filter
49
+ prepend_around_filter
50
+ prepend_before_filter
51
+ skip_after_filter
52
+ skip_around_filter
53
+ skip_before_filter
54
+ skip_filter
55
+ ].freeze
56
+
57
+ ACTION_METHODS = %i[
58
+ after_action
59
+ append_after_action
60
+ append_around_action
61
+ append_before_action
62
+ around_action
63
+ before_action
64
+ prepend_after_action
65
+ prepend_around_action
66
+ prepend_before_action
67
+ skip_after_action
68
+ skip_around_action
69
+ skip_before_action
70
+ skip_action_callback
71
+ ].freeze
72
+
73
+ minimum_target_rails_version 4.0
74
+
75
+ def on_block(node)
76
+ check_method_node(node.send_node)
77
+ end
78
+
79
+ def on_send(node)
80
+ check_method_node(node) unless node.receiver
81
+ end
82
+
83
+ def autocorrect(node)
84
+ lambda do |corrector|
85
+ corrector.replace(node.loc.selector,
86
+ preferred_method(node.loc.selector.source).to_s)
87
+ end
88
+ end
89
+
90
+ private
91
+
92
+ def check_method_node(node)
93
+ return unless bad_methods.include?(node.method_name)
94
+
95
+ add_offense(node, location: :selector)
96
+ end
97
+
98
+ def message(node)
99
+ format(MSG, prefer: preferred_method(node.method_name),
100
+ current: node.method_name)
101
+ end
102
+
103
+ def bad_methods
104
+ style == :action ? FILTER_METHODS : ACTION_METHODS
105
+ end
106
+
107
+ def good_methods
108
+ style == :action ? ACTION_METHODS : FILTER_METHODS
109
+ end
110
+
111
+ def preferred_method(method)
112
+ good_methods[bad_methods.index(method.to_sym)]
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Checks that ActiveRecord aliases are not used. The direct method names
7
+ # are more clear and easier to read.
8
+ #
9
+ # @example
10
+ # #bad
11
+ # Book.update_attributes!(author: 'Alice')
12
+ #
13
+ # #good
14
+ # Book.update!(author: 'Alice')
15
+ class ActiveRecordAliases < Cop
16
+ MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
17
+
18
+ ALIASES = {
19
+ update_attributes: :update,
20
+ update_attributes!: :update!
21
+ }.freeze
22
+
23
+ def on_send(node)
24
+ ALIASES.each do |bad, good|
25
+ next unless node.method?(bad)
26
+
27
+ add_offense(node,
28
+ message: format(MSG, prefer: good, current: bad),
29
+ location: :selector,
30
+ severity: :warning)
31
+ break
32
+ end
33
+ end
34
+
35
+ alias on_csend on_send
36
+
37
+ def autocorrect(node)
38
+ lambda do |corrector|
39
+ corrector.replace(
40
+ node.loc.selector,
41
+ ALIASES[node.method_name].to_s
42
+ )
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Checks for overriding built-in Active Record methods instead of using
7
+ # callbacks.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # class Book < ApplicationRecord
12
+ # def save
13
+ # self.title = title.upcase!
14
+ # super
15
+ # end
16
+ # end
17
+ #
18
+ # # good
19
+ # class Book < ApplicationRecord
20
+ # before_save :upcase_title
21
+ #
22
+ # def upcase_title
23
+ # self.title = title.upcase!
24
+ # end
25
+ # end
26
+ #
27
+ class ActiveRecordOverride < Cop
28
+ MSG =
29
+ 'Use %<prefer>s callbacks instead of overriding the Active Record ' \
30
+ 'method `%<bad>s`.'
31
+ BAD_METHODS = %i[create destroy save update].freeze
32
+ ACTIVE_RECORD_CLASSES = %w[ApplicationRecord ActiveModel::Base
33
+ ActiveRecord::Base].freeze
34
+
35
+ def on_def(node)
36
+ return unless BAD_METHODS.include?(node.method_name)
37
+
38
+ parent_class_name = find_parent_class_name(node)
39
+ return unless active_model?(parent_class_name)
40
+
41
+ return unless node.descendants.any?(&:zsuper_type?)
42
+
43
+ add_offense(node, message: message(node.method_name))
44
+ end
45
+
46
+ private
47
+
48
+ def active_model?(parent_class_name)
49
+ ACTIVE_RECORD_CLASSES.include?(parent_class_name)
50
+ end
51
+
52
+ def callback_names(method_name)
53
+ names = %w[before_ around_ after_].map do |prefix|
54
+ "`#{prefix}#{method_name}`"
55
+ end
56
+
57
+ names[-1] = "or #{names.last}"
58
+
59
+ names.join(', ')
60
+ end
61
+
62
+ def message(method_name)
63
+ format(MSG, prefer: callback_names(method_name), bad: method_name)
64
+ end
65
+
66
+ def find_parent_class_name(node)
67
+ return nil unless node
68
+
69
+ if node.class_type?
70
+ parent_class_name = node.node_parts[1]
71
+
72
+ return nil if parent_class_name.nil?
73
+
74
+ return parent_class_name.source
75
+ end
76
+
77
+ find_parent_class_name(node.parent)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop checks that ActiveSupport aliases to core ruby methods
7
+ # are not used.
8
+ #
9
+ # @example
10
+ # # good
11
+ # 'some_string'.start_with?('prefix')
12
+ # 'some_string'.end_with?('suffix')
13
+ # [1, 2, 'a'] << 'b'
14
+ # [1, 2, 'a'].unshift('b')
15
+ #
16
+ # # bad
17
+ # 'some_string'.starts_with?('prefix')
18
+ # 'some_string'.ends_with?('suffix')
19
+ # [1, 2, 'a'].append('b')
20
+ # [1, 2, 'a'].prepend('b')
21
+ #
22
+ class ActiveSupportAliases < Cop
23
+ MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
24
+
25
+ ALIASES = {
26
+ starts_with?: {
27
+ original: :start_with?, matcher: '(send str :starts_with? _)'
28
+ },
29
+ ends_with?: {
30
+ original: :end_with?, matcher: '(send str :ends_with? _)'
31
+ },
32
+ append: { original: :<<, matcher: '(send array :append _)' },
33
+ prepend: { original: :unshift, matcher: '(send array :prepend _)' }
34
+ }.freeze
35
+
36
+ ALIASES.each do |aliased_method, options|
37
+ def_node_matcher aliased_method, options[:matcher]
38
+ end
39
+
40
+ def on_send(node)
41
+ ALIASES.each_key do |aliased_method|
42
+ register_offense(node, aliased_method) if
43
+ public_send(aliased_method, node)
44
+ end
45
+ end
46
+
47
+ def autocorrect(node)
48
+ return false if append(node)
49
+
50
+ lambda do |corrector|
51
+ method_name = node.loc.selector.source
52
+ replacement = ALIASES[method_name.to_sym][:original]
53
+ corrector.replace(node.loc.selector, replacement.to_s)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def register_offense(node, method_name)
60
+ add_offense(
61
+ node,
62
+ message: format(MSG, prefer: ALIASES[method_name][:original],
63
+ current: method_name)
64
+ )
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop checks that jobs subclass ApplicationJob with Rails 5.0.
7
+ #
8
+ # @example
9
+ #
10
+ # # good
11
+ # class Rails5Job < ApplicationJob
12
+ # # ...
13
+ # end
14
+ #
15
+ # # bad
16
+ # class Rails4Job < ActiveJob::Base
17
+ # # ...
18
+ # end
19
+ class ApplicationJob < Cop
20
+ extend TargetRailsVersion
21
+
22
+ minimum_target_rails_version 5.0
23
+
24
+ MSG = 'Jobs should subclass `ApplicationJob`.'
25
+ SUPERCLASS = 'ApplicationJob'
26
+ BASE_PATTERN = '(const (const nil? :ActiveJob) :Base)'
27
+
28
+ # rubocop:disable Layout/ClassStructure
29
+ include RuboCop::Cop::EnforceSuperclass
30
+ # rubocop:enable Layout/ClassStructure
31
+
32
+ def autocorrect(node)
33
+ lambda do |corrector|
34
+ corrector.replace(node.source_range, self.class::SUPERCLASS)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop checks that models subclass ApplicationRecord with Rails 5.0.
7
+ #
8
+ # @example
9
+ #
10
+ # # good
11
+ # class Rails5Model < ApplicationRecord
12
+ # # ...
13
+ # end
14
+ #
15
+ # # bad
16
+ # class Rails4Model < ActiveRecord::Base
17
+ # # ...
18
+ # end
19
+ class ApplicationRecord < Cop
20
+ extend TargetRailsVersion
21
+
22
+ minimum_target_rails_version 5.0
23
+
24
+ MSG = 'Models should subclass `ApplicationRecord`.'
25
+ SUPERCLASS = 'ApplicationRecord'
26
+ BASE_PATTERN = '(const (const nil? :ActiveRecord) :Base)'
27
+
28
+ # rubocop:disable Layout/ClassStructure
29
+ include RuboCop::Cop::EnforceSuperclass
30
+ # rubocop:enable Layout/ClassStructure
31
+
32
+ def autocorrect(node)
33
+ lambda do |corrector|
34
+ corrector.replace(node.source_range, self.class::SUPERCLASS)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ #
7
+ # Use `assert_not` instead of `assert !`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # assert !x
12
+ #
13
+ # # good
14
+ # assert_not x
15
+ #
16
+ class AssertNot < RuboCop::Cop::Cop
17
+ MSG = 'Prefer `assert_not` over `assert !`.'
18
+
19
+ def_node_matcher :offensive?, '(send nil? :assert (send ... :!) ...)'
20
+
21
+ def on_send(node)
22
+ add_offense(node) if offensive?(node)
23
+ end
24
+
25
+ def autocorrect(node)
26
+ expression = node.loc.expression
27
+
28
+ lambda do |corrector|
29
+ corrector.replace(
30
+ expression,
31
+ corrected_source(expression.source)
32
+ )
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def corrected_source(source)
39
+ source.gsub(/^assert(\(| ) *! */, 'assert_not\\1')
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end