Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
166 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module Style | ||
# This cop enforces the use of `$stdout/$stderr/$stdin` instead of `STDOUT/STDERR/STDIN`. | ||
# `STDOUT/STDERR/STDIN` are constants, and while you can actually | ||
# reassign (possibly to redirect some stream) constants in Ruby, you'll get | ||
# an interpreter warning if you do so. | ||
# | ||
# @example | ||
# # bad | ||
# STDOUT.puts('hello') | ||
# | ||
# hash = { out: STDOUT, key: value } | ||
# | ||
# def m(out = STDOUT) | ||
# out.puts('hello') | ||
# end | ||
# | ||
# # good | ||
# $stdout.puts('hello') | ||
# | ||
# hash = { out: $stdout, key: value } | ||
# | ||
# def m(out = $stdout) | ||
# out.puts('hello') | ||
# end | ||
# | ||
class GlobalStdStream < Base | ||
extend AutoCorrector | ||
|
||
MSG = 'Use `%<gvar_name>s` instead of `%<const_name>s`.' | ||
|
||
STD_STREAMS = %i[STDIN STDOUT STDERR].to_set.freeze | ||
|
||
def_node_matcher :const_to_gvar_assignment?, <<~PATTERN | ||
(gvasgn %1 (const nil? _)) | ||
PATTERN | ||
|
||
def on_const(node) | ||
const_name = node.children[1] | ||
return unless STD_STREAMS.include?(const_name) | ||
|
||
gvar_name = gvar_name(const_name).to_sym | ||
return if const_to_gvar_assignment?(node.parent, gvar_name) | ||
|
||
add_offense(node, message: message(const_name)) do |corrector| | ||
corrector.replace(node, gvar_name) | ||
end | ||
end | ||
|
||
private | ||
|
||
def message(const_name) | ||
format(MSG, gvar_name: gvar_name(const_name), const_name: const_name) | ||
end | ||
|
||
def gvar_name(const_name) | ||
"$#{const_name.to_s.downcase}" | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe RuboCop::Cop::Style::GlobalStdStream do | ||
subject(:cop) { described_class.new } | ||
|
||
it 'registers an offense and corrects when using std stream as const' do | ||
expect_offense(<<~RUBY) | ||
STDOUT.puts('hello') | ||
^^^^^^ Use `$stdout` instead of `STDOUT`. | ||
hash = { out: STDOUT, key: value } | ||
^^^^^^ Use `$stdout` instead of `STDOUT`. | ||
def m(out = STDOUT) | ||
^^^^^^ Use `$stdout` instead of `STDOUT`. | ||
out.puts('hello') | ||
end | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
$stdout.puts('hello') | ||
hash = { out: $stdout, key: value } | ||
def m(out = $stdout) | ||
out.puts('hello') | ||
end | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when using non std stream const' do | ||
expect_no_offenses(<<~RUBY) | ||
SOME_CONST.puts('hello') | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when assigning std stream const to std stream gvar' do | ||
expect_no_offenses(<<~RUBY) | ||
$stdin = STDIN | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when assigning other const to std stream gvar' do | ||
expect_no_offenses(<<~RUBY) | ||
$stdin = SOME_CONST | ||
RUBY | ||
end | ||
end |