rubocop-rails 2.0.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.
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