brew vendor-gems: commit updates.
This commit is contained in:
parent
e557e79668
commit
211a889ce8
@ -8,7 +8,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/i18n-1.8.5/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/minitest-5.14.2/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thread_safe-0.3.6/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tzinfo-1.2.8/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/zeitwerk-2.4.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/zeitwerk-2.4.2/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/activesupport-6.0.3.4/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.8/lib"
|
||||
@ -79,7 +79,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.10
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-1.7.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.3.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.9.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rails-2.8.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rails-2.9.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.0.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.5.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.5.0/lib"
|
||||
|
||||
@ -98,6 +98,12 @@ Rails/ApplicationRecord:
|
||||
VersionAdded: '0.49'
|
||||
VersionChanged: '2.5'
|
||||
|
||||
Rails/ArelStar:
|
||||
Description: 'Enforces `Arel.star` instead of `"*"` for expanded columns.'
|
||||
Enabled: true
|
||||
SafeAutoCorrect: false
|
||||
VersionAdded: '2.9'
|
||||
|
||||
Rails/AssertNot:
|
||||
Description: 'Use `assert_not` instead of `assert !`.'
|
||||
Enabled: true
|
||||
@ -105,6 +111,13 @@ Rails/AssertNot:
|
||||
Include:
|
||||
- '**/test/**/*'
|
||||
|
||||
Rails/AttributeDefaultBlockValue:
|
||||
Description: 'Pass method call in block for attribute option `default`.'
|
||||
Enabled: pending
|
||||
VersionAdded: '2.9'
|
||||
Include:
|
||||
- 'models/**/*'
|
||||
|
||||
Rails/BelongsTo:
|
||||
Description: >-
|
||||
Use `optional: true` instead of `required: false` for
|
||||
@ -269,8 +282,15 @@ Rails/FindEach:
|
||||
StyleGuide: 'https://rails.rubystyle.guide#find-each'
|
||||
Enabled: true
|
||||
VersionAdded: '0.30'
|
||||
VersionChanged: '2.9'
|
||||
Include:
|
||||
- app/models/**/*.rb
|
||||
IgnoredMethods:
|
||||
# Methods that don't work well with `find_each`.
|
||||
- order
|
||||
- limit
|
||||
- select
|
||||
- lock
|
||||
|
||||
Rails/HasAndBelongsToMany:
|
||||
Description: 'Prefer has_many :through to has_and_belongs_to_many.'
|
||||
@ -387,7 +407,9 @@ Rails/NegateInclude:
|
||||
Description: 'Prefer `collection.exclude?(obj)` over `!collection.include?(obj)`.'
|
||||
StyleGuide: 'https://rails.rubystyle.guide#exclude'
|
||||
Enabled: 'pending'
|
||||
Safe: false
|
||||
VersionAdded: '2.7'
|
||||
VersionChanged: '2.9'
|
||||
|
||||
Rails/NotNullColumn:
|
||||
Description: 'Do not add a NOT NULL column without a default value.'
|
||||
@ -653,6 +675,10 @@ Rails/SquishedSQLHeredocs:
|
||||
StyleGuide: 'https://rails.rubystyle.guide/#squished-heredocs'
|
||||
Enabled: 'pending'
|
||||
VersionAdded: '2.8'
|
||||
VersionChanged: '2.9'
|
||||
# Some SQL syntax (e.g. PostgreSQL comments and functions) requires newlines
|
||||
# to be preserved in order to work, thus auto-correction is not safe.
|
||||
SafeAutoCorrect: false
|
||||
|
||||
Rails/TimeZone:
|
||||
Description: 'Checks the correct usage of time zone aware methods.'
|
||||
@ -705,6 +731,12 @@ Rails/Validation:
|
||||
Include:
|
||||
- app/models/**/*.rb
|
||||
|
||||
Rails/WhereEquals:
|
||||
Description: 'Pass conditions to `where` as a hash instead of manually constructing SQL.'
|
||||
StyleGuide: 'https://rails.rubystyle.guide/#hash-conditions'
|
||||
Enabled: 'pending'
|
||||
VersionAdded: '2.9'
|
||||
|
||||
Rails/WhereExists:
|
||||
Description: 'Prefer `exists?(...)` over `where(...).exists?`.'
|
||||
Enabled: 'pending'
|
||||
@ -717,7 +749,7 @@ Rails/WhereExists:
|
||||
|
||||
Rails/WhereNot:
|
||||
Description: 'Use `where.not(...)` instead of manually constructing negated SQL in `where`.'
|
||||
StyleGuide: 'https://rails.rubystyle.guide/#where-not'
|
||||
StyleGuide: 'https://rails.rubystyle.guide/#hash-conditions'
|
||||
Enabled: 'pending'
|
||||
VersionAdded: '2.8'
|
||||
|
||||
@ -35,10 +35,11 @@ module RuboCop
|
||||
table_name = find_set_table_name(class_node).to_a.last&.first_argument
|
||||
return table_name.value.to_s if table_name
|
||||
|
||||
namespaces = class_node.each_ancestor(:class, :module)
|
||||
[class_node, *namespaces]
|
||||
class_nodes = class_node.defined_module.each_node
|
||||
namespaces = class_node.each_ancestor(:class, :module).map(&:identifier)
|
||||
[*class_nodes, *namespaces]
|
||||
.reverse
|
||||
.map { |klass| klass.identifier.children[1] }.join('_')
|
||||
.map { |node| node.children[1] }.join('_')
|
||||
.tableize
|
||||
end
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
# Common functionality for enforcing a specific superclass.
|
||||
module EnforceSuperclass
|
||||
def self.included(base)
|
||||
base.def_node_matcher :class_definition, <<~PATTERN
|
||||
(class (const _ !:#{base::SUPERCLASS}) #{base::BASE_PATTERN} ...)
|
||||
PATTERN
|
||||
|
||||
base.def_node_matcher :class_new_definition, <<~PATTERN
|
||||
[!^(casgn {nil? cbase} :#{base::SUPERCLASS} ...)
|
||||
!^^(casgn {nil? cbase} :#{base::SUPERCLASS} (block ...))
|
||||
(send (const {nil? cbase} :Class) :new #{base::BASE_PATTERN})]
|
||||
PATTERN
|
||||
end
|
||||
|
||||
def on_class(node)
|
||||
class_definition(node) do
|
||||
register_offense(node.children[1])
|
||||
end
|
||||
end
|
||||
|
||||
def on_send(node)
|
||||
class_new_definition(node) do
|
||||
register_offense(node.children.last)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def register_offense(offense_node)
|
||||
add_offense(offense_node) do |corrector|
|
||||
corrector.replace(offense_node.source_range, self.class::SUPERCLASS)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -4,6 +4,8 @@ module RuboCop
|
||||
module Cop
|
||||
# Common functionality for Rails/IndexBy and Rails/IndexWith
|
||||
module IndexMethod # rubocop:disable Metrics/ModuleLength
|
||||
RESTRICT_ON_SEND = %i[each_with_object to_h map collect []].freeze
|
||||
|
||||
def on_block(node)
|
||||
on_bad_each_with_object(node) do |*match|
|
||||
handle_possible_offense(node, match, 'each_with_object')
|
||||
@ -32,13 +34,6 @@ module RuboCop
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
correction = prepare_correction(node)
|
||||
execute_correction(corrector, node, correction)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# @abstract Implemented with `def_node_matcher`
|
||||
@ -67,9 +62,11 @@ module RuboCop
|
||||
return if captures.noop_transformation?
|
||||
|
||||
add_offense(
|
||||
node,
|
||||
message: "Prefer `#{new_method_name}` over `#{match_desc}`."
|
||||
)
|
||||
node, message: "Prefer `#{new_method_name}` over `#{match_desc}`."
|
||||
) do |corrector|
|
||||
correction = prepare_correction(node)
|
||||
execute_correction(corrector, node, correction)
|
||||
end
|
||||
end
|
||||
|
||||
def extract_captures(match)
|
||||
@ -119,7 +116,7 @@ module RuboCop
|
||||
end
|
||||
|
||||
# Internal helper class to hold autocorrect data
|
||||
Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do # rubocop:disable Metrics/BlockLength
|
||||
Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
|
||||
def self.from_each_with_object(node, match)
|
||||
new(match, node, 0, 0)
|
||||
end
|
||||
@ -29,8 +29,9 @@ module RuboCop
|
||||
# after_filter :do_stuff
|
||||
# append_around_filter :do_stuff
|
||||
# skip_after_filter :do_stuff
|
||||
class ActionFilter < Cop
|
||||
class ActionFilter < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Prefer `%<prefer>s` over `%<current>s`.'
|
||||
|
||||
@ -66,6 +67,8 @@ module RuboCop
|
||||
skip_action_callback
|
||||
].freeze
|
||||
|
||||
RESTRICT_ON_SEND = FILTER_METHODS + ACTION_METHODS
|
||||
|
||||
def on_block(node)
|
||||
check_method_node(node.send_node)
|
||||
end
|
||||
@ -74,24 +77,17 @@ module RuboCop
|
||||
check_method_node(node) unless node.receiver
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
corrector.replace(node.loc.selector,
|
||||
preferred_method(node.loc.selector.source).to_s)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_method_node(node)
|
||||
return unless bad_methods.include?(node.method_name)
|
||||
method_name = node.method_name
|
||||
return unless bad_methods.include?(method_name)
|
||||
|
||||
add_offense(node, location: :selector)
|
||||
end
|
||||
message = format(MSG, prefer: preferred_method(method_name), current: method_name)
|
||||
|
||||
def message(node)
|
||||
format(MSG, prefer: preferred_method(node.method_name),
|
||||
current: node.method_name)
|
||||
add_offense(node.loc.selector, message: message) do |corrector|
|
||||
corrector.replace(node.loc.selector, preferred_method(node.loc.selector.source))
|
||||
end
|
||||
end
|
||||
|
||||
def bad_methods
|
||||
@ -12,7 +12,9 @@ module RuboCop
|
||||
#
|
||||
# #good
|
||||
# Book.update!(author: 'Alice')
|
||||
class ActiveRecordAliases < Cop
|
||||
class ActiveRecordAliases < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
||||
|
||||
ALIASES = {
|
||||
@ -20,28 +22,22 @@ module RuboCop
|
||||
update_attributes!: :update!
|
||||
}.freeze
|
||||
|
||||
def on_send(node)
|
||||
ALIASES.each do |bad, good|
|
||||
next unless node.method?(bad)
|
||||
RESTRICT_ON_SEND = ALIASES.keys.freeze
|
||||
|
||||
add_offense(node,
|
||||
message: format(MSG, prefer: good, current: bad),
|
||||
location: :selector,
|
||||
severity: :warning)
|
||||
break
|
||||
def on_send(node)
|
||||
method_name = node.method_name
|
||||
alias_method = ALIASES[method_name]
|
||||
|
||||
add_offense(
|
||||
node.loc.selector,
|
||||
message: format(MSG, prefer: alias_method, current: method_name),
|
||||
severity: :warning
|
||||
) do |corrector|
|
||||
corrector.replace(node.loc.selector, alias_method)
|
||||
end
|
||||
end
|
||||
|
||||
alias on_csend on_send
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
corrector.replace(
|
||||
node.loc.selector,
|
||||
ALIASES[node.method_name].to_s
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -19,7 +19,9 @@ module RuboCop
|
||||
# after_commit :after_commit_callback
|
||||
# end
|
||||
#
|
||||
class ActiveRecordCallbacksOrder < Cop
|
||||
class ActiveRecordCallbacksOrder < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = '`%<current>s` is supposed to appear before `%<previous>s`.'
|
||||
|
||||
CALLBACKS_IN_ORDER = %i[
|
||||
@ -55,17 +57,20 @@ module RuboCop
|
||||
index = CALLBACKS_ORDER_MAP[callback]
|
||||
|
||||
if index < previous_index
|
||||
message = format(MSG, current: callback,
|
||||
previous: previous_callback)
|
||||
add_offense(node, message: message)
|
||||
message = format(MSG, current: callback, previous: previous_callback)
|
||||
add_offense(node, message: message) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
previous_index = index
|
||||
previous_callback = callback
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Autocorrect by swapping between two nodes autocorrecting them
|
||||
def autocorrect(node)
|
||||
def autocorrect(corrector, node)
|
||||
previous = left_siblings_of(node).reverse_each.find do |sibling|
|
||||
callback?(sibling)
|
||||
end
|
||||
@ -73,14 +78,10 @@ module RuboCop
|
||||
current_range = source_range_with_comment(node)
|
||||
previous_range = source_range_with_comment(previous)
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.insert_before(previous_range, current_range.source)
|
||||
corrector.remove(current_range)
|
||||
end
|
||||
corrector.insert_before(previous_range, current_range.source)
|
||||
corrector.remove(current_range)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def defined_callbacks(class_node)
|
||||
class_def = class_node.body
|
||||
|
||||
@ -121,7 +122,7 @@ module RuboCop
|
||||
|
||||
processed_source.comments_before_line(annotation_line)
|
||||
.reverse_each do |comment|
|
||||
if comment.location.line == annotation_line
|
||||
if comment.location.line == annotation_line && !inline_comment?(comment)
|
||||
first_comment = comment
|
||||
annotation_line -= 1
|
||||
end
|
||||
@ -130,6 +131,10 @@ module RuboCop
|
||||
start_line_position(first_comment || node)
|
||||
end
|
||||
|
||||
def inline_comment?(comment)
|
||||
!comment_line?(comment.loc.expression.source_line)
|
||||
end
|
||||
|
||||
def start_line_position(node)
|
||||
buffer.line_range(node.loc.line).begin_pos - 1
|
||||
end
|
||||
@ -24,7 +24,7 @@ module RuboCop
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class ActiveRecordOverride < Cop
|
||||
class ActiveRecordOverride < Base
|
||||
MSG =
|
||||
'Use %<prefer>s callbacks instead of overriding the Active Record ' \
|
||||
'method `%<bad>s`.'
|
||||
@ -19,8 +19,11 @@ module RuboCop
|
||||
# [1, 2, 'a'].append('b')
|
||||
# [1, 2, 'a'].prepend('b')
|
||||
#
|
||||
class ActiveSupportAliases < Cop
|
||||
class ActiveSupportAliases < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
||||
RESTRICT_ON_SEND = %i[starts_with? ends_with? append prepend].freeze
|
||||
|
||||
ALIASES = {
|
||||
starts_with?: {
|
||||
@ -39,30 +42,18 @@ module RuboCop
|
||||
|
||||
def on_send(node)
|
||||
ALIASES.each_key do |aliased_method|
|
||||
register_offense(node, aliased_method) if
|
||||
public_send(aliased_method, node)
|
||||
next unless public_send(aliased_method, node)
|
||||
|
||||
preferred_method = ALIASES[aliased_method][:original]
|
||||
message = format(MSG, prefer: preferred_method, current: aliased_method)
|
||||
|
||||
add_offense(node, message: message) do |corrector|
|
||||
next if append(node)
|
||||
|
||||
corrector.replace(node.loc.selector, preferred_method)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
return false if append(node)
|
||||
|
||||
lambda do |corrector|
|
||||
method_name = node.loc.selector.source
|
||||
replacement = ALIASES[method_name.to_sym][:original]
|
||||
corrector.replace(node.loc.selector, replacement.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def register_offense(node, method_name)
|
||||
add_offense(
|
||||
node,
|
||||
message: format(MSG, prefer: ALIASES[method_name][:original],
|
||||
current: method_name)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -31,7 +31,7 @@ module RuboCop
|
||||
# after_create_commit :log_create_action
|
||||
# after_update_commit :log_update_action
|
||||
#
|
||||
class AfterCommitOverride < Cop
|
||||
class AfterCommitOverride < Base
|
||||
MSG = 'There can only be one `after_*_commit :%<name>s` hook defined for a model.'
|
||||
|
||||
AFTER_COMMIT_CALLBACKS = %i[
|
||||
@ -16,7 +16,9 @@ module RuboCop
|
||||
# class MyController < ActionController::Base
|
||||
# # ...
|
||||
# end
|
||||
class ApplicationController < Cop
|
||||
class ApplicationController < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Controllers should subclass `ApplicationController`.'
|
||||
SUPERCLASS = 'ApplicationController'
|
||||
BASE_PATTERN = '(const (const nil? :ActionController) :Base)'
|
||||
@ -24,12 +26,6 @@ module RuboCop
|
||||
# rubocop:disable Layout/ClassStructure
|
||||
include RuboCop::Cop::EnforceSuperclass
|
||||
# rubocop:enable Layout/ClassStructure
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
corrector.replace(node.source_range, self.class::SUPERCLASS)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -16,7 +16,8 @@ module RuboCop
|
||||
# class Rails4Job < ActiveJob::Base
|
||||
# # ...
|
||||
# end
|
||||
class ApplicationJob < Cop
|
||||
class ApplicationJob < Base
|
||||
extend AutoCorrector
|
||||
extend TargetRailsVersion
|
||||
|
||||
minimum_target_rails_version 5.0
|
||||
@ -16,7 +16,8 @@ module RuboCop
|
||||
# class MyMailer < ActionMailer::Base
|
||||
# # ...
|
||||
# end
|
||||
class ApplicationMailer < Cop
|
||||
class ApplicationMailer < Base
|
||||
extend AutoCorrector
|
||||
extend TargetRailsVersion
|
||||
|
||||
minimum_target_rails_version 5.0
|
||||
@ -28,12 +29,6 @@ module RuboCop
|
||||
# rubocop:disable Layout/ClassStructure
|
||||
include RuboCop::Cop::EnforceSuperclass
|
||||
# rubocop:enable Layout/ClassStructure
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
corrector.replace(node.source_range, self.class::SUPERCLASS)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -16,7 +16,8 @@ module RuboCop
|
||||
# class Rails4Model < ActiveRecord::Base
|
||||
# # ...
|
||||
# end
|
||||
class ApplicationRecord < Cop
|
||||
class ApplicationRecord < Base
|
||||
extend AutoCorrector
|
||||
extend TargetRailsVersion
|
||||
|
||||
minimum_target_rails_version 5.0
|
||||
@ -28,12 +29,6 @@ module RuboCop
|
||||
# rubocop:disable Layout/ClassStructure
|
||||
include RuboCop::Cop::EnforceSuperclass
|
||||
# rubocop:enable Layout/ClassStructure
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
corrector.replace(node.source_range, self.class::SUPERCLASS)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,41 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Rails
|
||||
# This cop prevents usage of `"*"` on an Arel::Table column reference.
|
||||
#
|
||||
# Using `arel_table["*"]` causes the outputted string to be a literal
|
||||
# quoted asterisk (e.g. <tt>`my_model`.`*`</tt>). This causes the
|
||||
# database to look for a column named <tt>`*`</tt> (or `"*"`) as opposed
|
||||
# to expanding the column list as one would likely expect.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# MyTable.arel_table["*"]
|
||||
#
|
||||
# # good
|
||||
# MyTable.arel_table[Arel.star]
|
||||
#
|
||||
class ArelStar < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `Arel.star` instead of `"*"` for expanded column lists.'
|
||||
|
||||
RESTRICT_ON_SEND = %i[[]].freeze
|
||||
|
||||
def_node_matcher :star_bracket?, <<~PATTERN
|
||||
(send {const (send _ :arel_table)} :[] $(str "*"))
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
return unless (star = star_bracket?(node))
|
||||
|
||||
add_offense(star) do |corrector|
|
||||
corrector.replace(star.loc.expression, 'Arel.star')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -13,23 +13,21 @@ module RuboCop
|
||||
# # good
|
||||
# assert_not x
|
||||
#
|
||||
class AssertNot < RuboCop::Cop::Cop
|
||||
class AssertNot < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Prefer `assert_not` over `assert !`.'
|
||||
RESTRICT_ON_SEND = %i[assert].freeze
|
||||
|
||||
def_node_matcher :offensive?, '(send nil? :assert (send ... :!) ...)'
|
||||
|
||||
def on_send(node)
|
||||
add_offense(node) if offensive?(node)
|
||||
end
|
||||
return unless offensive?(node)
|
||||
|
||||
def autocorrect(node)
|
||||
expression = node.loc.expression
|
||||
add_offense(node) do |corrector|
|
||||
expression = node.loc.expression
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.replace(
|
||||
expression,
|
||||
corrected_source(expression.source)
|
||||
)
|
||||
corrector.replace(expression, corrected_source(expression.source))
|
||||
end
|
||||
end
|
||||
|
||||
@ -0,0 +1,90 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Rails
|
||||
# This cop looks for `attribute` class methods that specify a `:default` option
|
||||
# which value is an array, string literal or method call without a block.
|
||||
# It will accept all other values, such as string, symbol, integer and float literals
|
||||
# as well as constants.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# class User < ApplicationRecord
|
||||
# attribute :confirmed_at, :datetime, default: Time.zone.now
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# class User < ApplicationRecord
|
||||
# attribute :confirmed_at, :datetime, default: -> { Time.zone.now }
|
||||
# end
|
||||
#
|
||||
# # bad
|
||||
# class User < ApplicationRecord
|
||||
# attribute :roles, :string, array: true, default: []
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# class User < ApplicationRecord
|
||||
# attribute :roles, :string, array: true, default: -> { [] }
|
||||
# end
|
||||
#
|
||||
# # bad
|
||||
# class User < ApplicationRecord
|
||||
# attribute :configuration, default: {}
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# class User < ApplicationRecord
|
||||
# attribute :configuration, default: -> { {} }
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# class User < ApplicationRecord
|
||||
# attribute :role, :string, default: :customer
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# class User < ApplicationRecord
|
||||
# attribute :activated, :boolean, default: false
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# class User < ApplicationRecord
|
||||
# attribute :login_count, :integer, default: 0
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# class User < ApplicationRecord
|
||||
# FOO = 123
|
||||
# attribute :custom_attribute, :integer, default: FOO
|
||||
# end
|
||||
class AttributeDefaultBlockValue < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Pass method in a block to `:default` option.'
|
||||
RESTRICT_ON_SEND = %i[attribute].freeze
|
||||
TYPE_OFFENDERS = %i[send array hash].freeze
|
||||
|
||||
def_node_matcher :default_attribute, <<~PATTERN
|
||||
(send nil? :attribute _ ?_ (hash <$#attribute ...>))
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :attribute, '(pair (sym :default) $_)'
|
||||
|
||||
def on_send(node)
|
||||
default_attribute(node) do |attribute|
|
||||
value = attribute.children.last
|
||||
return unless TYPE_OFFENDERS.any? { |type| value.type == type }
|
||||
|
||||
add_offense(value) do |corrector|
|
||||
expression = default_attribute(node).children.last
|
||||
|
||||
corrector.replace(value, "-> { #{expression.source} }")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -50,7 +50,8 @@ module RuboCop
|
||||
#
|
||||
# @see https://guides.rubyonrails.org/5_0_release_notes.html
|
||||
# @see https://github.com/rails/rails/pull/18937
|
||||
class BelongsTo < Cop
|
||||
class BelongsTo < Base
|
||||
extend AutoCorrector
|
||||
extend TargetRailsVersion
|
||||
|
||||
minimum_target_rails_version 5.0
|
||||
@ -64,6 +65,7 @@ module RuboCop
|
||||
'option is deprecated and you want to use `optional: false`. ' \
|
||||
'In most configurations, this is the default and you can omit ' \
|
||||
'this option altogether'
|
||||
RESTRICT_ON_SEND = %i[belongs_to].freeze
|
||||
|
||||
def_node_matcher :match_belongs_to_with_options, <<~PATTERN
|
||||
(send _ :belongs_to _
|
||||
@ -72,27 +74,16 @@ module RuboCop
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
match_belongs_to_with_options(node) do |_option_node, option_value|
|
||||
message =
|
||||
match_belongs_to_with_options(node) do |option_node, option_value|
|
||||
message, replacement =
|
||||
if option_value.true_type?
|
||||
SUPERFLOUS_REQUIRE_TRUE_MSG
|
||||
[SUPERFLOUS_REQUIRE_TRUE_MSG, 'optional: false']
|
||||
elsif option_value.false_type?
|
||||
SUPERFLOUS_REQUIRE_FALSE_MSG
|
||||
[SUPERFLOUS_REQUIRE_FALSE_MSG, 'optional: true']
|
||||
end
|
||||
|
||||
add_offense(node, message: message, location: :selector)
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
option_node, option_value = match_belongs_to_with_options(node)
|
||||
return unless option_node
|
||||
|
||||
lambda do |corrector|
|
||||
if option_value.true_type?
|
||||
corrector.replace(option_node.loc.expression, 'optional: false')
|
||||
elsif option_value.false_type?
|
||||
corrector.replace(option_node.loc.expression, 'optional: true')
|
||||
add_offense(node.loc.selector, message: message) do |corrector|
|
||||
corrector.replace(option_node.loc.expression, replacement)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -53,11 +53,14 @@ module RuboCop
|
||||
# def blank?
|
||||
# !present?
|
||||
# end
|
||||
class Blank < Cop
|
||||
class Blank < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG_NIL_OR_EMPTY = 'Use `%<prefer>s` instead of `%<current>s`.'
|
||||
MSG_NOT_PRESENT = 'Use `%<prefer>s` instead of `%<current>s`.'
|
||||
MSG_UNLESS_PRESENT = 'Use `if %<prefer>s` instead of ' \
|
||||
'`%<current>s`.'
|
||||
RESTRICT_ON_SEND = %i[!].freeze
|
||||
|
||||
# `(send nil $_)` is not actually a valid match for an offense. Nodes
|
||||
# that have a single method call on the left hand side
|
||||
@ -93,10 +96,10 @@ module RuboCop
|
||||
# accepts !present? if its in the body of a `blank?` method
|
||||
next if defining_blank?(node.parent)
|
||||
|
||||
add_offense(node,
|
||||
message: format(MSG_NOT_PRESENT,
|
||||
prefer: replacement(receiver),
|
||||
current: node.source))
|
||||
message = format(MSG_NOT_PRESENT, prefer: replacement(receiver), current: node.source)
|
||||
add_offense(node, message: message) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -106,10 +109,10 @@ module RuboCop
|
||||
nil_or_empty?(node) do |var1, var2|
|
||||
return unless var1 == var2
|
||||
|
||||
add_offense(node,
|
||||
message: format(MSG_NIL_OR_EMPTY,
|
||||
prefer: replacement(var1),
|
||||
current: node.source))
|
||||
message = format(MSG_NIL_OR_EMPTY, prefer: replacement(var1), current: node.source)
|
||||
add_offense(node, message: message) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -121,32 +124,29 @@ module RuboCop
|
||||
unless_present?(node) do |method_call, receiver|
|
||||
range = unless_condition(node, method_call)
|
||||
|
||||
add_offense(node,
|
||||
location: range,
|
||||
message: format(MSG_UNLESS_PRESENT,
|
||||
prefer: replacement(receiver),
|
||||
current: range.source))
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
method_call, variable1 = unless_present?(node)
|
||||
|
||||
if method_call
|
||||
corrector.replace(node.loc.keyword, 'if')
|
||||
range = method_call.loc.expression
|
||||
else
|
||||
variable1, _variable2 = nil_or_empty?(node) || not_present?(node)
|
||||
range = node.loc.expression
|
||||
message = format(MSG_UNLESS_PRESENT, prefer: replacement(receiver), current: range.source)
|
||||
add_offense(range, message: message) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
|
||||
corrector.replace(range, replacement(variable1))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
method_call, variable1 = unless_present?(node)
|
||||
|
||||
if method_call
|
||||
corrector.replace(node.loc.keyword, 'if')
|
||||
range = method_call.loc.expression
|
||||
else
|
||||
variable1, _variable2 = nil_or_empty?(node) || not_present?(node)
|
||||
range = node.loc.expression
|
||||
end
|
||||
|
||||
corrector.replace(range, replacement(variable1))
|
||||
end
|
||||
|
||||
def unless_condition(node, method_call)
|
||||
if node.modifier_form?
|
||||
node.loc.keyword.join(node.loc.expression.end)
|
||||
@ -65,7 +65,7 @@ module RuboCop
|
||||
#
|
||||
# @see https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_table
|
||||
# @see https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html
|
||||
class BulkChangeTable < Cop
|
||||
class BulkChangeTable < Base
|
||||
MSG_FOR_CHANGE_TABLE = <<~MSG.chomp
|
||||
You can combine alter queries using `bulk: true` options.
|
||||
MSG
|
||||
@ -18,42 +18,42 @@ module RuboCop
|
||||
# tag.p('Hello world!')
|
||||
# tag.br
|
||||
# content_tag(name, 'Hello world!')
|
||||
class ContentTag < Cop
|
||||
class ContentTag < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
extend TargetRailsVersion
|
||||
|
||||
minimum_target_rails_version 5.1
|
||||
|
||||
MSG = 'Use `tag` instead of `content_tag`.'
|
||||
RESTRICT_ON_SEND = %i[content_tag].freeze
|
||||
|
||||
def on_send(node)
|
||||
return unless node.method?(:content_tag)
|
||||
|
||||
first_argument = node.first_argument
|
||||
return unless first_argument
|
||||
|
||||
return if first_argument.variable? || first_argument.send_type? || first_argument.const_type?
|
||||
|
||||
add_offense(node)
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
if method_name?(node.first_argument)
|
||||
range = correction_range(node)
|
||||
|
||||
rest_args = node.arguments.drop(1)
|
||||
replacement = "tag.#{node.first_argument.value.to_s.underscore}(#{rest_args.map(&:source).join(', ')})"
|
||||
|
||||
corrector.replace(range, replacement)
|
||||
else
|
||||
corrector.replace(node.loc.selector, 'tag')
|
||||
end
|
||||
add_offense(node) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
if method_name?(node.first_argument)
|
||||
range = correction_range(node)
|
||||
|
||||
rest_args = node.arguments.drop(1)
|
||||
replacement = "tag.#{node.first_argument.value.to_s.underscore}(#{rest_args.map(&:source).join(', ')})"
|
||||
|
||||
corrector.replace(range, replacement)
|
||||
else
|
||||
corrector.replace(node.loc.selector, 'tag')
|
||||
end
|
||||
end
|
||||
|
||||
def method_name?(node)
|
||||
return false unless node.str_type? || node.sym_type?
|
||||
|
||||
@ -40,8 +40,9 @@ module RuboCop
|
||||
#
|
||||
# t.datetime :updated_at, default: -> { 'CURRENT_TIMESTAMP' }
|
||||
# end
|
||||
class CreateTableWithTimestamps < Cop
|
||||
class CreateTableWithTimestamps < Base
|
||||
MSG = 'Add timestamps when creating a new table.'
|
||||
RESTRICT_ON_SEND = %i[create_table].freeze
|
||||
|
||||
def_node_matcher :create_table_with_block?, <<~PATTERN
|
||||
(block
|
||||
@ -43,7 +43,7 @@ module RuboCop
|
||||
# Date.yesterday
|
||||
# date.in_time_zone
|
||||
#
|
||||
class Date < Cop
|
||||
class Date < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
MSG = 'Do not use `Date.%<method_called>s` without zone. Use ' \
|
||||
@ -52,6 +52,8 @@ module RuboCop
|
||||
MSG_SEND = 'Do not use `%<method>s` on Date objects, because they ' \
|
||||
'know nothing about the time zone in use.'
|
||||
|
||||
RESTRICT_ON_SEND = %i[to_time to_time_in_current_zone].freeze
|
||||
|
||||
BAD_DAYS = %i[today current yesterday tomorrow].freeze
|
||||
|
||||
DEPRECATED_METHODS = [
|
||||
@ -76,8 +78,7 @@ module RuboCop
|
||||
|
||||
check_deprecated_methods(node)
|
||||
|
||||
add_offense(node, location: :selector,
|
||||
message: format(MSG_SEND, method: node.method_name))
|
||||
add_offense(node.loc.selector, message: format(MSG_SEND, method: node.method_name))
|
||||
end
|
||||
alias on_csend on_send
|
||||
|
||||
@ -87,10 +88,9 @@ module RuboCop
|
||||
DEPRECATED_METHODS.each do |method|
|
||||
next unless node.method?(method[:deprecated].to_sym)
|
||||
|
||||
add_offense(node, location: :selector,
|
||||
message: format(DEPRECATED_MSG,
|
||||
deprecated: method[:deprecated],
|
||||
relevant: method[:relevant]))
|
||||
message = format(DEPRECATED_MSG, deprecated: method[:deprecated], relevant: method[:relevant])
|
||||
|
||||
add_offense(node.loc.selector, message: message)
|
||||
end
|
||||
end
|
||||
|
||||
@ -104,10 +104,9 @@ module RuboCop
|
||||
day = method_name
|
||||
day = 'today' if method_name == 'current'
|
||||
|
||||
add_offense(node, location: :selector,
|
||||
message: format(MSG,
|
||||
method_called: method_name,
|
||||
day: day))
|
||||
message = format(MSG, method_called: method_name, day: day)
|
||||
|
||||
add_offense(node.loc.selector, message: message)
|
||||
end
|
||||
|
||||
def extract_method_chain(node)
|
||||
@ -22,8 +22,9 @@ module RuboCop
|
||||
# where(hidden: false)
|
||||
# end
|
||||
#
|
||||
class DefaultScope < Cop
|
||||
class DefaultScope < Base
|
||||
MSG = 'Avoid use of `default_scope`. It is better to use explicitly named scopes.'
|
||||
RESTRICT_ON_SEND = %i[default_scope].freeze
|
||||
|
||||
def_node_matcher :method_call?, <<~PATTERN
|
||||
(send nil? :default_scope ...)
|
||||
@ -38,15 +39,21 @@ module RuboCop
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
add_offense(node, location: :selector) if method_call?(node)
|
||||
return unless method_call?(node)
|
||||
|
||||
add_offense(node.loc.selector)
|
||||
end
|
||||
|
||||
def on_defs(node)
|
||||
add_offense(node, location: :name) if class_method_definition?(node)
|
||||
return unless class_method_definition?(node)
|
||||
|
||||
add_offense(node.loc.name)
|
||||
end
|
||||
|
||||
def on_sclass(node)
|
||||
eigenclass_method_definition?(node) { |default_scope| add_offense(default_scope, location: :name) }
|
||||
eigenclass_method_definition?(node) do |default_scope|
|
||||
add_offense(default_scope.loc.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -52,7 +52,9 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# delegate :bar, to: :foo, prefix: true
|
||||
class Delegate < Cop
|
||||
class Delegate < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `delegate` to define delegations.'
|
||||
|
||||
def_node_matcher :delegate?, <<~PATTERN
|
||||
@ -64,22 +66,20 @@ module RuboCop
|
||||
return unless trivial_delegate?(node)
|
||||
return if private_or_protected_delegation(node)
|
||||
|
||||
add_offense(node, location: :keyword)
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
delegation = ["delegate :#{node.body.method_name}",
|
||||
"to: :#{node.body.receiver.method_name}"]
|
||||
|
||||
delegation << ['prefix: true'] if node.method?(prefixed_method_name(node.body))
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.replace(node.source_range, delegation.join(', '))
|
||||
end
|
||||
register_offense(node)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def register_offense(node)
|
||||
add_offense(node.loc.keyword) do |corrector|
|
||||
delegation = ["delegate :#{node.body.method_name}", "to: :#{node.body.receiver.method_name}"]
|
||||
delegation << ['prefix: true'] if node.method?(prefixed_method_name(node.body))
|
||||
|
||||
corrector.replace(node.source_range, delegation.join(', '))
|
||||
end
|
||||
end
|
||||
|
||||
def trivial_delegate?(def_node)
|
||||
delegate?(def_node) &&
|
||||
method_name_matches?(def_node.method_name, def_node.body) &&
|
||||
@ -13,22 +13,21 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# delegate :foo, to: :bar, allow_nil: true
|
||||
class DelegateAllowBlank < Cop
|
||||
class DelegateAllowBlank < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = '`allow_blank` is not a valid option, use `allow_nil`.'
|
||||
RESTRICT_ON_SEND = %i[delegate].freeze
|
||||
|
||||
def_node_matcher :allow_blank_option, <<~PATTERN
|
||||
(send nil? :delegate _ (hash <$(pair (sym :allow_blank) true) ...>))
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
allow_blank_option(node) do |offending_node|
|
||||
add_offense(offending_node)
|
||||
end
|
||||
end
|
||||
return unless (offending_node = allow_blank_option(node))
|
||||
|
||||
def autocorrect(pair_node)
|
||||
lambda do |corrector|
|
||||
corrector.replace(pair_node.key.source_range, 'allow_nil')
|
||||
add_offense(offending_node) do |corrector|
|
||||
corrector.replace(offending_node.key.source_range, 'allow_nil')
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -31,7 +31,9 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# Gem::Specification.find_by_name('backend').gem_dir
|
||||
class DynamicFindBy < Cop
|
||||
class DynamicFindBy < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<static_name>s` instead of dynamic `%<method>s`.'
|
||||
METHOD_PATTERN = /^find_by_(.+?)(!)?$/.freeze
|
||||
|
||||
@ -43,25 +45,24 @@ module RuboCop
|
||||
return unless static_name
|
||||
return if node.arguments.any?(&:splat_type?)
|
||||
|
||||
add_offense(node,
|
||||
message: format(MSG, static_name: static_name,
|
||||
method: method_name))
|
||||
message = format(MSG, static_name: static_name, method: method_name)
|
||||
add_offense(node, message: message) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
alias on_csend on_send
|
||||
|
||||
def autocorrect(node)
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
keywords = column_keywords(node.method_name)
|
||||
|
||||
return if keywords.size != node.arguments.size
|
||||
|
||||
lambda do |corrector|
|
||||
autocorrect_method_name(corrector, node)
|
||||
autocorrect_argument_keywords(corrector, node, keywords)
|
||||
end
|
||||
autocorrect_method_name(corrector, node)
|
||||
autocorrect_argument_keywords(corrector, node, keywords)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def allowed_invocation?(node)
|
||||
allowed_method?(node) || allowed_receiver?(node) ||
|
||||
whitelisted?(node)
|
||||
@ -17,9 +17,12 @@ module RuboCop
|
||||
# # good
|
||||
# enum status: { active: 0, archived: 1 }
|
||||
#
|
||||
class EnumHash < Cop
|
||||
class EnumHash < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Enum defined as an array found in `%<enum>s` enum declaration. '\
|
||||
'Use hash syntax instead.'
|
||||
RESTRICT_ON_SEND = %i[enum].freeze
|
||||
|
||||
def_node_matcher :enum?, <<~PATTERN
|
||||
(send nil? :enum (hash $...))
|
||||
@ -35,19 +38,17 @@ module RuboCop
|
||||
key, array = array_pair?(pair)
|
||||
next unless key
|
||||
|
||||
add_offense(array, message: format(MSG, enum: enum_name(key)))
|
||||
add_offense(array, message: format(MSG, enum: enum_name(key))) do |corrector|
|
||||
hash = array.children.each_with_index.map do |elem, index|
|
||||
"#{source(elem)} => #{index}"
|
||||
end.join(', ')
|
||||
|
||||
corrector.replace(array.loc.expression, "{#{hash}}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
hash = node.children.each_with_index.map do |elem, index|
|
||||
"#{source(elem)} => #{index}"
|
||||
end.join(', ')
|
||||
|
||||
->(corrector) { corrector.replace(node.loc.expression, "{#{hash}}") }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def enum_name(key)
|
||||
@ -17,11 +17,12 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# enum status: [:active, :archived]
|
||||
class EnumUniqueness < Cop
|
||||
class EnumUniqueness < Base
|
||||
include Duplication
|
||||
|
||||
MSG = 'Duplicate value `%<value>s` found in `%<enum>s` ' \
|
||||
'enum declaration.'
|
||||
RESTRICT_ON_SEND = %i[enum].freeze
|
||||
|
||||
def_node_matcher :enum?, <<~PATTERN
|
||||
(send nil? :enum (hash $...))
|
||||
@ -15,12 +15,16 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# Rails.env.production?
|
||||
class EnvironmentComparison < Cop
|
||||
class EnvironmentComparison < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Favor `%<bang>sRails.env.%<env>s?` over `%<source>s`.'
|
||||
|
||||
SYM_MSG = 'Do not compare `Rails.env` with a symbol, it will always ' \
|
||||
'evaluate to `false`.'
|
||||
|
||||
RESTRICT_ON_SEND = %i[== !=].freeze
|
||||
|
||||
def_node_matcher :comparing_str_env_with_rails_env_on_lhs?, <<~PATTERN
|
||||
(send
|
||||
(send (const {nil? cbase} :Rails) :env)
|
||||
@ -62,28 +66,28 @@ module RuboCop
|
||||
comparing_str_env_with_rails_env_on_rhs?(node))
|
||||
env, = *env_node
|
||||
bang = node.method?(:!=) ? '!' : ''
|
||||
message = format(MSG, bang: bang, env: env, source: node.source)
|
||||
|
||||
add_offense(node, message: format(
|
||||
MSG, bang: bang, env: env, source: node.source
|
||||
))
|
||||
add_offense(node, message: message) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
|
||||
if comparing_sym_env_with_rails_env_on_lhs?(node) ||
|
||||
comparing_sym_env_with_rails_env_on_rhs?(node)
|
||||
add_offense(node, message: SYM_MSG)
|
||||
end
|
||||
end
|
||||
return unless comparing_sym_env_with_rails_env_on_lhs?(node) || comparing_sym_env_with_rails_env_on_rhs?(node)
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
replacement = build_predicate_method(node)
|
||||
|
||||
corrector.replace(node.source_range, replacement)
|
||||
add_offense(node, message: SYM_MSG) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
replacement = build_predicate_method(node)
|
||||
|
||||
corrector.replace(node.source_range, replacement)
|
||||
end
|
||||
|
||||
def build_predicate_method(node)
|
||||
if rails_env_on_lhs?(node)
|
||||
build_predicate_method_for_rails_env_on_lhs(node)
|
||||
@ -23,27 +23,21 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# raise 'a bad error has happened'
|
||||
class Exit < Cop
|
||||
class Exit < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
MSG = 'Do not use `exit` in Rails applications.'
|
||||
TARGET_METHODS = %i[exit exit!].freeze
|
||||
RESTRICT_ON_SEND = %i[exit exit!].freeze
|
||||
EXPLICIT_RECEIVERS = %i[Kernel Process].freeze
|
||||
|
||||
def on_send(node)
|
||||
add_offense(node, location: :selector) if offending_node?(node)
|
||||
add_offense(node.loc.selector) if offending_node?(node)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def offending_node?(node)
|
||||
right_method_name?(node.method_name) &&
|
||||
right_argument_count?(node.arguments) &&
|
||||
right_receiver?(node.receiver)
|
||||
end
|
||||
|
||||
def right_method_name?(method_name)
|
||||
TARGET_METHODS.include?(method_name)
|
||||
right_argument_count?(node.arguments) && right_receiver?(node.receiver)
|
||||
end
|
||||
|
||||
# More than 1 argument likely means it is a different
|
||||
@ -25,7 +25,7 @@ module RuboCop
|
||||
# # good
|
||||
# Rails.root.join('app/models/goober')
|
||||
#
|
||||
class FilePath < Cop
|
||||
class FilePath < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
include RangeHelp
|
||||
|
||||
@ -33,6 +33,7 @@ module RuboCop
|
||||
'instead.'
|
||||
MSG_ARGUMENTS = 'Please use `Rails.root.join(\'path\', \'to\')` ' \
|
||||
'instead.'
|
||||
RESTRICT_ON_SEND = %i[join].freeze
|
||||
|
||||
def_node_matcher :file_join_nodes?, <<~PATTERN
|
||||
(send (const nil? :File) :join ...)
|
||||
@ -97,10 +98,10 @@ module RuboCop
|
||||
line_range = node.loc.column...node.loc.last_column
|
||||
source_range = source_range(processed_source.buffer, node.first_line,
|
||||
line_range)
|
||||
add_offense(node, location: source_range)
|
||||
add_offense(source_range)
|
||||
end
|
||||
|
||||
def message(_node)
|
||||
def message(_range)
|
||||
format(style == :arguments ? MSG_ARGUMENTS : MSG_SLASHES)
|
||||
end
|
||||
end
|
||||
@ -13,11 +13,12 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# User.find_by(name: 'Bruce')
|
||||
class FindBy < Cop
|
||||
class FindBy < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `find_by` instead of `where.%<method>s`.'
|
||||
TARGET_SELECTORS = %i[first take].freeze
|
||||
RESTRICT_ON_SEND = %i[first take].freeze
|
||||
|
||||
def_node_matcher :where_first?, <<~PATTERN
|
||||
(send ({send csend} _ :where ...) {:first :take})
|
||||
@ -26,28 +27,27 @@ module RuboCop
|
||||
def on_send(node)
|
||||
return unless where_first?(node)
|
||||
|
||||
range = range_between(node.receiver.loc.selector.begin_pos,
|
||||
node.loc.selector.end_pos)
|
||||
range = range_between(node.receiver.loc.selector.begin_pos, node.loc.selector.end_pos)
|
||||
|
||||
add_offense(node, location: range,
|
||||
message: format(MSG, method: node.method_name))
|
||||
add_offense(range, message: format(MSG, method: node.method_name)) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
alias on_csend on_send
|
||||
|
||||
def autocorrect(node)
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
# Don't autocorrect where(...).first, because it can return different
|
||||
# results from find_by. (They order records differently, so the
|
||||
# 'first' record can be different.)
|
||||
return if node.method?(:first)
|
||||
|
||||
where_loc = node.receiver.loc.selector
|
||||
first_loc = range_between(node.loc.dot.begin_pos,
|
||||
node.loc.selector.end_pos)
|
||||
first_loc = range_between(node.loc.dot.begin_pos, node.loc.selector.end_pos)
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.replace(where_loc, 'find_by')
|
||||
corrector.replace(first_loc, '')
|
||||
end
|
||||
corrector.replace(where_loc, 'find_by')
|
||||
corrector.replace(first_loc, '')
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -16,10 +16,12 @@ module RuboCop
|
||||
# # good
|
||||
# User.find(id)
|
||||
#
|
||||
class FindById < Cop
|
||||
class FindById < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<good_method>s` instead of `%<bad_method>s`.'
|
||||
RESTRICT_ON_SEND = %i[take! find_by_id! find_by!].freeze
|
||||
|
||||
def_node_matcher :where_take?, <<~PATTERN
|
||||
(send
|
||||
@ -38,41 +40,30 @@ module RuboCop
|
||||
def on_send(node)
|
||||
where_take?(node) do |where, id_value|
|
||||
range = where_take_offense_range(node, where)
|
||||
|
||||
good_method = build_good_method(id_value)
|
||||
bad_method = build_where_take_bad_method(id_value)
|
||||
message = format(MSG, good_method: good_method, bad_method: bad_method)
|
||||
|
||||
add_offense(node, location: range, message: message)
|
||||
register_offense(range, id_value, bad_method)
|
||||
end
|
||||
|
||||
find_by?(node) do |id_value|
|
||||
range = find_by_offense_range(node)
|
||||
|
||||
good_method = build_good_method(id_value)
|
||||
bad_method = build_find_by_bad_method(node, id_value)
|
||||
message = format(MSG, good_method: good_method, bad_method: bad_method)
|
||||
|
||||
add_offense(node, location: range, message: message)
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
if (matches = where_take?(node))
|
||||
where, id_value = *matches
|
||||
range = where_take_offense_range(node, where)
|
||||
elsif (id_value = find_by?(node))
|
||||
range = find_by_offense_range(node)
|
||||
end
|
||||
|
||||
lambda do |corrector|
|
||||
replacement = build_good_method(id_value)
|
||||
corrector.replace(range, replacement)
|
||||
register_offense(range, id_value, bad_method)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def register_offense(range, id_value, bad_method)
|
||||
good_method = build_good_method(id_value)
|
||||
message = format(MSG, good_method: good_method, bad_method: bad_method)
|
||||
|
||||
add_offense(range, message: message) do |corrector|
|
||||
corrector.replace(range, good_method)
|
||||
end
|
||||
end
|
||||
|
||||
def where_take_offense_range(node, where)
|
||||
range_between(where.loc.selector.begin_pos, node.loc.expression.end_pos)
|
||||
end
|
||||
@ -12,27 +12,30 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# User.all.find_each
|
||||
class FindEach < Cop
|
||||
#
|
||||
# @example IgnoredMethods: ['order']
|
||||
# # good
|
||||
# User.order(:foo).each
|
||||
class FindEach < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `find_each` instead of `each`.'
|
||||
RESTRICT_ON_SEND = %i[each].freeze
|
||||
|
||||
SCOPE_METHODS = %i[
|
||||
all eager_load includes joins left_joins left_outer_joins not preload
|
||||
references unscoped where
|
||||
].freeze
|
||||
IGNORED_METHODS = %i[order limit select].freeze
|
||||
|
||||
def on_send(node)
|
||||
return unless node.receiver&.send_type? &&
|
||||
node.method?(:each)
|
||||
|
||||
return unless node.receiver&.send_type?
|
||||
return unless SCOPE_METHODS.include?(node.receiver.method_name)
|
||||
return if method_chain(node).any? { |m| ignored_by_find_each?(m) }
|
||||
return if method_chain(node).any? { |m| ignored?(m) }
|
||||
|
||||
add_offense(node, location: :selector)
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
->(corrector) { corrector.replace(node.loc.selector, 'find_each') }
|
||||
range = node.loc.selector
|
||||
add_offense(range) do |corrector|
|
||||
corrector.replace(range, 'find_each')
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
@ -41,9 +44,8 @@ module RuboCop
|
||||
node.each_node(:send).map(&:method_name)
|
||||
end
|
||||
|
||||
def ignored_by_find_each?(relation_method)
|
||||
# Active Record's #find_each ignores various extra parameters
|
||||
IGNORED_METHODS.include?(relation_method)
|
||||
def ignored?(relation_method)
|
||||
cop_config['IgnoredMethods'].include?(relation_method)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -11,13 +11,14 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# # has_many :ingredients, through: :recipe_ingredients
|
||||
class HasAndBelongsToMany < Cop
|
||||
class HasAndBelongsToMany < Base
|
||||
MSG = 'Prefer `has_many :through` to `has_and_belongs_to_many`.'
|
||||
RESTRICT_ON_SEND = %i[has_and_belongs_to_many].freeze
|
||||
|
||||
def on_send(node)
|
||||
return unless node.command?(:has_and_belongs_to_many)
|
||||
|
||||
add_offense(node, location: :selector)
|
||||
add_offense(node.loc.selector)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -20,8 +20,9 @@ module RuboCop
|
||||
# has_one :avatar, dependent: :destroy
|
||||
# has_many :patients, through: :appointments
|
||||
# end
|
||||
class HasManyOrHasOneDependent < Cop
|
||||
class HasManyOrHasOneDependent < Base
|
||||
MSG = 'Specify a `:dependent` option.'
|
||||
RESTRICT_ON_SEND = %i[has_many has_one].freeze
|
||||
|
||||
def_node_search :active_resource_class?, <<~PATTERN
|
||||
(const (const nil? :ActiveResource) :Base)
|
||||
@ -55,7 +56,7 @@ module RuboCop
|
||||
return if !association_without_options?(node) && valid_options?(association_with_options?(node))
|
||||
return if valid_options_in_with_options_block?(node)
|
||||
|
||||
add_offense(node, location: :selector)
|
||||
add_offense(node.loc.selector)
|
||||
end
|
||||
|
||||
private
|
||||
@ -23,7 +23,7 @@ module RuboCop
|
||||
# def welcome_message(user)
|
||||
# "Hello #{user.name}"
|
||||
# end
|
||||
class HelperInstanceVariable < Cop
|
||||
class HelperInstanceVariable < Base
|
||||
MSG = 'Do not use instance variables in helpers.'
|
||||
|
||||
def on_ivar(node)
|
||||
@ -33,7 +33,7 @@ module RuboCop
|
||||
def on_ivasgn(node)
|
||||
return if node.parent.or_asgn_type?
|
||||
|
||||
add_offense(node, location: :name)
|
||||
add_offense(node.loc.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -17,7 +17,8 @@ module RuboCop
|
||||
# # good
|
||||
# get :new, params: { user_id: 1 }
|
||||
# get :new, **options
|
||||
class HttpPositionalArguments < Cop
|
||||
class HttpPositionalArguments < Base
|
||||
extend AutoCorrector
|
||||
extend TargetRailsVersion
|
||||
|
||||
MSG = 'Use keyword arguments instead of ' \
|
||||
@ -25,12 +26,12 @@ module RuboCop
|
||||
KEYWORD_ARGS = %i[
|
||||
method params session body flash xhr as headers env to
|
||||
].freeze
|
||||
HTTP_METHODS = %i[get post put patch delete head].freeze
|
||||
RESTRICT_ON_SEND = %i[get post put patch delete head].freeze
|
||||
|
||||
minimum_target_rails_version 5.0
|
||||
|
||||
def_node_matcher :http_request?, <<~PATTERN
|
||||
(send nil? {#{HTTP_METHODS.map(&:inspect).join(' ')}} !nil? $_ ...)
|
||||
(send nil? {#{RESTRICT_ON_SEND.map(&:inspect).join(' ')}} !nil? $_ ...)
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :kwsplat_hash?, <<~PATTERN
|
||||
@ -41,24 +42,21 @@ module RuboCop
|
||||
http_request?(node) do |data|
|
||||
return unless needs_conversion?(data)
|
||||
|
||||
add_offense(node, location: :selector,
|
||||
message: format(MSG, verb: node.method_name))
|
||||
end
|
||||
end
|
||||
message = format(MSG, verb: node.method_name)
|
||||
|
||||
# given a pre Rails 5 method: get :new, {user_id: @user.id}, {}
|
||||
#
|
||||
# @return lambda of auto correct procedure
|
||||
# the result should look like:
|
||||
# get :new, params: { user_id: @user.id }, session: {}
|
||||
# the http_method is the method used to call the controller
|
||||
# the controller node can be a symbol, method, object or string
|
||||
# that represents the path/action on the Rails controller
|
||||
# the data is the http parameters and environment sent in
|
||||
# the Rails 5 http call
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
corrector.replace(node.loc.expression, correction(node))
|
||||
add_offense(node.loc.selector, message: message) do |corrector|
|
||||
# given a pre Rails 5 method: get :new, {user_id: @user.id}, {}
|
||||
#
|
||||
# @return lambda of auto correct procedure
|
||||
# the result should look like:
|
||||
# get :new, params: { user_id: @user.id }, session: {}
|
||||
# the http_method is the method used to call the controller
|
||||
# the controller node can be a symbol, method, object or string
|
||||
# that represents the path/action on the Rails controller
|
||||
# the data is the http parameters and environment sent in
|
||||
# the Rails 5 http call
|
||||
corrector.replace(node.loc.expression, correction(node))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -31,8 +31,11 @@ module RuboCop
|
||||
# render plain: 'foo/bar', status: 304
|
||||
# redirect_to root_url, status: 301
|
||||
#
|
||||
class HttpStatus < Cop
|
||||
class HttpStatus < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
extend AutoCorrector
|
||||
|
||||
RESTRICT_ON_SEND = %i[render redirect_to].freeze
|
||||
|
||||
def_node_matcher :http_status, <<~PATTERN
|
||||
{
|
||||
@ -53,14 +56,9 @@ module RuboCop
|
||||
checker = checker_class.new(status)
|
||||
return unless checker.offensive?
|
||||
|
||||
add_offense(checker.node, message: checker.message)
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
checker = checker_class.new(node)
|
||||
corrector.replace(node.loc.expression, checker.preferred_style)
|
||||
add_offense(checker.node, message: checker.message) do |corrector|
|
||||
corrector.replace(checker.node.loc.expression, checker.preferred_style)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -37,18 +37,20 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
# @see https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-_normalize_callback_options
|
||||
class IgnoredSkipActionFilterOption < Cop
|
||||
class IgnoredSkipActionFilterOption < Base
|
||||
MSG = <<~MSG.chomp.freeze
|
||||
`%<ignore>s` option will be ignored when `%<prefer>s` and `%<ignore>s` are used together.
|
||||
MSG
|
||||
|
||||
FILTERS = %w[
|
||||
:skip_after_action
|
||||
:skip_around_action
|
||||
:skip_before_action
|
||||
:skip_action_callback
|
||||
RESTRICT_ON_SEND = %i[
|
||||
skip_after_action
|
||||
skip_around_action
|
||||
skip_before_action
|
||||
skip_action_callback
|
||||
].freeze
|
||||
|
||||
FILTERS = RESTRICT_ON_SEND.map { |method_name| ":#{method_name}" }
|
||||
|
||||
def_node_matcher :filter_options, <<~PATTERN
|
||||
(send
|
||||
nil?
|
||||
@ -17,8 +17,9 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# [1, 2, 3].index_by { |el| foo(el) }
|
||||
class IndexBy < Cop
|
||||
class IndexBy < Base
|
||||
include IndexMethod
|
||||
extend AutoCorrector
|
||||
|
||||
def_node_matcher :on_bad_each_with_object, <<~PATTERN
|
||||
(block
|
||||
@ -17,7 +17,8 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# [1, 2, 3].index_with { |el| foo(el) }
|
||||
class IndexWith < Cop
|
||||
class IndexWith < Base
|
||||
extend AutoCorrector
|
||||
extend TargetRailsVersion
|
||||
include IndexMethod
|
||||
|
||||
@ -22,15 +22,16 @@ module RuboCop
|
||||
# pets = %w(cat dog)
|
||||
# pets.include? 'cat'
|
||||
#
|
||||
class Inquiry < Cop
|
||||
class Inquiry < Base
|
||||
MSG = "Prefer Ruby's comparison operators over Active Support's `inquiry`."
|
||||
RESTRICT_ON_SEND = %i[inquiry].freeze
|
||||
|
||||
def on_send(node)
|
||||
return unless node.method?(:inquiry) && node.arguments.empty?
|
||||
return unless node.arguments.empty?
|
||||
return unless (receiver = node.receiver)
|
||||
return if !receiver.str_type? && !receiver.array_type?
|
||||
|
||||
add_offense(node, location: :selector)
|
||||
add_offense(node.loc.selector)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -128,10 +128,11 @@ module RuboCop
|
||||
#
|
||||
# @see https://guides.rubyonrails.org/association_basics.html#bi-directional-associations
|
||||
# @see https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Setting+Inverses
|
||||
class InverseOf < Cop
|
||||
class InverseOf < Base
|
||||
SPECIFY_MSG = 'Specify an `:inverse_of` option.'
|
||||
NIL_MSG = 'You specified `inverse_of: nil`, you probably meant to ' \
|
||||
'use `inverse_of: false`.'
|
||||
RESTRICT_ON_SEND = %i[has_many has_one belongs_to].freeze
|
||||
|
||||
def_node_matcher :association_recv_arguments, <<~PATTERN
|
||||
(send $_ {:has_many :has_one :belongs_to} _ $...)
|
||||
@ -185,7 +186,7 @@ module RuboCop
|
||||
|
||||
return if options_contain_inverse_of?(options)
|
||||
|
||||
add_offense(node, message: message(options), location: :selector)
|
||||
add_offense(node.loc.selector, message: message(options))
|
||||
end
|
||||
|
||||
def scope?(arguments)
|
||||
@ -82,25 +82,27 @@ module RuboCop
|
||||
# @content = Article.find(params[:article_id])
|
||||
# end
|
||||
# end
|
||||
class LexicallyScopedActionFilter < Cop
|
||||
class LexicallyScopedActionFilter < Base
|
||||
MSG = '%<action>s not explicitly defined on the %<type>s.'
|
||||
|
||||
FILTERS = %w[
|
||||
:after_action
|
||||
:append_after_action
|
||||
:append_around_action
|
||||
:append_before_action
|
||||
:around_action
|
||||
:before_action
|
||||
:prepend_after_action
|
||||
:prepend_around_action
|
||||
:prepend_before_action
|
||||
:skip_after_action
|
||||
:skip_around_action
|
||||
:skip_before_action
|
||||
:skip_action_callback
|
||||
RESTRICT_ON_SEND = %i[
|
||||
after_action
|
||||
append_after_action
|
||||
append_around_action
|
||||
append_before_action
|
||||
around_action
|
||||
before_action
|
||||
prepend_after_action
|
||||
prepend_around_action
|
||||
prepend_before_action
|
||||
skip_after_action
|
||||
skip_around_action
|
||||
skip_before_action
|
||||
skip_action_callback
|
||||
].freeze
|
||||
|
||||
FILTERS = RESTRICT_ON_SEND.map { |method_name| ":#{method_name}" }
|
||||
|
||||
def_node_matcher :only_or_except_filter_methods, <<~PATTERN
|
||||
(send
|
||||
nil?
|
||||
@ -20,8 +20,11 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# link_to 'Click here', url, target: '_blank', rel: 'noreferrer'
|
||||
class LinkToBlank < Cop
|
||||
class LinkToBlank < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Specify a `:rel` option containing noopener.'
|
||||
RESTRICT_ON_SEND = %i[link_to].freeze
|
||||
|
||||
def_node_matcher :blank_target?, <<~PATTERN
|
||||
(pair {(sym :target) (str "target")} {(str "_blank") (sym :_blank)})
|
||||
@ -35,39 +38,34 @@ module RuboCop
|
||||
(pair {(sym :rel) (str "rel")} (str _))
|
||||
PATTERN
|
||||
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
def on_send(node)
|
||||
return unless node.method?(:link_to)
|
||||
|
||||
option_nodes = node.each_child_node(:hash)
|
||||
|
||||
option_nodes.map(&:children).each do |options|
|
||||
blank = options.find { |o| blank_target?(o) }
|
||||
add_offense(blank) if blank && options.none? { |o| includes_noopener?(o) }
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
next unless blank && options.none? { |o| includes_noopener?(o) }
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
send_node = node.parent.parent
|
||||
|
||||
option_nodes = send_node.each_child_node(:hash)
|
||||
rel_node = nil
|
||||
option_nodes.map(&:children).each do |options|
|
||||
rel_node ||= options.find { |o| rel_node?(o) }
|
||||
end
|
||||
|
||||
if rel_node
|
||||
append_to_rel(rel_node, corrector)
|
||||
else
|
||||
add_rel(send_node, node, corrector)
|
||||
add_offense(blank) do |corrector|
|
||||
autocorrect(corrector, node, blank, option_nodes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, send_node, node, option_nodes)
|
||||
rel_node = nil
|
||||
option_nodes.map(&:children).each do |options|
|
||||
rel_node ||= options.find { |o| rel_node?(o) }
|
||||
end
|
||||
|
||||
if rel_node
|
||||
append_to_rel(rel_node, corrector)
|
||||
else
|
||||
add_rel(send_node, node, corrector)
|
||||
end
|
||||
end
|
||||
|
||||
def append_to_rel(rel_node, corrector)
|
||||
existing_rel = rel_node.children.last.value
|
||||
str_range = rel_node.children.last.loc.expression.adjust(
|
||||
@ -89,7 +87,7 @@ module RuboCop
|
||||
def contains_noopener?(value)
|
||||
return false unless value
|
||||
|
||||
rel_array = value.to_s.split(' ')
|
||||
rel_array = value.to_s.split
|
||||
rel_array.include?('noopener') || rel_array.include?('noreferrer')
|
||||
end
|
||||
end
|
||||
@ -23,7 +23,9 @@ module RuboCop
|
||||
# class UserMailer < ApplicationMailer
|
||||
# end
|
||||
#
|
||||
class MailerName < Cop
|
||||
class MailerName < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Mailer should end with `Mailer` suffix.'
|
||||
|
||||
def_node_matcher :mailer_base_class?, <<~PATTERN
|
||||
@ -43,7 +45,9 @@ module RuboCop
|
||||
|
||||
def on_class(node)
|
||||
class_definition?(node) do |name_node|
|
||||
add_offense(name_node)
|
||||
add_offense(name_node) do |corrector|
|
||||
autocorrect(corrector, name_node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -54,23 +58,25 @@ module RuboCop
|
||||
return unless casgn_parent
|
||||
|
||||
name = casgn_parent.children[1]
|
||||
add_offense(casgn_parent, location: :name) unless mailer_suffix?(name)
|
||||
end
|
||||
return if mailer_suffix?(name)
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
if node.casgn_type?
|
||||
name = node.children[1]
|
||||
corrector.replace(node.loc.name, "#{name}Mailer")
|
||||
else
|
||||
name = node.children.last
|
||||
corrector.replace(node.source_range, "#{name}Mailer")
|
||||
end
|
||||
add_offense(casgn_parent.loc.name) do |corrector|
|
||||
autocorrect(corrector, casgn_parent)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
if node.casgn_type?
|
||||
name = node.children[1]
|
||||
corrector.replace(node.loc.name, "#{name}Mailer")
|
||||
else
|
||||
name = node.children.last
|
||||
corrector.replace(node.source_range, "#{name}Mailer")
|
||||
end
|
||||
end
|
||||
|
||||
def mailer_suffix?(mailer_name)
|
||||
mailer_name.to_s.end_with?('Mailer')
|
||||
end
|
||||
@ -20,8 +20,11 @@ module RuboCop
|
||||
# match 'photos/:id', to: 'photos#show', via: [:get, :post]
|
||||
# match 'photos/:id', to: 'photos#show', via: :all
|
||||
#
|
||||
class MatchRoute < Cop
|
||||
class MatchRoute < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<http_method>s` instead of `match` to define a route.'
|
||||
RESTRICT_ON_SEND = %i[match].freeze
|
||||
HTTP_METHODS = %i[get post put patch delete].freeze
|
||||
|
||||
def_node_matcher :match_method_call?, <<~PATTERN
|
||||
@ -35,30 +38,28 @@ module RuboCop
|
||||
options_node = path_node.hash_type? ? path_node : options_node.first
|
||||
|
||||
if options_node.nil?
|
||||
message = format(MSG, http_method: 'get')
|
||||
add_offense(node, message: message)
|
||||
register_offense(node, 'get')
|
||||
else
|
||||
via = extract_via(options_node)
|
||||
if via.size == 1 && http_method?(via.first)
|
||||
message = format(MSG, http_method: via.first)
|
||||
add_offense(node, message: message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return unless via.size == 1 && http_method?(via.first)
|
||||
|
||||
def autocorrect(node)
|
||||
match_method_call?(node) do |path_node, options_node|
|
||||
options_node = options_node.first
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.replace(node, replacement(path_node, options_node))
|
||||
register_offense(node, via.first)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def register_offense(node, http_method)
|
||||
add_offense(node, message: format(MSG, http_method: http_method)) do |corrector|
|
||||
match_method_call?(node) do |path_node, options_node|
|
||||
options_node = options_node.first
|
||||
|
||||
corrector.replace(node, replacement(path_node, options_node))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def_node_matcher :routes_draw?, <<~PATTERN
|
||||
(send (send _ :routes) :draw)
|
||||
PATTERN
|
||||
@ -6,6 +6,9 @@ module RuboCop
|
||||
# This cop enforces the use of `collection.exclude?(obj)`
|
||||
# over `!collection.include?(obj)`.
|
||||
#
|
||||
# It is marked as unsafe by default because false positive will occur for
|
||||
# a receiver object that do not have `exclude?` method. (e.g. `IPAddr`)
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# !array.include?(2)
|
||||
@ -15,22 +18,21 @@ module RuboCop
|
||||
# array.exclude?(2)
|
||||
# hash.exclude?(:key)
|
||||
#
|
||||
class NegateInclude < Cop
|
||||
class NegateInclude < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `.exclude?` and remove the negation part.'
|
||||
RESTRICT_ON_SEND = %i[!].freeze
|
||||
|
||||
def_node_matcher :negate_include_call?, <<~PATTERN
|
||||
(send (send $_ :include? $_) :!)
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
add_offense(node) if negate_include_call?(node)
|
||||
end
|
||||
return unless (receiver, obj = negate_include_call?(node))
|
||||
|
||||
def autocorrect(node)
|
||||
negate_include_call?(node) do |receiver, obj|
|
||||
lambda do |corrector|
|
||||
corrector.replace(node, "#{receiver.source}.exclude?(#{obj.source})")
|
||||
end
|
||||
add_offense(node) do |corrector|
|
||||
corrector.replace(node, "#{receiver.source}.exclude?(#{obj.source})")
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -16,8 +16,9 @@ module RuboCop
|
||||
# add_column :users, :name, :string, null: false, default: ''
|
||||
# add_reference :products, :category
|
||||
# add_reference :products, :category, null: false, default: 1
|
||||
class NotNullColumn < Cop
|
||||
class NotNullColumn < Base
|
||||
MSG = 'Do not add a NOT NULL column without a default value.'
|
||||
RESTRICT_ON_SEND = %i[add_column add_reference].freeze
|
||||
|
||||
def_node_matcher :add_not_null_column?, <<~PATTERN
|
||||
(send nil? :add_column _ _ _ (hash $...))
|
||||
@ -25,6 +25,7 @@ module RuboCop
|
||||
|
||||
MSG = 'Do not use the `id` column for ordering. '\
|
||||
'Use a timestamp column to order chronologically.'
|
||||
RESTRICT_ON_SEND = %i[order].freeze
|
||||
|
||||
def_node_matcher :order_by_id?, <<~PATTERN
|
||||
(send _ :order
|
||||
@ -37,8 +38,6 @@ module RuboCop
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
return unless node.method?(:order)
|
||||
|
||||
add_offense(offense_range(node)) if order_by_id?(node)
|
||||
end
|
||||
|
||||
@ -13,9 +13,12 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# Rails.logger.debug 'A debug message'
|
||||
class Output < Cop
|
||||
class Output < Base
|
||||
MSG = 'Do not write to stdout. ' \
|
||||
"Use Rails's logger if you want to log."
|
||||
RESTRICT_ON_SEND = %i[
|
||||
ap p pp pretty_print print puts binwrite syswrite write write_nonblock
|
||||
].freeze
|
||||
|
||||
def_node_matcher :output?, <<~PATTERN
|
||||
(send nil? {:ap :p :pp :pretty_print :print :puts} ...)
|
||||
@ -35,7 +38,7 @@ module RuboCop
|
||||
return unless (output?(node) || io_output?(node)) &&
|
||||
node.arguments?
|
||||
|
||||
add_offense(node, location: :selector)
|
||||
add_offense(node.loc.selector)
|
||||
end
|
||||
|
||||
private
|
||||
@ -62,8 +62,9 @@ module RuboCop
|
||||
# safe_join([user_content, " ", content_tag(:span, user_content)])
|
||||
# # => ActiveSupport::SafeBuffer
|
||||
# # "<b>hi</b> <span><b>hi</b></span>"
|
||||
class OutputSafety < Cop
|
||||
class OutputSafety < Base
|
||||
MSG = 'Tagging a string as html safe may be a security risk.'
|
||||
RESTRICT_ON_SEND = %i[html_safe raw safe_concat].freeze
|
||||
|
||||
def on_send(node)
|
||||
return if non_interpolated_string?(node)
|
||||
@ -72,7 +73,7 @@ module RuboCop
|
||||
looks_like_rails_raw?(node) ||
|
||||
looks_like_rails_safe_concat?(node)
|
||||
|
||||
add_offense(node, location: :selector)
|
||||
add_offense(node.loc.selector)
|
||||
end
|
||||
alias on_csend on_send
|
||||
|
||||
@ -17,10 +17,12 @@ module RuboCop
|
||||
# # good
|
||||
# Model.pick(:a)
|
||||
# [{ a: :b, c: :d }].pick(:a, :b)
|
||||
class Pick < Cop
|
||||
class Pick < Base
|
||||
extend AutoCorrector
|
||||
extend TargetRailsVersion
|
||||
|
||||
MSG = 'Prefer `pick(%<args>s)` over `pluck(%<args>s).first`.'
|
||||
RESTRICT_ON_SEND = %i[first].freeze
|
||||
|
||||
minimum_target_rails_version 6.0
|
||||
|
||||
@ -30,24 +32,24 @@ module RuboCop
|
||||
|
||||
def on_send(node)
|
||||
pick_candidate?(node) do
|
||||
range = node.receiver.loc.selector.join(node.loc.selector)
|
||||
add_offense(node, location: range)
|
||||
end
|
||||
end
|
||||
receiver = node.receiver
|
||||
receiver_selector = receiver.loc.selector
|
||||
node_selector = node.loc.selector
|
||||
range = receiver_selector.join(node_selector)
|
||||
|
||||
def autocorrect(node)
|
||||
first_range = node.receiver.source_range.end.join(node.loc.selector)
|
||||
add_offense(range, message: message(receiver)) do |corrector|
|
||||
first_range = receiver.source_range.end.join(node_selector)
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.remove(first_range)
|
||||
corrector.replace(node.receiver.loc.selector, 'pick')
|
||||
corrector.remove(first_range)
|
||||
corrector.replace(receiver_selector, 'pick')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message(node)
|
||||
format(MSG, args: node.receiver.arguments.map(&:source).join(', '))
|
||||
def message(receiver)
|
||||
format(MSG, args: receiver.arguments.map(&:source).join(', '))
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -17,7 +17,8 @@ module RuboCop
|
||||
# # good
|
||||
# Post.published.pluck(:title)
|
||||
# [{ a: :b, c: :d }].pluck(:a)
|
||||
class Pluck < Cop
|
||||
class Pluck < Base
|
||||
extend AutoCorrector
|
||||
extend TargetRailsVersion
|
||||
|
||||
MSG = 'Prefer `pluck(:%<value>s)` over `%<method>s { |%<argument>s| %<element>s[:%<value>s] }`.'
|
||||
@ -32,15 +33,11 @@ module RuboCop
|
||||
pluck_candidate?(node) do |method, argument, element, value|
|
||||
next unless argument == element
|
||||
|
||||
add_offense(node, location: offense_range(node), message: message(method, argument, element, value))
|
||||
end
|
||||
end
|
||||
message = message(method, argument, element, value)
|
||||
|
||||
def autocorrect(node)
|
||||
_method, _argument, _element, value = pluck_candidate?(node)
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.replace(offense_range(node), "pluck(:#{value})")
|
||||
add_offense(offense_range(node), message: message) do |corrector|
|
||||
corrector.replace(offense_range(node), "pluck(:#{value})")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -22,11 +22,13 @@ module RuboCop
|
||||
# ids
|
||||
# end
|
||||
#
|
||||
class PluckId < Cop
|
||||
class PluckId < Base
|
||||
include RangeHelp
|
||||
include ActiveRecordHelper
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `ids` instead of `%<bad_method>s`.'
|
||||
RESTRICT_ON_SEND = %i[pluck].freeze
|
||||
|
||||
def_node_matcher :pluck_id_call?, <<~PATTERN
|
||||
(send _ :pluck {(sym :id) (send nil? :primary_key)})
|
||||
@ -38,11 +40,7 @@ module RuboCop
|
||||
range = offense_range(node)
|
||||
message = format(MSG, bad_method: range.source)
|
||||
|
||||
add_offense(node, location: range, message: message)
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
add_offense(range, message: message) do |corrector|
|
||||
corrector.replace(offense_range(node), 'ids')
|
||||
end
|
||||
end
|
||||
@ -34,22 +34,22 @@ module RuboCop
|
||||
# # bad
|
||||
# Post.where(user_id: active_users.pluck(:id))
|
||||
#
|
||||
class PluckInWhere < Cop
|
||||
class PluckInWhere < Base
|
||||
include ActiveRecordHelper
|
||||
include ConfigurableEnforcedStyle
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `select` instead of `pluck` within `where` query method.'
|
||||
RESTRICT_ON_SEND = %i[pluck].freeze
|
||||
|
||||
def on_send(node)
|
||||
return unless node.method?(:pluck) && in_where?(node)
|
||||
return unless in_where?(node)
|
||||
return if style == :conservative && !root_receiver(node)&.const_type?
|
||||
|
||||
add_offense(node, location: :selector)
|
||||
end
|
||||
range = node.loc.selector
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
corrector.replace(node.loc.selector, 'select')
|
||||
add_offense(range) do |corrector|
|
||||
corrector.replace(range, 'select')
|
||||
end
|
||||
end
|
||||
|
||||
@ -14,7 +14,9 @@ module RuboCop
|
||||
# # good
|
||||
# 3.days.ago
|
||||
# 1.month.ago
|
||||
class PluralizationGrammar < Cop
|
||||
class PluralizationGrammar < Base
|
||||
extend AutoCorrector
|
||||
|
||||
SINGULAR_DURATION_METHODS = { second: :seconds,
|
||||
minute: :minutes,
|
||||
hour: :hours,
|
||||
@ -24,21 +26,18 @@ module RuboCop
|
||||
month: :months,
|
||||
year: :years }.freeze
|
||||
|
||||
RESTRICT_ON_SEND = SINGULAR_DURATION_METHODS.keys + SINGULAR_DURATION_METHODS.values
|
||||
|
||||
PLURAL_DURATION_METHODS = SINGULAR_DURATION_METHODS.invert.freeze
|
||||
|
||||
MSG = 'Prefer `%<number>s.%<correct>s`.'
|
||||
|
||||
def on_send(node)
|
||||
return unless duration_method?(node.method_name)
|
||||
return unless literal_number?(node.receiver)
|
||||
return unless duration_method?(node.method_name) && literal_number?(node.receiver) && offense?(node)
|
||||
|
||||
return unless offense?(node)
|
||||
number, = *node.receiver
|
||||
|
||||
add_offense(node)
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
add_offense(node, message: message(number, node.method_name)) do |corrector|
|
||||
method_name = node.loc.selector.source
|
||||
|
||||
corrector.replace(node.loc.selector, correct_method(method_name))
|
||||
@ -47,11 +46,8 @@ module RuboCop
|
||||
|
||||
private
|
||||
|
||||
def message(node)
|
||||
number, = *node.receiver
|
||||
|
||||
format(MSG, number: number,
|
||||
correct: correct_method(node.method_name.to_s))
|
||||
def message(number, method_name)
|
||||
format(MSG, number: number, correct: correct_method(method_name))
|
||||
end
|
||||
|
||||
def correct_method(method_name)
|
||||
@ -37,8 +37,9 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# a.presence || b
|
||||
class Presence < Cop
|
||||
class Presence < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
||||
|
||||
@ -76,28 +77,26 @@ module RuboCop
|
||||
return if ignore_if_node?(node)
|
||||
|
||||
redundant_receiver_and_other(node) do |receiver, other|
|
||||
add_offense(node, message: message(node, receiver, other)) unless ignore_other_node?(other) || receiver.nil?
|
||||
return if ignore_other_node?(other) || receiver.nil?
|
||||
|
||||
register_offense(node, receiver, other)
|
||||
end
|
||||
|
||||
redundant_negative_receiver_and_other(node) do |receiver, other|
|
||||
add_offense(node, message: message(node, receiver, other)) unless ignore_other_node?(other) || receiver.nil?
|
||||
end
|
||||
end
|
||||
return if ignore_other_node?(other) || receiver.nil?
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
redundant_receiver_and_other(node) do |receiver, other|
|
||||
corrector.replace(node.source_range, replacement(receiver, other))
|
||||
end
|
||||
|
||||
redundant_negative_receiver_and_other(node) do |receiver, other|
|
||||
corrector.replace(node.source_range, replacement(receiver, other))
|
||||
end
|
||||
register_offense(node, receiver, other)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def register_offense(node, receiver, other)
|
||||
add_offense(node, message: message(node, receiver, other)) do |corrector|
|
||||
corrector.replace(node.source_range, replacement(receiver, other))
|
||||
end
|
||||
end
|
||||
|
||||
def ignore_if_node?(node)
|
||||
node.elsif?
|
||||
end
|
||||
@ -43,12 +43,15 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# something if foo.present?
|
||||
class Present < Cop
|
||||
class Present < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG_NOT_BLANK = 'Use `%<prefer>s` instead of `%<current>s`.'
|
||||
MSG_EXISTS_AND_NOT_EMPTY = 'Use `%<prefer>s` instead of ' \
|
||||
'`%<current>s`.'
|
||||
MSG_UNLESS_BLANK = 'Use `if %<prefer>s` instead of ' \
|
||||
'`%<current>s`.'
|
||||
RESTRICT_ON_SEND = %i[!].freeze
|
||||
|
||||
def_node_matcher :exists_and_not_empty?, <<~PATTERN
|
||||
(and
|
||||
@ -74,10 +77,11 @@ module RuboCop
|
||||
return unless cop_config['NotBlank']
|
||||
|
||||
not_blank?(node) do |receiver|
|
||||
add_offense(node,
|
||||
message: format(MSG_NOT_BLANK,
|
||||
prefer: replacement(receiver),
|
||||
current: node.source))
|
||||
message = format(MSG_NOT_BLANK, prefer: replacement(receiver), current: node.source)
|
||||
|
||||
add_offense(node, message: message) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -87,10 +91,11 @@ module RuboCop
|
||||
exists_and_not_empty?(node) do |var1, var2|
|
||||
return unless var1 == var2
|
||||
|
||||
add_offense(node,
|
||||
message: format(MSG_EXISTS_AND_NOT_EMPTY,
|
||||
prefer: replacement(var1),
|
||||
current: node.source))
|
||||
message = format(MSG_EXISTS_AND_NOT_EMPTY, prefer: replacement(var1), current: node.source)
|
||||
|
||||
add_offense(node, message: message) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -100,7 +105,9 @@ module RuboCop
|
||||
exists_and_not_empty?(node) do |var1, var2|
|
||||
return unless var1 == var2
|
||||
|
||||
add_offense(node, message: MSG_EXISTS_AND_NOT_EMPTY)
|
||||
add_offense(node, message: MSG_EXISTS_AND_NOT_EMPTY) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -113,25 +120,24 @@ module RuboCop
|
||||
range = unless_condition(node, method_call)
|
||||
msg = format(MSG_UNLESS_BLANK, prefer: replacement(receiver),
|
||||
current: range.source)
|
||||
add_offense(node, location: range, message: msg)
|
||||
add_offense(range, message: msg) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
method_call, variable1 = unless_blank?(node)
|
||||
def autocorrect(corrector, node)
|
||||
method_call, variable1 = unless_blank?(node)
|
||||
|
||||
if method_call
|
||||
corrector.replace(node.loc.keyword, 'if')
|
||||
range = method_call.loc.expression
|
||||
else
|
||||
variable1, _variable2 =
|
||||
exists_and_not_empty?(node) || not_blank?(node)
|
||||
range = node.loc.expression
|
||||
end
|
||||
|
||||
corrector.replace(range, replacement(variable1))
|
||||
if method_call
|
||||
corrector.replace(node.loc.keyword, 'if')
|
||||
range = method_call.loc.expression
|
||||
else
|
||||
variable1, _variable2 = exists_and_not_empty?(node) || not_blank?(node)
|
||||
range = node.loc.expression
|
||||
end
|
||||
|
||||
corrector.replace(range, replacement(variable1))
|
||||
end
|
||||
|
||||
private
|
||||
@ -25,7 +25,9 @@ module RuboCop
|
||||
# do_something
|
||||
# end
|
||||
#
|
||||
class RakeEnvironment < Cop
|
||||
class RakeEnvironment < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Include `:environment` task as a dependency for all Rake tasks.'
|
||||
|
||||
def_node_matcher :task_definition?, <<~PATTERN
|
||||
@ -37,16 +39,12 @@ module RuboCop
|
||||
return if task_name(task_method) == :default
|
||||
return if with_dependencies?(task_method)
|
||||
|
||||
add_offense(task_method)
|
||||
end
|
||||
end
|
||||
add_offense(task_method) do |corrector|
|
||||
task_name = task_method.arguments[0]
|
||||
task_dependency = correct_task_dependency(task_name)
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
task_name = node.arguments[0]
|
||||
task_dependency = correct_task_dependency(task_name)
|
||||
|
||||
corrector.replace(task_name.loc.expression, task_dependency)
|
||||
corrector.replace(task_name.loc.expression, task_dependency)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -23,8 +23,11 @@ module RuboCop
|
||||
# # good
|
||||
# x = self[:attr]
|
||||
# self[:attr] = val
|
||||
class ReadWriteAttribute < Cop
|
||||
class ReadWriteAttribute < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Prefer `%<prefer>s` over `%<current>s`.'
|
||||
RESTRICT_ON_SEND = %i[read_attribute write_attribute].freeze
|
||||
|
||||
def_node_matcher :read_write_attribute?, <<~PATTERN
|
||||
{
|
||||
@ -36,18 +39,16 @@ module RuboCop
|
||||
def on_send(node)
|
||||
return unless read_write_attribute?(node)
|
||||
|
||||
add_offense(node, location: :selector)
|
||||
end
|
||||
add_offense(node.loc.selector, message: message(node)) do |corrector|
|
||||
case node.method_name
|
||||
when :read_attribute
|
||||
replacement = read_attribute_replacement(node)
|
||||
when :write_attribute
|
||||
replacement = write_attribute_replacement(node)
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
case node.method_name
|
||||
when :read_attribute
|
||||
replacement = read_attribute_replacement(node)
|
||||
when :write_attribute
|
||||
replacement = write_attribute_replacement(node)
|
||||
corrector.replace(node.source_range, replacement)
|
||||
end
|
||||
|
||||
->(corrector) { corrector.replace(node.source_range, replacement) }
|
||||
end
|
||||
|
||||
private
|
||||
@ -26,8 +26,9 @@ module RuboCop
|
||||
# # Here, `nil` is valid but `''` is not
|
||||
# validates :x, length: { is: 5 }, allow_nil: true, allow_blank: false
|
||||
#
|
||||
class RedundantAllowNil < Cop
|
||||
class RedundantAllowNil < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
||||
MSG_SAME =
|
||||
'`allow_nil` is redundant when `allow_blank` has the same value.'
|
||||
@ -35,59 +36,56 @@ module RuboCop
|
||||
MSG_ALLOW_NIL_FALSE =
|
||||
'`allow_nil: false` is redundant when `allow_blank` is true.'
|
||||
|
||||
def on_send(node)
|
||||
return unless node.method?(:validates)
|
||||
RESTRICT_ON_SEND = %i[validates].freeze
|
||||
|
||||
def on_send(node)
|
||||
allow_nil, allow_blank = find_allow_nil_and_allow_blank(node)
|
||||
return unless allow_nil && allow_blank
|
||||
|
||||
allow_nil_val = allow_nil.children.last
|
||||
allow_blank_val = allow_blank.children.last
|
||||
|
||||
offense(allow_nil_val, allow_blank_val, allow_nil)
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
prv_sib = previous_sibling(node)
|
||||
nxt_sib = next_sibling(node)
|
||||
|
||||
lambda do |corrector|
|
||||
if nxt_sib
|
||||
corrector.remove(range_between(node_beg(node), node_beg(nxt_sib)))
|
||||
elsif prv_sib
|
||||
corrector.remove(range_between(node_end(prv_sib), node_end(node)))
|
||||
else
|
||||
corrector.remove(node.loc.expression)
|
||||
end
|
||||
if allow_nil_val.type == allow_blank_val.type
|
||||
register_offense(allow_nil, MSG_SAME)
|
||||
elsif allow_nil_val.false_type? && allow_blank_val.true_type?
|
||||
register_offense(allow_nil, MSG_ALLOW_NIL_FALSE)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def offense(allow_nil_val, allow_blank_val, allow_nil)
|
||||
if allow_nil_val.type == allow_blank_val.type
|
||||
add_offense(allow_nil, message: MSG_SAME)
|
||||
elsif allow_nil_val.false_type? && allow_blank_val.true_type?
|
||||
add_offense(allow_nil, message: MSG_ALLOW_NIL_FALSE)
|
||||
def register_offense(allow_nil, message)
|
||||
add_offense(allow_nil, message: message) do |corrector|
|
||||
prv_sib = previous_sibling(allow_nil)
|
||||
nxt_sib = next_sibling(allow_nil)
|
||||
|
||||
if nxt_sib
|
||||
corrector.remove(range_between(node_beg(allow_nil), node_beg(nxt_sib)))
|
||||
elsif prv_sib
|
||||
corrector.remove(range_between(node_end(prv_sib), node_end(allow_nil)))
|
||||
else
|
||||
corrector.remove(allow_nil.loc.expression)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def find_allow_nil_and_allow_blank(node)
|
||||
allow_nil = nil
|
||||
allow_blank = nil
|
||||
allow_nil, allow_blank = nil
|
||||
|
||||
node.each_descendant do |descendant|
|
||||
next unless descendant.pair_type?
|
||||
node.each_child_node do |child_node|
|
||||
if child_node.pair_type?
|
||||
key = child_node.children.first.source
|
||||
|
||||
key = descendant.children.first.source
|
||||
allow_nil = child_node if key == 'allow_nil'
|
||||
allow_blank = child_node if key == 'allow_blank'
|
||||
end
|
||||
return [allow_nil, allow_blank] if allow_nil && allow_blank
|
||||
|
||||
allow_nil = descendant if key == 'allow_nil'
|
||||
allow_blank = descendant if key == 'allow_blank'
|
||||
|
||||
break if allow_nil && allow_blank
|
||||
found_in_children_nodes = find_allow_nil_and_allow_blank(child_node)
|
||||
return found_in_children_nodes if found_in_children_nodes
|
||||
end
|
||||
|
||||
[allow_nil, allow_blank]
|
||||
nil
|
||||
end
|
||||
|
||||
def previous_sibling(node)
|
||||
@ -24,10 +24,12 @@ module RuboCop
|
||||
# class Comment
|
||||
# belongs_to :author, foreign_key: 'user_id'
|
||||
# end
|
||||
class RedundantForeignKey < Cop
|
||||
class RedundantForeignKey < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Specifying the default value for `foreign_key` is redundant.'
|
||||
RESTRICT_ON_SEND = %i[belongs_to has_one has_many has_and_belongs_to_many].freeze
|
||||
|
||||
def_node_matcher :association_with_foreign_key, <<~PATTERN
|
||||
(send nil? ${:belongs_to :has_one :has_many :has_and_belongs_to_many} ({sym str} $_)
|
||||
@ -38,21 +40,16 @@ module RuboCop
|
||||
def on_send(node)
|
||||
association_with_foreign_key(node) do |type, name, options, foreign_key_pair, foreign_key|
|
||||
if redundant?(node, type, name, options, foreign_key)
|
||||
add_offense(node, location: foreign_key_pair.loc.expression)
|
||||
add_offense(foreign_key_pair.loc.expression) do |corrector|
|
||||
range = range_with_surrounding_space(range: foreign_key_pair.source_range, side: :left)
|
||||
range = range_with_surrounding_comma(range, :left)
|
||||
|
||||
corrector.remove(range)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
_type, _name, _options, foreign_key_pair, _foreign_key = association_with_foreign_key(node)
|
||||
range = range_with_surrounding_space(range: foreign_key_pair.source_range, side: :left)
|
||||
range = range_with_surrounding_comma(range, :left)
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.remove(range)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def redundant?(node, association_type, association_name, options, foreign_key)
|
||||
@ -54,8 +54,9 @@ module RuboCop
|
||||
# merger.invoke(another_receiver)
|
||||
# end
|
||||
# end
|
||||
class RedundantReceiverInWithOptions < Cop
|
||||
class RedundantReceiverInWithOptions < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Redundant receiver in `with_options`.'
|
||||
|
||||
@ -86,22 +87,22 @@ module RuboCop
|
||||
if send_nodes.all? { |n| same_value?(arg, n.receiver) }
|
||||
send_nodes.each do |send_node|
|
||||
receiver = send_node.receiver
|
||||
add_offense(send_node, location: receiver.source_range)
|
||||
add_offense(receiver.source_range) do |corrector|
|
||||
autocorrect(corrector, send_node)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
corrector.remove(node.receiver.source_range)
|
||||
corrector.remove(node.loc.dot)
|
||||
corrector.remove(block_argument_range(node))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
corrector.remove(node.receiver.source_range)
|
||||
corrector.remove(node.loc.dot)
|
||||
corrector.remove(block_argument_range(node))
|
||||
end
|
||||
|
||||
def block_argument_range(node)
|
||||
block_node = node.each_ancestor(:block).first
|
||||
block_argument = block_node.children[1].source_range
|
||||
@ -13,8 +13,9 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# has_many :accounts, class_name: 'Account'
|
||||
class ReflectionClassName < Cop
|
||||
class ReflectionClassName < Base
|
||||
MSG = 'Use a string value for `class_name`.'
|
||||
RESTRICT_ON_SEND = %i[has_many has_one belongs_to].freeze
|
||||
|
||||
def_node_matcher :association_with_reflection, <<~PATTERN
|
||||
(send nil? {:has_many :has_one :belongs_to} _ _ ?
|
||||
@ -28,7 +29,7 @@ module RuboCop
|
||||
|
||||
def on_send(node)
|
||||
association_with_reflection(node) do |reflection_class_name|
|
||||
add_offense(node, location: reflection_class_name.loc.expression)
|
||||
add_offense(reflection_class_name.loc.expression)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -28,8 +28,9 @@ module RuboCop
|
||||
# refute_empty [1, 2, 3]
|
||||
# refute_equal true, false
|
||||
#
|
||||
class RefuteMethods < Cop
|
||||
class RefuteMethods < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Prefer `%<good_method>s` over `%<bad_method>s`.'
|
||||
|
||||
@ -53,21 +54,19 @@ module RuboCop
|
||||
REFUTE_METHODS = CORRECTIONS.keys.freeze
|
||||
ASSERT_NOT_METHODS = CORRECTIONS.values.freeze
|
||||
|
||||
RESTRICT_ON_SEND = REFUTE_METHODS + ASSERT_NOT_METHODS
|
||||
|
||||
def_node_matcher :offensive?, '(send nil? #bad_method? ...)'
|
||||
|
||||
def on_send(node)
|
||||
return unless offensive?(node)
|
||||
|
||||
message = offense_message(node.method_name)
|
||||
add_offense(node, location: :selector, message: message)
|
||||
end
|
||||
method_name = node.method_name
|
||||
message = offense_message(method_name)
|
||||
range = node.loc.selector
|
||||
|
||||
def autocorrect(node)
|
||||
bad_method = node.method_name
|
||||
good_method = convert_good_method(bad_method)
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.replace(node.loc.selector, good_method.to_s)
|
||||
add_offense(range, message: message) do |corrector|
|
||||
corrector.replace(range, convert_good_method(method_name))
|
||||
end
|
||||
end
|
||||
|
||||
@ -27,15 +27,18 @@ module RuboCop
|
||||
# 1.week.since
|
||||
# end
|
||||
# end
|
||||
class RelativeDateConstant < Cop
|
||||
class RelativeDateConstant < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Do not assign %<method_name>s to constants as it ' \
|
||||
'will be evaluated only once.'
|
||||
|
||||
def on_casgn(node)
|
||||
relative_date_assignment?(node) do |method_name|
|
||||
add_offense(node, message: format(MSG, method_name: method_name))
|
||||
add_offense(node, message: message(method_name)) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -48,9 +51,9 @@ module RuboCop
|
||||
next unless name.casgn_type?
|
||||
|
||||
relative_date?(value) do |method_name|
|
||||
add_offense(node,
|
||||
location: offense_range(name, value),
|
||||
message: format(MSG, method_name: method_name))
|
||||
add_offense(offense_range(name, value), message: message(method_name)) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -61,7 +64,9 @@ module RuboCop
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
return unless node.casgn_type?
|
||||
|
||||
scope, const_name, value = *node
|
||||
@ -71,10 +76,13 @@ module RuboCop
|
||||
new_code = ["def self.#{const_name.downcase}",
|
||||
"#{indent}#{value.source}",
|
||||
'end'].join("\n#{indent}")
|
||||
->(corrector) { corrector.replace(node.source_range, new_code) }
|
||||
|
||||
corrector.replace(node.source_range, new_code)
|
||||
end
|
||||
|
||||
private
|
||||
def message(method_name)
|
||||
format(MSG, method_name: method_name)
|
||||
end
|
||||
|
||||
def offense_range(name, value)
|
||||
range_between(name.loc.expression.begin_pos, value.loc.expression.end_pos)
|
||||
@ -24,8 +24,9 @@ module RuboCop
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class RenderInline < Cop
|
||||
class RenderInline < Base
|
||||
MSG = 'Prefer using a template over inline rendering.'
|
||||
RESTRICT_ON_SEND = %i[render].freeze
|
||||
|
||||
def_node_matcher :render_with_inline_option?, <<~PATTERN
|
||||
(send nil? :render (hash <(pair {(sym :inline) (str "inline")} _) ...>))
|
||||
@ -24,30 +24,25 @@ module RuboCop
|
||||
# # bad - sets MIME type to `text/html`
|
||||
# render text: 'Ruby!'
|
||||
#
|
||||
class RenderPlainText < Cop
|
||||
class RenderPlainText < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Prefer `render plain:` over `render text:`.'
|
||||
RESTRICT_ON_SEND = %i[render].freeze
|
||||
|
||||
def_node_matcher :render_plain_text?, <<~PATTERN
|
||||
(send nil? :render $(hash <$(pair (sym :text) $_) ...>))
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
render_plain_text?(node) do |options_node, _option_node, _option_value|
|
||||
content_type_node = find_content_type(options_node)
|
||||
add_offense(node) if compatible_content_type?(content_type_node)
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
render_plain_text?(node) do |options_node, option_node, option_value|
|
||||
content_type_node = find_content_type(options_node)
|
||||
rest_options = options_node.pairs - [option_node, content_type_node].compact
|
||||
return unless compatible_content_type?(content_type_node)
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.replace(
|
||||
node,
|
||||
replacement(rest_options, option_value)
|
||||
)
|
||||
add_offense(node) do |corrector|
|
||||
rest_options = options_node.pairs - [option_node, content_type_node].compact
|
||||
|
||||
corrector.replace(node, replacement(rest_options, option_value))
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -19,11 +19,13 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# request.referrer
|
||||
class RequestReferer < Cop
|
||||
class RequestReferer < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `request.%<prefer>s` instead of ' \
|
||||
'`request.%<current>s`.'
|
||||
RESTRICT_ON_SEND = %i[referer referrer].freeze
|
||||
|
||||
def_node_matcher :referer?, <<~PATTERN
|
||||
(send (send nil? :request) {:referer :referrer})
|
||||
@ -33,17 +35,15 @@ module RuboCop
|
||||
referer?(node) do
|
||||
return unless node.method?(wrong_method_name)
|
||||
|
||||
add_offense(node.source_range, location: node.source_range)
|
||||
add_offense(node.source_range) do |corrector|
|
||||
corrector.replace(node, "request.#{style}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
->(corrector) { corrector.replace(node, "request.#{style}") }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message(_node)
|
||||
def message(_range)
|
||||
format(MSG, prefer: style, current: wrong_method_name)
|
||||
end
|
||||
|
||||
@ -175,7 +175,7 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
# @see https://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html
|
||||
class ReversibleMigration < Cop
|
||||
class ReversibleMigration < Base
|
||||
MSG = '%<action>s is not reversible.'
|
||||
|
||||
def_node_matcher :irreversible_schema_statement_call, <<~PATTERN
|
||||
@ -271,11 +271,7 @@ module RuboCop
|
||||
def check_remove_foreign_key_node(node)
|
||||
remove_foreign_key_call(node) do |arg|
|
||||
if arg.hash_type? && !all_hash_key?(arg, :to_table)
|
||||
add_offense(
|
||||
node,
|
||||
message: format(MSG,
|
||||
action: 'remove_foreign_key(without table)')
|
||||
)
|
||||
add_offense(node, message: format(MSG, action: 'remove_foreign_key(without table)'))
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -36,10 +36,12 @@ module RuboCop
|
||||
# foo&.bar
|
||||
# foo&.bar(baz)
|
||||
# foo&.bar { |e| e.baz }
|
||||
class SafeNavigation < Cop
|
||||
class SafeNavigation < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use safe navigation (`&.`) instead of `%<try>s`.'
|
||||
RESTRICT_ON_SEND = %i[try try!].freeze
|
||||
|
||||
def_node_matcher :try_call, <<~PATTERN
|
||||
(send !nil? ${:try :try!} $_ ...)
|
||||
@ -50,24 +52,23 @@ module RuboCop
|
||||
return if try_method == :try && !cop_config['ConvertTry']
|
||||
return unless dispatch.sym_type? && dispatch.value.match?(/\w+[=!?]?/)
|
||||
|
||||
add_offense(node, message: format(MSG, try: try_method))
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
method_node, *params = *node.arguments
|
||||
method = method_node.source[1..-1]
|
||||
|
||||
range = range_between(node.loc.dot.begin_pos,
|
||||
node.loc.expression.end_pos)
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.replace(range, replacement(method, params))
|
||||
add_offense(node, message: format(MSG, try: try_method)) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
method_node, *params = *node.arguments
|
||||
method = method_node.source[1..-1]
|
||||
|
||||
range = range_between(node.loc.dot.begin_pos, node.loc.expression.end_pos)
|
||||
|
||||
corrector.replace(range, replacement(method, params))
|
||||
end
|
||||
|
||||
def replacement(method, params)
|
||||
new_params = params.map(&:source).join(', ')
|
||||
|
||||
@ -19,7 +19,9 @@ module RuboCop
|
||||
# do_something if foo.blank?
|
||||
# do_something unless foo.blank?
|
||||
#
|
||||
class SafeNavigationWithBlank < Cop
|
||||
class SafeNavigationWithBlank < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG =
|
||||
'Avoid calling `blank?` with the safe navigation operator ' \
|
||||
'in conditionals.'
|
||||
@ -31,15 +33,8 @@ module RuboCop
|
||||
def on_if(node)
|
||||
return unless safe_navigation_blank_in_conditional?(node)
|
||||
|
||||
add_offense(node)
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
corrector.replace(
|
||||
safe_navigation_blank_in_conditional?(node).location.dot,
|
||||
'.'
|
||||
)
|
||||
add_offense(node) do |corrector|
|
||||
corrector.replace(safe_navigation_blank_in_conditional?(node).location.dot, '.')
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -98,8 +98,9 @@ module RuboCop
|
||||
# Services::Service::Mailer.update(message: 'Message')
|
||||
# Service::Mailer::update
|
||||
#
|
||||
class SaveBang < Cop
|
||||
class SaveBang < Base
|
||||
include NegativeConditional
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<prefer>s` instead of `%<current>s` if the return ' \
|
||||
'value is not checked.'
|
||||
@ -113,11 +114,10 @@ module RuboCop
|
||||
first_or_create find_or_create_by].freeze
|
||||
MODIFY_PERSIST_METHODS = %i[save
|
||||
update update_attributes destroy].freeze
|
||||
PERSIST_METHODS = (CREATE_PERSIST_METHODS +
|
||||
MODIFY_PERSIST_METHODS).freeze
|
||||
RESTRICT_ON_SEND = (CREATE_PERSIST_METHODS + MODIFY_PERSIST_METHODS).freeze
|
||||
|
||||
def join_force?(force_class)
|
||||
force_class == VariableForce
|
||||
def self.joining_forces
|
||||
VariableForce
|
||||
end
|
||||
|
||||
def after_leaving_scope(scope, _variable_table)
|
||||
@ -135,7 +135,7 @@ module RuboCop
|
||||
return unless persist_method?(node, CREATE_PERSIST_METHODS)
|
||||
return if persisted_referenced?(assignment)
|
||||
|
||||
add_offense_for_node(node, CREATE_MSG)
|
||||
register_offense(node, CREATE_MSG)
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
@ -148,25 +148,22 @@ module RuboCop
|
||||
return if explicit_return?(node)
|
||||
return if checked_immediately?(node)
|
||||
|
||||
add_offense_for_node(node)
|
||||
register_offense(node, MSG)
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
alias on_csend on_send
|
||||
|
||||
def autocorrect(node)
|
||||
save_loc = node.loc.selector
|
||||
new_method = "#{node.method_name}!"
|
||||
|
||||
->(corrector) { corrector.replace(save_loc, new_method) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def add_offense_for_node(node, msg = MSG)
|
||||
name = node.method_name
|
||||
full_message = format(msg, prefer: "#{name}!", current: name.to_s)
|
||||
def register_offense(node, msg)
|
||||
current_method = node.method_name
|
||||
bang_method = "#{current_method}!"
|
||||
full_message = format(msg, prefer: bang_method, current: current_method)
|
||||
|
||||
add_offense(node, location: :selector, message: full_message)
|
||||
range = node.loc.selector
|
||||
add_offense(range, message: full_message) do |corrector|
|
||||
corrector.replace(range, bang_method)
|
||||
end
|
||||
end
|
||||
|
||||
def right_assignment_node(assignment)
|
||||
@ -218,7 +215,7 @@ module RuboCop
|
||||
def check_used_in_condition_or_compound_boolean(node)
|
||||
return false unless in_condition_or_compound_boolean?(node)
|
||||
|
||||
add_offense_for_node(node, CREATE_CONDITIONAL_MSG) unless MODIFY_PERSIST_METHODS.include?(node.method_name)
|
||||
register_offense(node, CREATE_CONDITIONAL_MSG) unless MODIFY_PERSIST_METHODS.include?(node.method_name)
|
||||
|
||||
true
|
||||
end
|
||||
@ -318,7 +315,7 @@ module RuboCop
|
||||
assignment&.lvasgn_type?
|
||||
end
|
||||
|
||||
def persist_method?(node, methods = PERSIST_METHODS)
|
||||
def persist_method?(node, methods = RESTRICT_ON_SEND)
|
||||
methods.include?(node.method_name) &&
|
||||
expected_signature?(node) &&
|
||||
!allowed_receiver?(node)
|
||||
@ -13,8 +13,9 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# scope :something, -> { where(something: true) }
|
||||
class ScopeArgs < Cop
|
||||
class ScopeArgs < Base
|
||||
MSG = 'Use `lambda`/`proc` instead of a plain method call.'
|
||||
RESTRICT_ON_SEND = %i[scope].freeze
|
||||
|
||||
def_node_matcher :scope?, '(send nil? :scope _ $send)'
|
||||
|
||||
@ -38,8 +38,9 @@ module RuboCop
|
||||
# t :key
|
||||
# l Time.now
|
||||
#
|
||||
class ShortI18n < Cop
|
||||
class ShortI18n < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<good_method>s` instead of `%<bad_method>s`.'
|
||||
|
||||
@ -48,6 +49,8 @@ module RuboCop
|
||||
localize: :l
|
||||
}.freeze
|
||||
|
||||
RESTRICT_ON_SEND = PREFERRED_METHODS.keys.freeze
|
||||
|
||||
def_node_matcher :long_i18n?, <<~PATTERN
|
||||
(send {nil? (const nil? :I18n)} ${:translate :localize} ...)
|
||||
PATTERN
|
||||
@ -58,15 +61,10 @@ module RuboCop
|
||||
long_i18n?(node) do |method_name|
|
||||
good_method = PREFERRED_METHODS[method_name]
|
||||
message = format(MSG, good_method: good_method, bad_method: method_name)
|
||||
range = node.loc.selector
|
||||
|
||||
add_offense(node, location: :selector, message: message)
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
long_i18n?(node) do |method_name|
|
||||
lambda do |corrector|
|
||||
corrector.replace(node.loc.selector, PREFERRED_METHODS[method_name])
|
||||
add_offense(range, message: message) do |corrector|
|
||||
corrector.replace(range, PREFERRED_METHODS[method_name])
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -7,7 +7,7 @@ module RuboCop
|
||||
# validations which are listed in
|
||||
# https://guides.rubyonrails.org/active_record_validations.html#skipping-validations
|
||||
#
|
||||
# Methods may be ignored from this rule by configuring a `Whitelist`.
|
||||
# Methods may be ignored from this rule by configuring a `AllowedMethods`.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
@ -26,7 +26,7 @@ module RuboCop
|
||||
# user.update(website: 'example.com')
|
||||
# FileUtils.touch('file')
|
||||
#
|
||||
# @example Whitelist: ["touch"]
|
||||
# @example AllowedMethods: ["touch"]
|
||||
# # bad
|
||||
# DiscussionBoard.decrement_counter(:post_count, 5)
|
||||
# DiscussionBoard.increment_counter(:post_count, 5)
|
||||
@ -35,7 +35,7 @@ module RuboCop
|
||||
# # good
|
||||
# user.touch
|
||||
#
|
||||
class SkipsModelValidations < Cop
|
||||
class SkipsModelValidations < Base
|
||||
MSG = 'Avoid using `%<method>s` because it skips validations.'
|
||||
|
||||
METHODS_WITH_ARGUMENTS = %w[decrement!
|
||||
@ -76,7 +76,7 @@ module RuboCop
|
||||
return if good_touch?(node)
|
||||
return if good_insert?(node)
|
||||
|
||||
add_offense(node, location: :selector)
|
||||
add_offense(node.loc.selector, message: message(node))
|
||||
end
|
||||
alias on_csend on_send
|
||||
|
||||
@ -5,6 +5,8 @@ module RuboCop
|
||||
module Rails
|
||||
#
|
||||
# Checks SQL heredocs to use `.squish`.
|
||||
# Some SQL syntax (e.g. PostgreSQL comments and functions) requires newlines
|
||||
# to be preserved in order to work, thus auto-correction for this cop is not safe.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
@ -37,8 +39,9 @@ module RuboCop
|
||||
# WHERE post_id = 1
|
||||
# SQL
|
||||
#
|
||||
class SquishedSQLHeredocs < Cop
|
||||
class SquishedSQLHeredocs < Base
|
||||
include Heredoc
|
||||
extend AutoCorrector
|
||||
|
||||
SQL = 'SQL'
|
||||
SQUISH = '.squish'
|
||||
@ -47,11 +50,7 @@ module RuboCop
|
||||
def on_heredoc(node)
|
||||
return unless offense_detected?(node)
|
||||
|
||||
add_offense(node)
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
add_offense(node) do |corrector|
|
||||
corrector.insert_after(node, SQUISH)
|
||||
end
|
||||
end
|
||||
@ -43,8 +43,9 @@ module RuboCop
|
||||
# # good
|
||||
# Time.current
|
||||
# Time.at(timestamp).in_time_zone
|
||||
class TimeZone < Cop
|
||||
class TimeZone < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Do not use `%<current>s` without zone. Use `%<prefer>s` ' \
|
||||
'instead.'
|
||||
@ -71,27 +72,25 @@ module RuboCop
|
||||
check_time_node(klass, node.parent) if klass == :Time
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
# add `.zone`: `Time.at` => `Time.zone.at`
|
||||
corrector.insert_after(node.children[0].source_range, '.zone')
|
||||
|
||||
case node.method_name
|
||||
when :current
|
||||
# replace `Time.zone.current` => `Time.zone.now`
|
||||
corrector.replace(node.loc.selector, 'now')
|
||||
when :new
|
||||
autocorrect_time_new(node, corrector)
|
||||
end
|
||||
|
||||
# prefer `Time` over `DateTime` class
|
||||
corrector.replace(node.children.first.source_range, 'Time') if strict?
|
||||
remove_redundant_in_time_zone(corrector, node)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
# add `.zone`: `Time.at` => `Time.zone.at`
|
||||
corrector.insert_after(node.children[0].source_range, '.zone')
|
||||
|
||||
case node.method_name
|
||||
when :current
|
||||
# replace `Time.zone.current` => `Time.zone.now`
|
||||
corrector.replace(node.loc.selector, 'now')
|
||||
when :new
|
||||
autocorrect_time_new(node, corrector)
|
||||
end
|
||||
|
||||
# prefer `Time` over `DateTime` class
|
||||
corrector.replace(node.children.first.source_range, 'Time') if strict?
|
||||
remove_redundant_in_time_zone(corrector, node)
|
||||
end
|
||||
|
||||
def autocorrect_time_new(node, corrector)
|
||||
if node.arguments?
|
||||
corrector.replace(node.loc.selector, 'local')
|
||||
@ -128,7 +127,9 @@ module RuboCop
|
||||
|
||||
message = build_message(klass, method_name, node)
|
||||
|
||||
add_offense(node, location: :selector, message: message)
|
||||
add_offense(node.loc.selector, message: message) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
|
||||
def build_message(klass, method_name, node)
|
||||
@ -193,8 +194,9 @@ module RuboCop
|
||||
|
||||
return if node.arguments?
|
||||
|
||||
add_offense(selector_node,
|
||||
location: :selector, message: MSG_LOCALTIME)
|
||||
add_offense(selector_node.loc.selector, message: MSG_LOCALTIME) do |corrector|
|
||||
autocorrect(corrector, selector_node)
|
||||
end
|
||||
end
|
||||
|
||||
def not_danger_chain?(chain)
|
||||
@ -45,11 +45,13 @@ module RuboCop
|
||||
# # good
|
||||
# Model.distinct.pluck(:id)
|
||||
#
|
||||
class UniqBeforePluck < RuboCop::Cop::Cop
|
||||
class UniqBeforePluck < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `distinct` before `pluck`.'
|
||||
RESTRICT_ON_SEND = %i[uniq distinct pluck].freeze
|
||||
NEWLINE = "\n"
|
||||
PATTERN = '[!^block (send (send %<type>s :pluck ...) ' \
|
||||
'${:uniq :distinct} ...)]'
|
||||
@ -69,11 +71,7 @@ module RuboCop
|
||||
|
||||
return unless method
|
||||
|
||||
add_offense(node, location: :selector)
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
add_offense(node.loc.selector) do |corrector|
|
||||
method = node.method_name
|
||||
|
||||
corrector.remove(dot_method_with_whitespace(method, node))
|
||||
@ -24,13 +24,13 @@ module RuboCop
|
||||
# # good - even if the schema does not have a unique index
|
||||
# validates :account, length: { minimum: MIN_LENGTH }
|
||||
#
|
||||
class UniqueValidationWithoutIndex < Cop
|
||||
class UniqueValidationWithoutIndex < Base
|
||||
include ActiveRecordHelper
|
||||
|
||||
MSG = 'Uniqueness validation should be with a unique index.'
|
||||
RESTRICT_ON_SEND = %i[validates].freeze
|
||||
|
||||
def on_send(node)
|
||||
return unless node.method?(:validates)
|
||||
return unless uniqueness_part(node)
|
||||
return if condition_part?(node)
|
||||
return unless schema
|
||||
@ -17,7 +17,7 @@ module RuboCop
|
||||
# # good
|
||||
# Rails.env.production?
|
||||
# Rails.env == 'production'
|
||||
class UnknownEnv < Cop
|
||||
class UnknownEnv < Base
|
||||
MSG = 'Unknown environment `%<name>s`.'
|
||||
MSG_SIMILAR = 'Unknown environment `%<name>s`. ' \
|
||||
'Did you mean `%<similar>s`?'
|
||||
@ -41,7 +41,7 @@ module RuboCop
|
||||
|
||||
def on_send(node)
|
||||
unknown_environment_predicate?(node) do |name|
|
||||
add_offense(node, location: :selector, message: message(name))
|
||||
add_offense(node.loc.selector, message: message(name))
|
||||
end
|
||||
|
||||
unknown_environment_equal?(node) do |str_node|
|
||||
@ -32,7 +32,9 @@ module RuboCop
|
||||
# validates :foo, size: true
|
||||
# validates :foo, uniqueness: true
|
||||
#
|
||||
class Validation < Cop
|
||||
class Validation < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Prefer the new style validations `%<prefer>s` over ' \
|
||||
'`%<current>s`.'
|
||||
|
||||
@ -50,22 +52,20 @@ module RuboCop
|
||||
uniqueness
|
||||
].freeze
|
||||
|
||||
DENYLIST = TYPES.map { |p| "validates_#{p}_of".to_sym }.freeze
|
||||
RESTRICT_ON_SEND = TYPES.map { |p| "validates_#{p}_of".to_sym }.freeze
|
||||
ALLOWLIST = TYPES.map { |p| "validates :column, #{p}: value" }.freeze
|
||||
|
||||
def on_send(node)
|
||||
return unless !node.receiver && DENYLIST.include?(node.method_name)
|
||||
return if node.receiver
|
||||
|
||||
add_offense(node, location: :selector)
|
||||
end
|
||||
range = node.loc.selector
|
||||
|
||||
def autocorrect(node)
|
||||
last_argument = node.arguments.last
|
||||
return if !last_argument.literal? && !last_argument.splat_type? &&
|
||||
!frozen_array_argument?(last_argument)
|
||||
add_offense(range, message: message(node)) do |corrector|
|
||||
last_argument = node.arguments.last
|
||||
return if !last_argument.literal? && !last_argument.splat_type? &&
|
||||
!frozen_array_argument?(last_argument)
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.replace(node.loc.selector, 'validates')
|
||||
corrector.replace(range, 'validates')
|
||||
correct_validate_type(corrector, node)
|
||||
end
|
||||
end
|
||||
@ -73,12 +73,13 @@ module RuboCop
|
||||
private
|
||||
|
||||
def message(node)
|
||||
format(MSG, prefer: preferred_method(node.method_name),
|
||||
current: node.method_name)
|
||||
method_name = node.method_name
|
||||
|
||||
format(MSG, prefer: preferred_method(method_name), current: method_name)
|
||||
end
|
||||
|
||||
def preferred_method(method)
|
||||
ALLOWLIST[DENYLIST.index(method.to_sym)]
|
||||
ALLOWLIST[RESTRICT_ON_SEND.index(method.to_sym)]
|
||||
end
|
||||
|
||||
def correct_validate_type(corrector, node)
|
||||
@ -0,0 +1,94 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Rails
|
||||
# This cop identifies places where manually constructed SQL
|
||||
# in `where` can be replaced with `where(attribute: value)`.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# User.where('name = ?', 'Gabe')
|
||||
# User.where('name = :name', name: 'Gabe')
|
||||
# User.where('name IS NULL')
|
||||
# User.where('name IN (?)', ['john', 'jane'])
|
||||
# User.where('name IN (:names)', names: ['john', 'jane'])
|
||||
#
|
||||
# # good
|
||||
# User.where(name: 'Gabe')
|
||||
# User.where(name: nil)
|
||||
# User.where(name: ['john', 'jane'])
|
||||
class WhereEquals < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<good_method>s` instead of manually constructing SQL.'
|
||||
RESTRICT_ON_SEND = %i[where].freeze
|
||||
|
||||
def_node_matcher :where_method_call?, <<~PATTERN
|
||||
{
|
||||
(send _ :where (array $str_type? $_ ?))
|
||||
(send _ :where $str_type? $_ ?)
|
||||
}
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
where_method_call?(node) do |template_node, value_node|
|
||||
value_node = value_node.first
|
||||
|
||||
range = offense_range(node)
|
||||
|
||||
column_and_value = extract_column_and_value(template_node, value_node)
|
||||
return unless column_and_value
|
||||
|
||||
good_method = build_good_method(*column_and_value)
|
||||
message = format(MSG, good_method: good_method)
|
||||
|
||||
add_offense(range, message: message) do |corrector|
|
||||
corrector.replace(range, good_method)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
EQ_ANONYMOUS_RE = /\A([\w.]+)\s+=\s+\?\z/.freeze # column = ?
|
||||
IN_ANONYMOUS_RE = /\A([\w.]+)\s+IN\s+\(\?\)\z/i.freeze # column IN (?)
|
||||
EQ_NAMED_RE = /\A([\w.]+)\s+=\s+:(\w+)\z/.freeze # column = :column
|
||||
IN_NAMED_RE = /\A([\w.]+)\s+IN\s+\(:(\w+)\)\z/i.freeze # column IN (:column)
|
||||
IS_NULL_RE = /\A([\w.]+)\s+IS\s+NULL\z/i.freeze # column IS NULL
|
||||
|
||||
private
|
||||
|
||||
def offense_range(node)
|
||||
range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos)
|
||||
end
|
||||
|
||||
def extract_column_and_value(template_node, value_node)
|
||||
value =
|
||||
case template_node.value
|
||||
when EQ_ANONYMOUS_RE, IN_ANONYMOUS_RE
|
||||
value_node.source
|
||||
when EQ_NAMED_RE, IN_NAMED_RE
|
||||
return unless value_node.hash_type?
|
||||
|
||||
pair = value_node.pairs.find { |p| p.key.value.to_sym == Regexp.last_match(2).to_sym }
|
||||
pair.value.source
|
||||
when IS_NULL_RE
|
||||
'nil'
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
[Regexp.last_match(1), value]
|
||||
end
|
||||
|
||||
def build_good_method(column, value)
|
||||
if column.include?('.')
|
||||
"where('#{column}' => #{value})"
|
||||
else
|
||||
"where(#{column}: #{value})"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -36,10 +36,12 @@ module RuboCop
|
||||
# User.where('name = ?', 'john').exists?
|
||||
# user.posts.where(published: true).exists?
|
||||
# User.where('length(name) > 10').exists?
|
||||
class WhereExists < Cop
|
||||
class WhereExists < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Prefer `%<good_method>s` over `%<bad_method>s`.'
|
||||
RESTRICT_ON_SEND = %i[exists?].freeze
|
||||
|
||||
def_node_matcher :where_exists_call?, <<~PATTERN
|
||||
(send (send _ :where $...) :exists?)
|
||||
@ -54,19 +56,12 @@ module RuboCop
|
||||
return unless convertable_args?(args)
|
||||
|
||||
range = correction_range(node)
|
||||
message = format(MSG, good_method: build_good_method(args), bad_method: range.source)
|
||||
add_offense(node, location: range, message: message)
|
||||
end
|
||||
end
|
||||
good_method = build_good_method(args)
|
||||
message = format(MSG, good_method: good_method, bad_method: range.source)
|
||||
|
||||
def autocorrect(node)
|
||||
args = find_offenses(node)
|
||||
|
||||
lambda do |corrector|
|
||||
corrector.replace(
|
||||
correction_range(node),
|
||||
build_good_method(args)
|
||||
)
|
||||
add_offense(range, message: message) do |corrector|
|
||||
corrector.replace(range, good_method)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -21,10 +21,12 @@ module RuboCop
|
||||
# User.where.not(name: nil)
|
||||
# User.where.not(name: ['john', 'jane'])
|
||||
#
|
||||
class WhereNot < Cop
|
||||
class WhereNot < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<good_method>s` instead of manually constructing negated SQL in `where`.'
|
||||
RESTRICT_ON_SEND = %i[where].freeze
|
||||
|
||||
def_node_matcher :where_method_call?, <<~PATTERN
|
||||
{
|
||||
@ -45,21 +47,8 @@ module RuboCop
|
||||
good_method = build_good_method(*column_and_value)
|
||||
message = format(MSG, good_method: good_method)
|
||||
|
||||
add_offense(node, location: range, message: message)
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
where_method_call?(node) do |template_node, value_node|
|
||||
value_node = value_node.first
|
||||
|
||||
lambda do |corrector|
|
||||
range = offense_range(node)
|
||||
|
||||
column, value = *extract_column_and_value(template_node, value_node)
|
||||
replacement = build_good_method(column, value)
|
||||
|
||||
corrector.replace(range, replacement)
|
||||
add_offense(range, message: message) do |corrector|
|
||||
corrector.replace(range, good_method)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,6 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'mixin/active_record_helper'
|
||||
require_relative 'mixin/enforce_superclass'
|
||||
require_relative 'mixin/index_method'
|
||||
require_relative 'mixin/target_rails_version'
|
||||
|
||||
@ -14,7 +15,9 @@ require_relative 'rails/application_controller'
|
||||
require_relative 'rails/application_job'
|
||||
require_relative 'rails/application_mailer'
|
||||
require_relative 'rails/application_record'
|
||||
require_relative 'rails/arel_star'
|
||||
require_relative 'rails/assert_not'
|
||||
require_relative 'rails/attribute_default_block_value'
|
||||
require_relative 'rails/belongs_to'
|
||||
require_relative 'rails/blank'
|
||||
require_relative 'rails/bulk_change_table'
|
||||
@ -83,5 +86,6 @@ require_relative 'rails/uniq_before_pluck'
|
||||
require_relative 'rails/unique_validation_without_index'
|
||||
require_relative 'rails/unknown_env'
|
||||
require_relative 'rails/validation'
|
||||
require_relative 'rails/where_equals'
|
||||
require_relative 'rails/where_exists'
|
||||
require_relative 'rails/where_not'
|
||||
@ -13,15 +13,15 @@ module RuboCop
|
||||
#
|
||||
# @return [Schema, nil]
|
||||
def load(target_ruby_version)
|
||||
return @schema if defined?(@schema)
|
||||
return @load if defined?(@load)
|
||||
|
||||
@schema = load!(target_ruby_version)
|
||||
@load = load!(target_ruby_version)
|
||||
end
|
||||
|
||||
def reset!
|
||||
return unless instance_variable_defined?(:@schema)
|
||||
return unless instance_variable_defined?(:@load)
|
||||
|
||||
remove_instance_variable(:@schema)
|
||||
remove_instance_variable(:@load)
|
||||
end
|
||||
|
||||
def db_schema_path
|
||||
@ -98,7 +98,7 @@ module RuboCop
|
||||
end
|
||||
|
||||
def each_content(node, &block)
|
||||
return enum_for(__method__, node) unless block_given?
|
||||
return enum_for(__method__, node) unless block
|
||||
|
||||
case node.body&.type
|
||||
when :begin
|
||||
@ -4,7 +4,11 @@ module RuboCop
|
||||
module Rails
|
||||
# This module holds the RuboCop Rails version information.
|
||||
module Version
|
||||
STRING = '2.8.1'
|
||||
STRING = '2.9.0'
|
||||
|
||||
def self.document_version
|
||||
STRING.match('\d+\.\d+').to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user