rubocop-rails 2.0.1 → 2.19.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +52 -5
- data/config/default.yml +726 -32
- data/config/obsoletion.yml +17 -0
- data/lib/rubocop/cop/mixin/active_record_helper.rb +106 -0
- data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +32 -0
- data/lib/rubocop/cop/mixin/class_send_node_helper.rb +20 -0
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +40 -0
- data/lib/rubocop/cop/mixin/index_method.rb +165 -0
- data/lib/rubocop/cop/mixin/migrations_helper.rb +26 -0
- data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +112 -0
- data/lib/rubocop/cop/rails/action_controller_test_case.rb +47 -0
- data/lib/rubocop/cop/rails/action_filter.rb +11 -21
- data/lib/rubocop/cop/rails/action_order.rb +116 -0
- data/lib/rubocop/cop/rails/active_record_aliases.rb +23 -24
- data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +143 -0
- data/lib/rubocop/cop/rails/active_record_override.rb +3 -6
- data/lib/rubocop/cop/rails/active_support_aliases.rb +13 -22
- data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
- data/lib/rubocop/cop/rails/add_column_index.rb +61 -0
- data/lib/rubocop/cop/rails/after_commit_override.rb +81 -0
- data/lib/rubocop/cop/rails/application_controller.rb +36 -0
- data/lib/rubocop/cop/rails/application_job.rb +9 -4
- data/lib/rubocop/cop/rails/application_mailer.rb +39 -0
- data/lib/rubocop/cop/rails/application_record.rb +9 -9
- data/lib/rubocop/cop/rails/arel_star.rb +47 -0
- data/lib/rubocop/cop/rails/assert_not.rb +8 -10
- data/lib/rubocop/cop/rails/attribute_default_block_value.rb +90 -0
- data/lib/rubocop/cop/rails/belongs_to.rb +12 -24
- data/lib/rubocop/cop/rails/blank.rb +40 -36
- data/lib/rubocop/cop/rails/bulk_change_table.rb +40 -35
- data/lib/rubocop/cop/rails/compact_blank.rb +111 -0
- data/lib/rubocop/cop/rails/content_tag.rb +93 -0
- data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +22 -15
- data/lib/rubocop/cop/rails/date.rb +41 -36
- data/lib/rubocop/cop/rails/default_scope.rb +61 -0
- data/lib/rubocop/cop/rails/delegate.rb +33 -29
- data/lib/rubocop/cop/rails/delegate_allow_blank.rb +9 -10
- data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +168 -0
- data/lib/rubocop/cop/rails/dot_separated_keys.rb +71 -0
- data/lib/rubocop/cop/rails/duplicate_association.rb +56 -0
- data/lib/rubocop/cop/rails/duplicate_scope.rb +46 -0
- data/lib/rubocop/cop/rails/duration_arithmetic.rb +98 -0
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +76 -31
- data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +82 -0
- data/lib/rubocop/cop/rails/enum_hash.rb +75 -0
- data/lib/rubocop/cop/rails/enum_uniqueness.rb +30 -12
- data/lib/rubocop/cop/rails/environment_comparison.rb +70 -22
- data/lib/rubocop/cop/rails/environment_variable_access.rb +67 -0
- data/lib/rubocop/cop/rails/exit.rb +7 -13
- data/lib/rubocop/cop/rails/expanded_date_range.rb +102 -0
- data/lib/rubocop/cop/rails/file_path.rb +48 -31
- data/lib/rubocop/cop/rails/find_by.rb +43 -24
- data/lib/rubocop/cop/rails/find_by_id.rb +94 -0
- data/lib/rubocop/cop/rails/find_each.rb +42 -18
- data/lib/rubocop/cop/rails/freeze_time.rb +79 -0
- data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +4 -3
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +62 -25
- data/lib/rubocop/cop/rails/helper_instance_variable.rb +32 -4
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +61 -32
- data/lib/rubocop/cop/rails/http_status.rb +27 -23
- data/lib/rubocop/cop/rails/i18n_lazy_lookup.rb +96 -0
- data/lib/rubocop/cop/rails/i18n_locale_assignment.rb +37 -0
- data/lib/rubocop/cop/rails/i18n_locale_texts.rb +110 -0
- data/lib/rubocop/cop/rails/ignored_columns_assignment.rb +50 -0
- data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +9 -16
- data/lib/rubocop/cop/rails/index_by.rb +65 -0
- data/lib/rubocop/cop/rails/index_with.rb +68 -0
- data/lib/rubocop/cop/rails/inquiry.rb +39 -0
- data/lib/rubocop/cop/rails/inverse_of.rb +33 -27
- data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +62 -32
- data/lib/rubocop/cop/rails/link_to_blank.rb +31 -32
- data/lib/rubocop/cop/rails/mailer_name.rb +90 -0
- data/lib/rubocop/cop/rails/match_route.rb +120 -0
- data/lib/rubocop/cop/rails/migration_class_name.rb +63 -0
- data/lib/rubocop/cop/rails/negate_include.rb +42 -0
- data/lib/rubocop/cop/rails/not_null_column.rb +16 -12
- data/lib/rubocop/cop/rails/order_by_id.rb +51 -0
- data/lib/rubocop/cop/rails/output.rb +29 -10
- data/lib/rubocop/cop/rails/output_safety.rb +9 -4
- data/lib/rubocop/cop/rails/pick.rb +64 -0
- data/lib/rubocop/cop/rails/pluck.rb +96 -0
- data/lib/rubocop/cop/rails/pluck_id.rb +59 -0
- data/lib/rubocop/cop/rails/pluck_in_where.rb +71 -0
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +14 -19
- data/lib/rubocop/cop/rails/presence.rb +54 -26
- data/lib/rubocop/cop/rails/present.rb +40 -37
- data/lib/rubocop/cop/rails/rake_environment.rb +112 -0
- data/lib/rubocop/cop/rails/read_write_attribute.rb +56 -18
- data/lib/rubocop/cop/rails/redundant_allow_nil.rb +33 -45
- data/lib/rubocop/cop/rails/redundant_foreign_key.rb +77 -0
- data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +257 -0
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +34 -32
- data/lib/rubocop/cop/rails/redundant_travel_back.rb +57 -0
- data/lib/rubocop/cop/rails/reflection_class_name.rb +56 -7
- data/lib/rubocop/cop/rails/refute_methods.rb +56 -35
- data/lib/rubocop/cop/rails/relative_date_constant.rb +52 -33
- data/lib/rubocop/cop/rails/render_inline.rb +41 -0
- data/lib/rubocop/cop/rails/render_plain_text.rb +71 -0
- data/lib/rubocop/cop/rails/request_referer.rb +10 -11
- data/lib/rubocop/cop/rails/require_dependency.rb +38 -0
- data/lib/rubocop/cop/rails/response_parsed_body.rb +57 -0
- data/lib/rubocop/cop/rails/reversible_migration.rb +122 -82
- data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +66 -0
- data/lib/rubocop/cop/rails/root_join_chain.rb +72 -0
- data/lib/rubocop/cop/rails/root_pathname_methods.rb +238 -0
- data/lib/rubocop/cop/rails/root_public_path.rb +59 -0
- data/lib/rubocop/cop/rails/safe_navigation.rb +55 -43
- data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +50 -0
- data/lib/rubocop/cop/rails/save_bang.rb +89 -63
- data/lib/rubocop/cop/rails/schema_comment.rb +104 -0
- data/lib/rubocop/cop/rails/scope_args.rb +8 -3
- data/lib/rubocop/cop/rails/short_i18n.rb +71 -0
- data/lib/rubocop/cop/rails/skips_model_validations.rb +53 -16
- data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +87 -0
- data/lib/rubocop/cop/rails/strip_heredoc.rb +56 -0
- data/lib/rubocop/cop/rails/table_name_assignment.rb +44 -0
- data/lib/rubocop/cop/rails/three_state_boolean_column.rb +73 -0
- data/lib/rubocop/cop/rails/time_zone.rb +83 -67
- data/lib/rubocop/cop/rails/time_zone_assignment.rb +37 -0
- data/lib/rubocop/cop/rails/to_formatted_s.rb +46 -0
- data/lib/rubocop/cop/rails/to_s_with_argument.rb +78 -0
- data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +49 -0
- data/lib/rubocop/cop/rails/transaction_exit_statement.rb +99 -0
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +40 -49
- data/lib/rubocop/cop/rails/unique_validation_without_index.rb +172 -0
- data/lib/rubocop/cop/rails/unknown_env.rb +52 -21
- data/lib/rubocop/cop/rails/unused_ignored_columns.rb +76 -0
- data/lib/rubocop/cop/rails/validation.rb +54 -23
- data/lib/rubocop/cop/rails/where_equals.rb +102 -0
- data/lib/rubocop/cop/rails/where_exists.rb +138 -0
- data/lib/rubocop/cop/rails/where_missing.rb +118 -0
- data/lib/rubocop/cop/rails/where_not.rb +101 -0
- data/lib/rubocop/cop/rails/where_not_with_multiple_conditions.rb +55 -0
- data/lib/rubocop/cop/rails_cops.rb +78 -8
- data/lib/rubocop/rails/inject.rb +1 -1
- data/lib/rubocop/rails/schema_loader/schema.rb +191 -0
- data/lib/rubocop/rails/schema_loader.rb +61 -0
- data/lib/rubocop/rails/version.rb +5 -1
- data/lib/rubocop/rails.rb +3 -1
- data/lib/rubocop-rails.rb +22 -0
- metadata +120 -19
- data/bin/setup +0 -7
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Checks if collection can be blank-compacted with `compact_blank`.
|
7
|
+
#
|
8
|
+
# @safety
|
9
|
+
# It is unsafe by default because false positives may occur in the
|
10
|
+
# blank check of block arguments to the receiver object.
|
11
|
+
#
|
12
|
+
# For example, `[[1, 2], [3, nil]].reject { |first, second| second.blank? }` and
|
13
|
+
# `[[1, 2], [3, nil]].compact_blank` are not compatible. The same is true for `blank?`.
|
14
|
+
# This will work fine when the receiver is a hash object.
|
15
|
+
#
|
16
|
+
# And `compact_blank!` has different implementations for `Array`, `Hash`, and
|
17
|
+
# `ActionController::Parameters`.
|
18
|
+
# `Array#compact_blank!`, `Hash#compact_blank!` are equivalent to `delete_if(&:blank?)`.
|
19
|
+
# `ActionController::Parameters#compact_blank!` is equivalent to `reject!(&:blank?)`.
|
20
|
+
# If the cop makes a mistake, autocorrected code may get unexpected behavior.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
#
|
24
|
+
# # bad
|
25
|
+
# collection.reject(&:blank?)
|
26
|
+
# collection.reject { |_k, v| v.blank? }
|
27
|
+
#
|
28
|
+
# # good
|
29
|
+
# collection.compact_blank
|
30
|
+
#
|
31
|
+
# # bad
|
32
|
+
# collection.delete_if(&:blank?) # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
|
33
|
+
# collection.delete_if { |_k, v| v.blank? } # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
|
34
|
+
# collection.reject!(&:blank?) # Same behavior as `ActionController::Parameters#compact_blank!`
|
35
|
+
# collection.reject! { |_k, v| v.blank? } # Same behavior as `ActionController::Parameters#compact_blank!`
|
36
|
+
#
|
37
|
+
# # good
|
38
|
+
# collection.compact_blank!
|
39
|
+
#
|
40
|
+
class CompactBlank < Base
|
41
|
+
include RangeHelp
|
42
|
+
extend AutoCorrector
|
43
|
+
extend TargetRailsVersion
|
44
|
+
|
45
|
+
MSG = 'Use `%<preferred_method>s` instead.'
|
46
|
+
RESTRICT_ON_SEND = %i[reject delete_if reject!].freeze
|
47
|
+
|
48
|
+
minimum_target_rails_version 6.1
|
49
|
+
|
50
|
+
def_node_matcher :reject_with_block?, <<~PATTERN
|
51
|
+
(block
|
52
|
+
(send _ {:reject :delete_if :reject!})
|
53
|
+
$(args ...)
|
54
|
+
(send
|
55
|
+
$(lvar _) :blank?))
|
56
|
+
PATTERN
|
57
|
+
|
58
|
+
def_node_matcher :reject_with_block_pass?, <<~PATTERN
|
59
|
+
(send _ {:reject :delete_if :reject!}
|
60
|
+
(block_pass
|
61
|
+
(sym :blank?)))
|
62
|
+
PATTERN
|
63
|
+
|
64
|
+
def on_send(node)
|
65
|
+
return unless bad_method?(node)
|
66
|
+
|
67
|
+
range = offense_range(node)
|
68
|
+
preferred_method = preferred_method(node)
|
69
|
+
add_offense(range, message: format(MSG, preferred_method: preferred_method)) do |corrector|
|
70
|
+
corrector.replace(range, preferred_method)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def bad_method?(node)
|
77
|
+
return true if reject_with_block_pass?(node)
|
78
|
+
|
79
|
+
if (arguments, receiver_in_block = reject_with_block?(node.parent))
|
80
|
+
return use_single_value_block_argument?(arguments, receiver_in_block) ||
|
81
|
+
use_hash_value_block_argument?(arguments, receiver_in_block)
|
82
|
+
end
|
83
|
+
|
84
|
+
false
|
85
|
+
end
|
86
|
+
|
87
|
+
def use_single_value_block_argument?(arguments, receiver_in_block)
|
88
|
+
arguments.length == 1 && arguments[0].source == receiver_in_block.source
|
89
|
+
end
|
90
|
+
|
91
|
+
def use_hash_value_block_argument?(arguments, receiver_in_block)
|
92
|
+
arguments.length == 2 && arguments[1].source == receiver_in_block.source
|
93
|
+
end
|
94
|
+
|
95
|
+
def offense_range(node)
|
96
|
+
end_pos = if node.parent&.block_type? && node.parent&.send_node == node
|
97
|
+
node.parent.source_range.end_pos
|
98
|
+
else
|
99
|
+
node.source_range.end_pos
|
100
|
+
end
|
101
|
+
|
102
|
+
range_between(node.loc.selector.begin_pos, end_pos)
|
103
|
+
end
|
104
|
+
|
105
|
+
def preferred_method(node)
|
106
|
+
node.method?(:reject) ? 'compact_blank' : 'compact_blank!'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Checks legacy syntax usage of `tag`
|
7
|
+
#
|
8
|
+
# NOTE: Allow `tag` when the first argument is a variable because
|
9
|
+
# `tag(name)` is simpler rather than `tag.public_send(name)`.
|
10
|
+
# And this cop will be renamed to something like `LegacyTag` in the future. (e.g. RuboCop Rails 2.0)
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# tag(:p)
|
15
|
+
# tag(:br, class: 'classname')
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# tag.p
|
19
|
+
# tag.br(class: 'classname')
|
20
|
+
# tag(name, class: 'classname')
|
21
|
+
class ContentTag < Base
|
22
|
+
include RangeHelp
|
23
|
+
extend AutoCorrector
|
24
|
+
extend TargetRailsVersion
|
25
|
+
|
26
|
+
minimum_target_rails_version 5.1
|
27
|
+
|
28
|
+
MSG = 'Use `tag.%<preferred_method>s` instead of `tag(%<current_argument>s)`.'
|
29
|
+
RESTRICT_ON_SEND = %i[tag].freeze
|
30
|
+
|
31
|
+
def on_new_investigation
|
32
|
+
@corrected_nodes = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def on_send(node)
|
36
|
+
return unless node.receiver.nil?
|
37
|
+
return if node.arguments.count >= 3
|
38
|
+
|
39
|
+
first_argument = node.first_argument
|
40
|
+
return if !first_argument || allowed_argument?(first_argument) || corrected_ancestor?(node)
|
41
|
+
|
42
|
+
preferred_method = node.first_argument.value.to_s.underscore
|
43
|
+
message = format(MSG, preferred_method: preferred_method, current_argument: first_argument.source)
|
44
|
+
|
45
|
+
register_offense(node, message, preferred_method)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def corrected_ancestor?(node)
|
51
|
+
node.each_ancestor(:send).any? { |ancestor| @corrected_nodes&.include?(ancestor) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def allowed_argument?(argument)
|
55
|
+
argument.variable? ||
|
56
|
+
argument.send_type? ||
|
57
|
+
argument.const_type? ||
|
58
|
+
argument.splat_type? ||
|
59
|
+
allowed_name?(argument) ||
|
60
|
+
!argument.respond_to?(:value)
|
61
|
+
end
|
62
|
+
|
63
|
+
def register_offense(node, message, preferred_method)
|
64
|
+
add_offense(node, message: message) do |corrector|
|
65
|
+
autocorrect(corrector, node, preferred_method)
|
66
|
+
|
67
|
+
@corrected_nodes ||= Set.new.compare_by_identity
|
68
|
+
@corrected_nodes.add(node)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def autocorrect(corrector, node, preferred_method)
|
73
|
+
range = correction_range(node)
|
74
|
+
|
75
|
+
rest_args = node.arguments.drop(1)
|
76
|
+
replacement = "tag.#{preferred_method}(#{rest_args.map(&:source).join(', ')})"
|
77
|
+
|
78
|
+
corrector.replace(range, replacement)
|
79
|
+
end
|
80
|
+
|
81
|
+
def allowed_name?(argument)
|
82
|
+
return false unless argument.str_type? || argument.sym_type?
|
83
|
+
|
84
|
+
!/^[a-zA-Z-][a-zA-Z\-0-9]*$/.match?(argument.value)
|
85
|
+
end
|
86
|
+
|
87
|
+
def correction_range(node)
|
88
|
+
range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -3,10 +3,12 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
7
|
-
# when creating a new table.
|
6
|
+
# Checks the migration for which timestamps are not included when creating a new table.
|
8
7
|
# In many cases, timestamps are useful information and should be added.
|
9
8
|
#
|
9
|
+
# NOTE: Allow `timestamps` not written when `id: false` because this emphasizes respecting
|
10
|
+
# user's editing intentions.
|
11
|
+
#
|
10
12
|
# @example
|
11
13
|
# # bad
|
12
14
|
# create_table :users
|
@@ -40,39 +42,44 @@ module RuboCop
|
|
40
42
|
#
|
41
43
|
# t.datetime :updated_at, default: -> { 'CURRENT_TIMESTAMP' }
|
42
44
|
# end
|
43
|
-
|
45
|
+
#
|
46
|
+
# # good
|
47
|
+
# create_table :users, articles, id: false do |t|
|
48
|
+
# t.integer :user_id
|
49
|
+
# t.integer :article_id
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
class CreateTableWithTimestamps < Base
|
53
|
+
include ActiveRecordMigrationsHelper
|
54
|
+
|
44
55
|
MSG = 'Add timestamps when creating a new table.'
|
56
|
+
RESTRICT_ON_SEND = %i[create_table].freeze
|
45
57
|
|
46
|
-
|
47
|
-
(
|
48
|
-
(send nil? :create_table ...)
|
49
|
-
(args (arg _var))
|
50
|
-
_)
|
58
|
+
def_node_search :use_id_false_option?, <<~PATTERN
|
59
|
+
(pair (sym :id) (false))
|
51
60
|
PATTERN
|
52
61
|
|
53
|
-
def_node_matcher :create_table_with_timestamps_proc?,
|
62
|
+
def_node_matcher :create_table_with_timestamps_proc?, <<~PATTERN
|
54
63
|
(send nil? :create_table (sym _) ... (block-pass (sym :timestamps)))
|
55
64
|
PATTERN
|
56
65
|
|
57
|
-
def_node_search :timestamps_included?,
|
66
|
+
def_node_search :timestamps_included?, <<~PATTERN
|
58
67
|
(send _var :timestamps ...)
|
59
68
|
PATTERN
|
60
69
|
|
61
|
-
def_node_search :created_at_or_updated_at_included?,
|
70
|
+
def_node_search :created_at_or_updated_at_included?, <<~PATTERN
|
62
71
|
(send _var :datetime
|
63
72
|
{(sym {:created_at :updated_at})(str {"created_at" "updated_at"})}
|
64
73
|
...)
|
65
74
|
PATTERN
|
66
75
|
|
67
76
|
def on_send(node)
|
68
|
-
return
|
77
|
+
return if !node.command?(:create_table) || use_id_false_option?(node)
|
69
78
|
|
70
79
|
parent = node.parent
|
71
80
|
|
72
81
|
if create_table_with_block?(parent)
|
73
|
-
if parent.body.nil? || !time_columns_included?(parent.body)
|
74
|
-
add_offense(parent)
|
75
|
-
end
|
82
|
+
add_offense(parent) if parent.body.nil? || !time_columns_included?(parent.body)
|
76
83
|
elsif create_table_with_timestamps_proc?(node)
|
77
84
|
# nothing to do
|
78
85
|
else
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Checks for the correct use of Date methods,
|
7
7
|
# such as Date.today, Date.current etc.
|
8
8
|
#
|
9
9
|
# Using `Date.today` is dangerous, because it doesn't know anything about
|
@@ -12,54 +12,58 @@ module RuboCop
|
|
12
12
|
# The cop also reports warnings when you are using `to_time` method,
|
13
13
|
# because it doesn't know about Rails time zone either.
|
14
14
|
#
|
15
|
-
# Two styles are supported for this cop. When EnforcedStyle is 'strict'
|
15
|
+
# Two styles are supported for this cop. When `EnforcedStyle` is 'strict'
|
16
16
|
# then the Date methods `today`, `current`, `yesterday`, and `tomorrow`
|
17
17
|
# are prohibited and the usage of both `to_time`
|
18
18
|
# and 'to_time_in_current_zone' are reported as warning.
|
19
19
|
#
|
20
|
-
# When EnforcedStyle is
|
21
|
-
# and only `to_time` is reported as warning.
|
20
|
+
# When `EnforcedStyle` is `flexible` then only `Date.today` is prohibited.
|
22
21
|
#
|
23
|
-
#
|
22
|
+
# And you can set a warning for `to_time` with `AllowToTime: false`.
|
23
|
+
# `AllowToTime` is `true` by default to prevent false positive on `DateTime` object.
|
24
|
+
#
|
25
|
+
# @example EnforcedStyle: flexible (default)
|
24
26
|
# # bad
|
25
|
-
# Date.current
|
26
|
-
# Date.yesterday
|
27
27
|
# Date.today
|
28
|
-
# date.to_time
|
29
28
|
#
|
30
29
|
# # good
|
31
30
|
# Time.zone.today
|
32
31
|
# Time.zone.today - 1.day
|
32
|
+
# Date.current
|
33
|
+
# Date.yesterday
|
34
|
+
# date.in_time_zone
|
33
35
|
#
|
34
|
-
# @example EnforcedStyle:
|
36
|
+
# @example EnforcedStyle: strict
|
35
37
|
# # bad
|
38
|
+
# Date.current
|
39
|
+
# Date.yesterday
|
36
40
|
# Date.today
|
37
|
-
# date.to_time
|
38
41
|
#
|
39
42
|
# # good
|
40
43
|
# Time.zone.today
|
41
44
|
# Time.zone.today - 1.day
|
42
|
-
# Date.current
|
43
|
-
# Date.yesterday
|
44
|
-
# date.in_time_zone
|
45
45
|
#
|
46
|
-
|
46
|
+
# @example AllowToTime: true (default)
|
47
|
+
# # good
|
48
|
+
# date.to_time
|
49
|
+
#
|
50
|
+
# @example AllowToTime: false
|
51
|
+
# # bad
|
52
|
+
# date.to_time
|
53
|
+
class Date < Base
|
47
54
|
include ConfigurableEnforcedStyle
|
48
55
|
|
49
|
-
MSG = 'Do not use `Date.%<method_called>s` without zone. Use '
|
50
|
-
|
56
|
+
MSG = 'Do not use `Date.%<method_called>s` without zone. Use `Time.zone.%<day>s` instead.'
|
57
|
+
|
58
|
+
MSG_SEND = 'Do not use `%<method>s` on Date objects, because they know nothing about the time zone in use.'
|
51
59
|
|
52
|
-
|
53
|
-
'know nothing about the time zone in use.'
|
60
|
+
RESTRICT_ON_SEND = %i[to_time to_time_in_current_zone].freeze
|
54
61
|
|
55
62
|
BAD_DAYS = %i[today current yesterday tomorrow].freeze
|
56
63
|
|
57
|
-
DEPRECATED_METHODS = [
|
58
|
-
{ deprecated: 'to_time_in_current_zone', relevant: 'in_time_zone' }
|
59
|
-
].freeze
|
64
|
+
DEPRECATED_METHODS = [{ deprecated: 'to_time_in_current_zone', relevant: 'in_time_zone' }].freeze
|
60
65
|
|
61
|
-
DEPRECATED_MSG = '`%<deprecated>s` is deprecated. '
|
62
|
-
'Use `%<relevant>s` instead.'
|
66
|
+
DEPRECATED_MSG = '`%<deprecated>s` is deprecated. Use `%<relevant>s` instead.'
|
63
67
|
|
64
68
|
def on_const(node)
|
65
69
|
mod, klass = *node.children
|
@@ -71,26 +75,24 @@ module RuboCop
|
|
71
75
|
|
72
76
|
def on_send(node)
|
73
77
|
return unless node.receiver && bad_methods.include?(node.method_name)
|
74
|
-
|
78
|
+
return if allow_to_time? && node.method?(:to_time)
|
75
79
|
return if safe_chain?(node) || safe_to_time?(node)
|
76
80
|
|
77
81
|
check_deprecated_methods(node)
|
78
82
|
|
79
|
-
add_offense(node,
|
80
|
-
message: format(MSG_SEND, method: node.method_name))
|
83
|
+
add_offense(node.loc.selector, message: format(MSG_SEND, method: node.method_name))
|
81
84
|
end
|
82
85
|
alias on_csend on_send
|
83
86
|
|
84
87
|
private
|
85
88
|
|
86
89
|
def check_deprecated_methods(node)
|
87
|
-
DEPRECATED_METHODS.each do |
|
88
|
-
next unless node.
|
90
|
+
DEPRECATED_METHODS.each do |method|
|
91
|
+
next unless node.method?(method[:deprecated].to_sym)
|
92
|
+
|
93
|
+
message = format(DEPRECATED_MSG, deprecated: method[:deprecated], relevant: method[:relevant])
|
89
94
|
|
90
|
-
add_offense(node,
|
91
|
-
message: format(DEPRECATED_MSG,
|
92
|
-
deprecated: deprecated,
|
93
|
-
relevant: relevant))
|
95
|
+
add_offense(node.loc.selector, message: message)
|
94
96
|
end
|
95
97
|
end
|
96
98
|
|
@@ -104,10 +106,9 @@ module RuboCop
|
|
104
106
|
day = method_name
|
105
107
|
day = 'today' if method_name == 'current'
|
106
108
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
day: day))
|
109
|
+
message = format(MSG, method_called: method_name, day: day)
|
110
|
+
|
111
|
+
add_offense(node.loc.selector, message: message)
|
111
112
|
end
|
112
113
|
|
113
114
|
def extract_method_chain(node)
|
@@ -140,6 +141,10 @@ module RuboCop
|
|
140
141
|
end
|
141
142
|
end
|
142
143
|
|
144
|
+
def allow_to_time?
|
145
|
+
cop_config.fetch('AllowToTime', true)
|
146
|
+
end
|
147
|
+
|
143
148
|
def good_days
|
144
149
|
style == :strict ? [] : %i[current yesterday tomorrow]
|
145
150
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Looks for uses of `default_scope`.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# default_scope -> { where(hidden: false) }
|
11
|
+
#
|
12
|
+
# # good
|
13
|
+
# scope :published, -> { where(hidden: false) }
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# def self.default_scope
|
17
|
+
# where(hidden: false)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# def self.published
|
22
|
+
# where(hidden: false)
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
class DefaultScope < Base
|
26
|
+
MSG = 'Avoid use of `default_scope`. It is better to use explicitly named scopes.'
|
27
|
+
RESTRICT_ON_SEND = %i[default_scope].freeze
|
28
|
+
|
29
|
+
def_node_matcher :method_call?, <<~PATTERN
|
30
|
+
(send nil? :default_scope ...)
|
31
|
+
PATTERN
|
32
|
+
|
33
|
+
def_node_matcher :class_method_definition?, <<~PATTERN
|
34
|
+
(defs _ :default_scope args ...)
|
35
|
+
PATTERN
|
36
|
+
|
37
|
+
def_node_matcher :eigenclass_method_definition?, <<~PATTERN
|
38
|
+
(sclass (self) $(def :default_scope args ...))
|
39
|
+
PATTERN
|
40
|
+
|
41
|
+
def on_send(node)
|
42
|
+
return unless method_call?(node)
|
43
|
+
|
44
|
+
add_offense(node.loc.selector)
|
45
|
+
end
|
46
|
+
|
47
|
+
def on_defs(node)
|
48
|
+
return unless class_method_definition?(node)
|
49
|
+
|
50
|
+
add_offense(node.loc.name)
|
51
|
+
end
|
52
|
+
|
53
|
+
def on_sclass(node)
|
54
|
+
eigenclass_method_definition?(node) do |default_scope|
|
55
|
+
add_offense(default_scope.loc.name)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Looks for delegations that could have been created
|
7
7
|
# automatically with the `delegate` method.
|
8
8
|
#
|
9
9
|
# Safe navigation `&.` is ignored because Rails' `allow_nil`
|
@@ -24,6 +24,14 @@ module RuboCop
|
|
24
24
|
# # good
|
25
25
|
# delegate :bar, to: :foo
|
26
26
|
#
|
27
|
+
# # bad
|
28
|
+
# def bar
|
29
|
+
# self.bar
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# delegate :bar, to: :self
|
34
|
+
#
|
27
35
|
# # good
|
28
36
|
# def bar
|
29
37
|
# foo&.bar
|
@@ -52,36 +60,39 @@ module RuboCop
|
|
52
60
|
#
|
53
61
|
# # good
|
54
62
|
# delegate :bar, to: :foo, prefix: true
|
55
|
-
class Delegate <
|
63
|
+
class Delegate < Base
|
64
|
+
extend AutoCorrector
|
65
|
+
include VisibilityHelp
|
66
|
+
|
56
67
|
MSG = 'Use `delegate` to define delegations.'
|
57
68
|
|
58
|
-
def_node_matcher :delegate?,
|
69
|
+
def_node_matcher :delegate?, <<~PATTERN
|
59
70
|
(def _method_name _args
|
60
|
-
(send (send nil? _) _ ...))
|
71
|
+
(send {(send nil? _) (self)} _ ...))
|
61
72
|
PATTERN
|
62
73
|
|
63
74
|
def on_def(node)
|
64
75
|
return unless trivial_delegate?(node)
|
65
76
|
return if private_or_protected_delegation(node)
|
66
77
|
|
67
|
-
|
78
|
+
register_offense(node)
|
68
79
|
end
|
69
80
|
|
70
|
-
|
71
|
-
|
72
|
-
|
81
|
+
private
|
82
|
+
|
83
|
+
def register_offense(node)
|
84
|
+
add_offense(node.loc.keyword) do |corrector|
|
85
|
+
body = node.body
|
73
86
|
|
74
|
-
|
75
|
-
delegation << ['prefix: true']
|
76
|
-
end
|
87
|
+
receiver = body.receiver.self_type? ? 'self' : ":#{body.receiver.method_name}"
|
77
88
|
|
78
|
-
|
79
|
-
|
89
|
+
delegation = ["delegate :#{body.method_name}", "to: #{receiver}"]
|
90
|
+
delegation << ['prefix: true'] if node.method?(prefixed_method_name(node.body))
|
91
|
+
|
92
|
+
corrector.replace(node, delegation.join(', '))
|
80
93
|
end
|
81
94
|
end
|
82
95
|
|
83
|
-
private
|
84
|
-
|
85
96
|
def trivial_delegate?(def_node)
|
86
97
|
delegate?(def_node) &&
|
87
98
|
method_name_matches?(def_node.method_name, def_node.body) &&
|
@@ -94,15 +105,12 @@ module RuboCop
|
|
94
105
|
return false if arg_array.size != argument_array.size
|
95
106
|
|
96
107
|
arg_array.zip(argument_array).all? do |arg, argument|
|
97
|
-
arg.arg_type? &&
|
98
|
-
argument.lvar_type? &&
|
99
|
-
arg.children == argument.children
|
108
|
+
arg.arg_type? && argument.lvar_type? && arg.children == argument.children
|
100
109
|
end
|
101
110
|
end
|
102
111
|
|
103
112
|
def method_name_matches?(method_name, body)
|
104
|
-
method_name == body.method_name ||
|
105
|
-
include_prefix_case? && method_name == prefixed_method_name(body)
|
113
|
+
method_name == body.method_name || (include_prefix_case? && method_name == prefixed_method_name(body))
|
106
114
|
end
|
107
115
|
|
108
116
|
def include_prefix_case?
|
@@ -110,21 +118,17 @@ module RuboCop
|
|
110
118
|
end
|
111
119
|
|
112
120
|
def prefixed_method_name(body)
|
121
|
+
return '' if body.receiver.self_type?
|
122
|
+
|
113
123
|
[body.receiver.method_name, body.method_name].join('_').to_sym
|
114
124
|
end
|
115
125
|
|
116
126
|
def private_or_protected_delegation(node)
|
117
|
-
|
118
|
-
private_or_protected_before(line) ||
|
119
|
-
private_or_protected_inline(line)
|
120
|
-
end
|
121
|
-
|
122
|
-
def private_or_protected_before(line)
|
123
|
-
(processed_source[0..line].map(&:strip) & %w[private protected]).any?
|
127
|
+
private_or_protected_inline(node) || node_visibility(node) != :public
|
124
128
|
end
|
125
129
|
|
126
|
-
def private_or_protected_inline(
|
127
|
-
processed_source[
|
130
|
+
def private_or_protected_inline(node)
|
131
|
+
processed_source[node.first_line - 1].strip.match?(/\A(private )|(protected )/)
|
128
132
|
end
|
129
133
|
end
|
130
134
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Looks for delegations that pass :allow_blank as an option
|
7
7
|
# instead of :allow_nil. :allow_blank is not a valid option to pass
|
8
8
|
# to ActiveSupport#delegate.
|
9
9
|
#
|
@@ -13,22 +13,21 @@ module RuboCop
|
|
13
13
|
#
|
14
14
|
# # good
|
15
15
|
# delegate :foo, to: :bar, allow_nil: true
|
16
|
-
class DelegateAllowBlank <
|
16
|
+
class DelegateAllowBlank < Base
|
17
|
+
extend AutoCorrector
|
18
|
+
|
17
19
|
MSG = '`allow_blank` is not a valid option, use `allow_nil`.'
|
20
|
+
RESTRICT_ON_SEND = %i[delegate].freeze
|
18
21
|
|
19
|
-
def_node_matcher :allow_blank_option,
|
22
|
+
def_node_matcher :allow_blank_option, <<~PATTERN
|
20
23
|
(send nil? :delegate _ (hash <$(pair (sym :allow_blank) true) ...>))
|
21
24
|
PATTERN
|
22
25
|
|
23
26
|
def on_send(node)
|
24
|
-
allow_blank_option(node)
|
25
|
-
add_offense(offending_node)
|
26
|
-
end
|
27
|
-
end
|
27
|
+
return unless (offending_node = allow_blank_option(node))
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
corrector.replace(pair_node.key.source_range, 'allow_nil')
|
29
|
+
add_offense(offending_node) do |corrector|
|
30
|
+
corrector.replace(offending_node.key, 'allow_nil')
|
32
31
|
end
|
33
32
|
end
|
34
33
|
end
|