Skip to content

Commit

Permalink
Add support for --stdin-filename
Browse files Browse the repository at this point in the history
When other tools, like automatic linters within editors, run a sample
through reek, they typically do so via stdin. However, if there are reek
config exceptions to apply to that file, then reek has no way of knowing
what the original filename was, triggering false positives.

This adds an `--stdin-filename` CLI option that takes the
original filename, and passes it through to the Examiner and SourceCode
file to use as the `origin` attribute, allowing the configuration
directives to apply.
  • Loading branch information
paul committed Jun 17, 2018
1 parent a5c8573 commit 9ce6b6f
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 6 deletions.
1 change: 1 addition & 0 deletions features/command_line_interface/options.feature
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Feature: Reek can be controlled using command-line options
--smell SMELL Only look for a specific smell.
Call it like this: reek --smell MissingSafeMethod source.rb
Check out https://github.com/troessner/reek/blob/v4.8.1/docs/Code-Smells.md for a list of smells
--stdin-filename FILE When passing code in via pipe, assume this filename when checking file or directory rules in the config.
Generate a todo list:
-t, --todo Generate a todo list
Expand Down
29 changes: 29 additions & 0 deletions features/command_line_interface/stdin.feature
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,32 @@ Feature: Reek reads from $stdin when no files are given
[2]:Syntax: This file has unexpected token $end
[1]:Syntax: This file has unexpected token tEQL
"""

Scenario: providing a filename to use for the config to match against
Given a file named "web_app/config.reek" with:
"""
---
directories:
"web_app/app/controllers":
IrresponsibleModule:
enabled: false
NestedIterators:
enabled: false
InstanceVariableAssumption:
enabled: false
"""
When I pass a stdin to reek --config web_app/config.reek --stdin-filename web_app/app/controllers/users_controller with:
"""
class UsersController < ApplicationController
def show
respond_with do |format|
format.json { |json| @user.to_custom_json }
format.xml { |xml| @user.to_fancy_xml }
end
end
end
"""
Then it succeeds



4 changes: 4 additions & 0 deletions features/step_definitions/reek_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
reek_with_pipe(stdin, args)
end

When /^I pass a stdin to reek *(.*) with:$/ do |args, stdin|
reek_with_pipe(stdin, args)
end

Then /^it reports nothing$/ do
expect(last_command_started).to have_output_on_stdout('')
end
Expand Down
2 changes: 2 additions & 0 deletions lib/reek/cli/command/report_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require_relative '../../examiner'
require_relative '../../logging_error_handler'
require_relative '../../report'
require_relative '../../source/source_code'

module Reek
module CLI
Expand All @@ -24,6 +25,7 @@ def execute
def populate_reporter_with_smells
sources.each do |source|
reporter.add_examiner Examiner.new(source,
stdin_filename: options.stdin_filename,
filter_by_smells: smell_names,
configuration: configuration,
error_handler: LoggingErrorHandler.new)
Expand Down
8 changes: 7 additions & 1 deletion lib/reek/cli/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Options
:show_empty,
:show_links,
:sorting,
:stdin_filename,
:success_exit_code,
:failure_exit_code,
:generate_todo_list,
Expand Down Expand Up @@ -98,7 +99,7 @@ def set_banner
BANNER
end

# :reek:TooManyStatements { max_statements: 6 }
# :reek:TooManyStatements { max_statements: 7 }
def set_configuration_options
parser.separator 'Configuration:'
parser.on('-c', '--config FILE', 'Read configuration options from FILE') do |file|
Expand All @@ -111,6 +112,11 @@ def set_configuration_options
'for a list of smells') do |smell|
smells_to_detect << smell
end
parser.on('--stdin-filename FILE',
'When passing code in via pipe, assume this filename when '\
'checking file or directory rules in the config.') do |file|
self.stdin_filename = Pathname.new(file)
end
end

def set_generate_todo_list_options
Expand Down
6 changes: 4 additions & 2 deletions lib/reek/examiner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ def handle(_exception)
# The configuration for this Examiner.
#
# @public
# :reek:LongParameterList { max_params: 6 }
def initialize(source,
stdin_filename: nil,
filter_by_smells: [],
configuration: Configuration::AppConfiguration.default,
detector_repository_class: DetectorRepository,
error_handler: NullHandler.new)
@source = Source::SourceCode.from(source)
@source = Source::SourceCode.from(source, filename: stdin_filename)
@smell_types = detector_repository_class.eligible_smell_types(filter_by_smells)
@detector_repository = detector_repository_class.new(smell_types: @smell_types,
configuration: configuration.directive_for(description))
Expand All @@ -49,7 +51,7 @@ def initialize(source,
#
# @public
def origin
@origin ||= source.origin
source.origin
end

# @return [String] description of the source being analysed
Expand Down
7 changes: 4 additions & 3 deletions lib/reek/source/source_code.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,13 @@ def initialize(code:, origin:, parser: self.class.default_parser)
#
# @return an instance of SourceCode
# :reek:DuplicateMethodCall { max_calls: 2 }
def self.from(source)
# :reek:ControlParameter
def self.from(source, filename: nil)
case source
when File then new(code: source.read, origin: source.path)
when IO then new(code: source.readlines.join, origin: IO_IDENTIFIER)
when IO then new(code: source.readlines.join, origin: filename || IO_IDENTIFIER)
when Pathname then new(code: source.read, origin: source.to_s)
when String then new(code: source, origin: STRING_IDENTIFIER)
when String then new(code: source, origin: filename || STRING_IDENTIFIER)
end
end

Expand Down
12 changes: 12 additions & 0 deletions spec/reek/cli/application_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@
configuration: Reek::Configuration::AppConfiguration,
options: Reek::CLI::Options)
end

context 'when a stdin filename is provided' do
let(:app) { described_class.new ['--stdin-filename', 'foo.rb'] }

it 'assumes that filename' do
app.execute
expect(Reek::CLI::Command::ReportCommand).to have_received(:new).
with(sources: [$stdin],
configuration: Reek::Configuration::AppConfiguration,
options: Reek::CLI::Options)
end
end
end

context 'when no source files given and no input was piped' do
Expand Down

0 comments on commit 9ce6b6f

Please sign in to comment.