diff --git a/CHANGELOG.md b/CHANGELOG.md index bacf0dd39d..2cc2e87cf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## master (unreleased) +### New features + +* [#521](https://github.com/rubocop/rubocop-rails/pull/521): Support auto-correction for `Rails/Output`. ([@koic][]) + ## 2.11.3 (2021-07-11) ### Bug fixes diff --git a/docs/modules/ROOT/pages/cops_rails.adoc b/docs/modules/ROOT/pages/cops_rails.adoc index 699bc76e66..cc5d523a92 100644 --- a/docs/modules/ROOT/pages/cops_rails.adoc +++ b/docs/modules/ROOT/pages/cops_rails.adoc @@ -2747,7 +2747,7 @@ scope :chronological, -> { order(created_at: :asc) } | Enabled | Yes -| No +| Yes | 0.15 | 0.19 |=== diff --git a/lib/rubocop/cop/rails/output.rb b/lib/rubocop/cop/rails/output.rb index 2d2df29581..a06b98b8e4 100644 --- a/lib/rubocop/cop/rails/output.rb +++ b/lib/rubocop/cop/rails/output.rb @@ -14,6 +14,9 @@ module Rails # # good # Rails.logger.debug 'A debug message' class Output < Base + include RangeHelp + extend AutoCorrector + MSG = 'Do not write to stdout. ' \ "Use Rails's logger if you want to log." RESTRICT_ON_SEND = %i[ @@ -35,10 +38,13 @@ class Output < Base PATTERN def on_send(node) - return unless (output?(node) || io_output?(node)) && - node.arguments? + return unless (output?(node) || io_output?(node)) && node.arguments? + + range = offense_range(node) - add_offense(node.loc.selector) + add_offense(range) do |corrector| + corrector.replace(range, 'Rails.logger.debug') + end end private @@ -46,6 +52,14 @@ def on_send(node) def match_gvar?(sym) %i[$stdout $stderr].include?(sym) end + + def offense_range(node) + if node.receiver + range_between(node.loc.expression.begin_pos, node.loc.selector.end_pos) + else + node.loc.selector + end + end end end end diff --git a/spec/rubocop/cop/rails/output_spec.rb b/spec/rubocop/cop/rails/output_spec.rb index c27d59c741..4e3077df18 100644 --- a/spec/rubocop/cop/rails/output_spec.rb +++ b/spec/rubocop/cop/rails/output_spec.rb @@ -1,22 +1,80 @@ # frozen_string_literal: true RSpec.describe RuboCop::Cop::Rails::Output, :config do - it 'registers an offense for methods without a receiver' do + it 'registers and corrects an offense for using `p` method without a receiver' do expect_offense(<<~RUBY) p "edmond dantes" ^ Do not write to stdout. Use Rails's logger if you want to log. + RUBY + + expect_correction(<<~RUBY) + Rails.logger.debug "edmond dantes" + RUBY + end + + it 'registers and corrects an offense for using `puts` method without a receiver' do + expect_offense(<<~RUBY) puts "sinbad" ^^^^ Do not write to stdout. Use Rails's logger if you want to log. + RUBY + + expect_correction(<<~RUBY) + Rails.logger.debug "sinbad" + RUBY + end + + it 'registers and corrects an offense for using `print` method without a receiver' do + expect_offense(<<~RUBY) print "abbe busoni" ^^^^^ Do not write to stdout. Use Rails's logger if you want to log. + RUBY + + expect_correction(<<~RUBY) + Rails.logger.debug "abbe busoni" + RUBY + end + + it 'registers and corrects an offense for using `pp` method without a receiver' do + expect_offense(<<~RUBY) pp "monte cristo" ^^ Do not write to stdout. Use Rails's logger if you want to log. + RUBY + + expect_correction(<<~RUBY) + Rails.logger.debug "monte cristo" + RUBY + end + + it 'registers and corrects an offense for using `$stdout` method without a receiver' do + expect_offense(<<~RUBY) $stdout.write "lord wilmore" - ^^^^^ Do not write to stdout. Use Rails's logger if you want to log. + ^^^^^^^^^^^^^ Do not write to stdout. Use Rails's logger if you want to log. + RUBY + + expect_correction(<<~RUBY) + Rails.logger.debug "lord wilmore" + RUBY + end + + it 'registers and corrects an offense for using `syswrite` method without a receiver' do + expect_offense(<<~RUBY) $stderr.syswrite "faria" - ^^^^^^^^ Do not write to stdout. Use Rails's logger if you want to log. + ^^^^^^^^^^^^^^^^ Do not write to stdout. Use Rails's logger if you want to log. + RUBY + + expect_correction(<<~RUBY) + Rails.logger.debug "faria" + RUBY + end + + it 'registers and corrects an offense for using `write` method without a receiver' do + expect_offense(<<~RUBY) STDOUT.write "bertuccio" - ^^^^^ Do not write to stdout. Use Rails's logger if you want to log. + ^^^^^^^^^^^^ Do not write to stdout. Use Rails's logger if you want to log. + RUBY + + expect_correction(<<~RUBY) + Rails.logger.debug "bertuccio" RUBY end