reek 4.7.3 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.codeclimate.yml +17 -12
- data/.rubocop.yml +18 -3
- data/.simplecov +1 -0
- data/.travis.yml +3 -4
- data/.yardopts +1 -1
- data/CHANGELOG.md +45 -0
- data/Gemfile +4 -4
- data/README.md +134 -104
- data/Rakefile +16 -3
- data/bin/reek +1 -3
- data/docs/API.md +2 -9
- data/docs/Basic-Smell-Options.md +51 -11
- data/docs/Code-Smells.md +1 -1
- data/docs/Command-Line-Options.md +14 -4
- data/docs/Duplicate-Method-Call.md +49 -1
- data/docs/Feature-Envy.md +44 -0
- data/docs/How-To-Write-New-Detectors.md +2 -3
- data/docs/Instance-Variable-Assumption.md +1 -1
- data/docs/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
- data/docs/Rake-Task.md +1 -1
- data/docs/Reek-4-to-Reek-5-migration.md +193 -0
- data/docs/Reek-Driven-Development.md +1 -1
- data/docs/Uncommunicative-Method-Name.md +45 -6
- data/docs/Uncommunicative-Module-Name.md +49 -7
- data/docs/Uncommunicative-Parameter-Name.md +43 -5
- data/docs/Uncommunicative-Variable-Name.md +73 -2
- data/docs/Unused-Private-Method.md +2 -2
- data/docs/defaults.reek.yml +129 -0
- data/docs/yard_plugin.rb +1 -0
- data/features/command_line_interface/basic_usage.feature +2 -2
- data/features/command_line_interface/options.feature +46 -4
- data/features/command_line_interface/show_progress.feature +4 -4
- data/features/command_line_interface/smell_selection.feature +1 -1
- data/features/command_line_interface/smells_count.feature +6 -6
- data/features/command_line_interface/stdin.feature +30 -8
- data/features/configuration_files/accept_setting.feature +45 -28
- data/features/configuration_files/directory_specific_directives.feature +78 -73
- data/features/configuration_files/exclude_directives.feature +11 -10
- data/features/configuration_files/exclude_paths_directives.feature +4 -4
- data/features/configuration_files/masking_smells.feature +38 -9
- data/features/configuration_files/mix_accept_reject_setting.feature +31 -28
- data/features/configuration_files/reject_setting.feature +52 -41
- data/features/configuration_files/schema_validation.feature +59 -0
- data/features/configuration_files/unused_private_method.feature +18 -16
- data/features/configuration_loading.feature +53 -10
- data/features/configuration_via_source_comments/erroneous_source_comments.feature +2 -2
- data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
- data/features/locales.feature +2 -2
- data/features/rake_task/rake_task.feature +15 -15
- data/features/reports/json.feature +3 -3
- data/features/reports/reports.feature +34 -34
- data/features/reports/yaml.feature +3 -3
- data/features/rspec_matcher.feature +9 -1
- data/features/samples.feature +287 -287
- data/features/step_definitions/reek_steps.rb +4 -0
- data/features/step_definitions/sample_file_steps.rb +9 -4
- data/features/support/env.rb +2 -2
- data/features/todo_list.feature +26 -23
- data/lib/reek/ast/node.rb +40 -55
- data/lib/reek/ast/object_refs.rb +1 -1
- data/lib/reek/ast/reference_collector.rb +2 -4
- data/lib/reek/ast/sexp_extensions/case.rb +1 -1
- data/lib/reek/ast/sexp_extensions/if.rb +8 -1
- data/lib/reek/ast/sexp_extensions/logical_operators.rb +1 -1
- data/lib/reek/ast/sexp_extensions/methods.rb +4 -6
- data/lib/reek/cli/application.rb +4 -3
- data/lib/reek/cli/command/report_command.rb +1 -2
- data/lib/reek/cli/command/todo_list_command.rb +8 -8
- data/lib/reek/cli/options.rb +29 -14
- data/lib/reek/cli/silencer.rb +14 -3
- data/lib/reek/code_comment.rb +14 -16
- data/lib/reek/configuration/app_configuration.rb +32 -28
- data/lib/reek/configuration/configuration_converter.rb +110 -0
- data/lib/reek/configuration/configuration_file_finder.rb +15 -40
- data/lib/reek/configuration/configuration_validator.rb +12 -23
- data/lib/reek/configuration/default_directive.rb +17 -3
- data/lib/reek/configuration/directory_directives.rb +17 -11
- data/lib/reek/configuration/excluded_paths.rb +1 -1
- data/lib/reek/configuration/rake_task_converter.rb +29 -0
- data/lib/reek/configuration/schema.yml +210 -0
- data/lib/reek/configuration/schema_validator.rb +38 -0
- data/lib/reek/context/attribute_context.rb +1 -1
- data/lib/reek/context/code_context.rb +8 -11
- data/lib/reek/context/method_context.rb +7 -12
- data/lib/reek/context/module_context.rb +4 -4
- data/lib/reek/context_builder.rb +11 -11
- data/lib/reek/detector_repository.rb +6 -0
- data/lib/reek/documentation_link.rb +28 -0
- data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +13 -12
- data/lib/reek/errors/bad_detector_in_comment_error.rb +11 -10
- data/lib/reek/errors/base_error.rb +3 -0
- data/lib/reek/errors/config_file_error.rb +11 -0
- data/lib/reek/errors/encoding_error.rb +16 -11
- data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +11 -10
- data/lib/reek/errors/incomprehensible_source_error.rb +20 -22
- data/lib/reek/errors/syntax_error.rb +41 -0
- data/lib/reek/examiner.rb +19 -25
- data/lib/reek/logging_error_handler.rb +7 -5
- data/lib/reek/rake/task.rb +3 -3
- data/lib/reek/report/base_report.rb +8 -12
- data/lib/reek/report/code_climate/code_climate_configuration.rb +1 -1
- data/lib/reek/report/code_climate/code_climate_configuration.yml +6 -10
- data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
- data/lib/reek/report/heading_formatter.rb +54 -0
- data/lib/reek/report/json_report.rb +1 -1
- data/lib/reek/report/location_formatter.rb +40 -0
- data/lib/reek/report/progress_formatter.rb +79 -0
- data/lib/reek/report/simple_warning_formatter.rb +34 -0
- data/lib/reek/report/text_report.rb +1 -2
- data/lib/reek/report/xml_report.rb +3 -3
- data/lib/reek/report/yaml_report.rb +1 -1
- data/lib/reek/report.rb +15 -10
- data/lib/reek/smell_configuration.rb +2 -2
- data/lib/reek/smell_detectors/attribute.rb +0 -1
- data/lib/reek/smell_detectors/base_detector.rb +9 -12
- data/lib/reek/smell_detectors/boolean_parameter.rb +0 -1
- data/lib/reek/smell_detectors/class_variable.rb +3 -11
- data/lib/reek/smell_detectors/control_parameter.rb +17 -32
- data/lib/reek/smell_detectors/data_clump.rb +3 -4
- data/lib/reek/smell_detectors/duplicate_method_call.rb +6 -7
- data/lib/reek/smell_detectors/feature_envy.rb +1 -1
- data/lib/reek/smell_detectors/instance_variable_assumption.rb +1 -10
- data/lib/reek/smell_detectors/irresponsible_module.rb +0 -1
- data/lib/reek/smell_detectors/long_parameter_list.rb +1 -2
- data/lib/reek/smell_detectors/long_yield_list.rb +2 -3
- data/lib/reek/smell_detectors/manual_dispatch.rb +3 -3
- data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +6 -7
- data/lib/reek/smell_detectors/module_initialize.rb +1 -2
- data/lib/reek/smell_detectors/nested_iterators.rb +6 -6
- data/lib/reek/smell_detectors/nil_check.rb +0 -1
- data/lib/reek/smell_detectors/repeated_conditional.rb +3 -4
- data/lib/reek/smell_detectors/subclassed_from_core_class.rb +0 -1
- data/lib/reek/smell_detectors/too_many_constants.rb +2 -3
- data/lib/reek/smell_detectors/too_many_instance_variables.rb +1 -2
- data/lib/reek/smell_detectors/too_many_methods.rb +1 -2
- data/lib/reek/smell_detectors/too_many_statements.rb +1 -2
- data/lib/reek/smell_detectors/uncommunicative_method_name.rb +2 -3
- data/lib/reek/smell_detectors/uncommunicative_module_name.rb +2 -3
- data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +2 -3
- data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +6 -7
- data/lib/reek/smell_detectors/unused_parameters.rb +0 -1
- data/lib/reek/smell_detectors/unused_private_method.rb +0 -1
- data/lib/reek/smell_detectors/utility_function.rb +2 -3
- data/lib/reek/smell_detectors.rb +1 -2
- data/lib/reek/smell_warning.rb +15 -8
- data/lib/reek/source/source_code.rb +50 -72
- data/lib/reek/source/source_locator.rb +7 -7
- data/lib/reek/spec/should_reek.rb +2 -2
- data/lib/reek/spec/should_reek_of.rb +9 -16
- data/lib/reek/spec/should_reek_only_of.rb +4 -4
- data/lib/reek/spec.rb +6 -6
- data/lib/reek/tree_dresser.rb +5 -5
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +5 -5
- data/samples/checkstyle.xml +1 -1
- data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
- data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
- data/samples/configuration/full_configuration.reek +8 -4
- data/samples/configuration/full_mask.reek +5 -4
- data/samples/configuration/partial_mask.reek +3 -2
- data/samples/configuration/regular_configuration/.reek.yml +4 -0
- data/samples/paths.rb +5 -4
- data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
- data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
- data/spec/factories/factories.rb +2 -13
- data/spec/reek/ast/node_spec.rb +103 -10
- data/spec/reek/ast/reference_collector_spec.rb +1 -1
- data/spec/reek/ast/sexp_extensions_spec.rb +2 -2
- data/spec/reek/cli/application_spec.rb +50 -38
- data/spec/reek/cli/command/todo_list_command_spec.rb +6 -4
- data/spec/reek/cli/silencer_spec.rb +28 -0
- data/spec/reek/code_comment_spec.rb +31 -38
- data/spec/reek/configuration/app_configuration_spec.rb +46 -33
- data/spec/reek/configuration/configuration_file_finder_spec.rb +133 -49
- data/spec/reek/configuration/default_directive_spec.rb +1 -1
- data/spec/reek/configuration/directory_directives_spec.rb +6 -7
- data/spec/reek/configuration/excluded_paths_spec.rb +6 -6
- data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
- data/spec/reek/configuration/schema_validator_spec.rb +165 -0
- data/spec/reek/context/code_context_spec.rb +60 -96
- data/spec/reek/context/ghost_context_spec.rb +1 -1
- data/spec/reek/context/root_context_spec.rb +1 -1
- data/spec/reek/documentation_link_spec.rb +20 -0
- data/spec/reek/errors/base_error_spec.rb +13 -0
- data/spec/reek/examiner_spec.rb +100 -30
- data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +82 -80
- data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
- data/spec/reek/report/json_report_spec.rb +13 -46
- data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
- data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
- data/spec/reek/report/text_report_spec.rb +4 -4
- data/spec/reek/report/xml_report_spec.rb +3 -3
- data/spec/reek/report/yaml_report_spec.rb +9 -38
- data/spec/reek/report_spec.rb +3 -3
- data/spec/reek/smell_detectors/boolean_parameter_spec.rb +2 -2
- data/spec/reek/smell_detectors/class_variable_spec.rb +26 -32
- data/spec/reek/smell_detectors/control_parameter_spec.rb +34 -4
- data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +3 -3
- data/spec/reek/smell_detectors/feature_envy_spec.rb +47 -2
- data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +9 -9
- data/spec/reek/smell_detectors/module_initialize_spec.rb +14 -0
- data/spec/reek/smell_detectors/nested_iterators_spec.rb +1 -1
- data/spec/reek/smell_detectors/too_many_constants_spec.rb +3 -3
- data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +1 -1
- data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +6 -6
- data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +6 -4
- data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +6 -4
- data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +9 -9
- data/spec/reek/smell_detectors/unused_parameters_spec.rb +3 -3
- data/spec/reek/smell_detectors/unused_private_method_spec.rb +10 -10
- data/spec/reek/smell_detectors/utility_function_spec.rb +5 -5
- data/spec/reek/smell_warning_spec.rb +12 -8
- data/spec/reek/source/source_code_spec.rb +17 -43
- data/spec/reek/source/source_locator_spec.rb +17 -17
- data/spec/reek/spec/should_reek_of_spec.rb +7 -11
- data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
- data/spec/reek/spec/should_reek_spec.rb +3 -3
- data/spec/reek/spec/smell_matcher_spec.rb +3 -3
- data/spec/reek/tree_dresser_spec.rb +12 -17
- data/spec/spec_helper.rb +6 -17
- data/tasks/configuration.rake +8 -5
- metadata +71 -41
- data/defaults.reek +0 -131
- data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
- data/lib/reek/report/formatter/heading_formatter.rb +0 -52
- data/lib/reek/report/formatter/location_formatter.rb +0 -42
- data/lib/reek/report/formatter/progress_formatter.rb +0 -81
- data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
- data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -36
- data/lib/reek/report/formatter.rb +0 -33
- data/lib/reek/smell_detectors/syntax.rb +0 -37
- data/samples/configuration/non_public_modifiers_mask.reek +0 -3
- data/samples/smelly_with_inline_mask.rb +0 -8
- data/samples/smelly_with_modifiers.rb +0 -12
- data/samples/source_with_hidden_directories/.hidden/uncommunicative_method_name.rb +0 -5
- data/samples/source_with_non_ruby_files/uncommunicative_parameter_name.rb +0 -6
- data/spec/reek/smell_detectors/syntax_spec.rb +0 -17
- /data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
- /data/samples/{clean.rb → clean_source/clean.rb} +0 -0
- /data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
- /data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
- /data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
- /data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
- /data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
- /data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
- /data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
- /data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
|
@@ -6,6 +6,10 @@ When /^I pass "([^\"]*)" to reek *(.*)$/ do |stdin, args|
|
|
|
6
6
|
reek_with_pipe(stdin, args)
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
+
When /^I pass a stdin to reek *(.*) with:$/ do |args, stdin|
|
|
10
|
+
reek_with_pipe(stdin, args)
|
|
11
|
+
end
|
|
12
|
+
|
|
9
13
|
Then /^it reports nothing$/ do
|
|
10
14
|
expect(last_command_started).to have_output_on_stdout('')
|
|
11
15
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require_relative '../../samples/paths'
|
|
2
2
|
|
|
3
3
|
Given(/^the smelly file '(.+)'$/) do |filename|
|
|
4
|
-
write_file(filename,
|
|
4
|
+
write_file(filename, SAMPLES_DIR.join('smelly_source').join(filename).read)
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
Given(/^the clean file 'clean.rb'$/) do
|
|
@@ -28,13 +28,18 @@ Given(/^a directory called 'smelly' containing two smelly files$/) do
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
Given(/^the smelly file '(.+)' in a subdirectory$/) do |filename|
|
|
31
|
-
contents =
|
|
31
|
+
contents = SAMPLES_DIR.join('smelly_source').join(filename).read
|
|
32
32
|
|
|
33
33
|
write_file("subdir/#{filename}", contents)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
Given(/^a configuration file '(.+)'$/) do |filename|
|
|
37
|
-
write_file(filename,
|
|
37
|
+
write_file(filename, CONFIGURATION_DIR.join(filename).read)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
Given(/^our default configuration file$/) do
|
|
41
|
+
default_configuration = File.read SAMPLES_DIR.join('..').join('docs').join('defaults.reek.yml')
|
|
42
|
+
write_file('defaults.reek', default_configuration)
|
|
38
43
|
end
|
|
39
44
|
|
|
40
45
|
When(/^I run "reek (.*?)" in a subdirectory$/) do |args|
|
|
@@ -44,7 +49,7 @@ When(/^I run "reek (.*?)" in a subdirectory$/) do |args|
|
|
|
44
49
|
end
|
|
45
50
|
|
|
46
51
|
Given(/^a configuration file '(.+)' in a subdirectory$/) do |filename|
|
|
47
|
-
contents =
|
|
52
|
+
contents = CONFIGURATION_DIR.join(filename).read
|
|
48
53
|
|
|
49
54
|
write_file("subdir/#{filename}", contents)
|
|
50
55
|
end
|
data/features/support/env.rb
CHANGED
|
@@ -13,11 +13,11 @@ end
|
|
|
13
13
|
#
|
|
14
14
|
class ReekWorld
|
|
15
15
|
def reek(args)
|
|
16
|
-
run_simple("reek --no-color #{args}", false)
|
|
16
|
+
run_simple("reek --no-color --no-documentation #{args}", false)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def reek_with_pipe(stdin, args)
|
|
20
|
-
run "reek --no-color #{args}"
|
|
20
|
+
run "reek --no-color --no-documentation #{args}"
|
|
21
21
|
type(stdin)
|
|
22
22
|
close_input
|
|
23
23
|
end
|
data/features/todo_list.feature
CHANGED
|
@@ -15,8 +15,8 @@ Feature: Auto-generate a todo file
|
|
|
15
15
|
And it reports:
|
|
16
16
|
"""
|
|
17
17
|
smelly.rb -- 2 warnings:
|
|
18
|
-
[4]:UncommunicativeMethodName: Smelly#x has the name 'x'
|
|
19
|
-
[5]:UncommunicativeVariableName: Smelly#x has the variable name 'y'
|
|
18
|
+
[4]:UncommunicativeMethodName: Smelly#x has the name 'x'
|
|
19
|
+
[5]:UncommunicativeVariableName: Smelly#x has the variable name 'y'
|
|
20
20
|
"""
|
|
21
21
|
When I run reek --todo smelly.rb
|
|
22
22
|
Then it succeeds
|
|
@@ -29,13 +29,14 @@ Feature: Auto-generate a todo file
|
|
|
29
29
|
And the file ".todo.reek" should contain:
|
|
30
30
|
"""
|
|
31
31
|
---
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
detectors:
|
|
33
|
+
UncommunicativeMethodName:
|
|
34
|
+
exclude:
|
|
35
|
+
- Smelly#x
|
|
36
|
+
UncommunicativeVariableName:
|
|
37
|
+
exclude:
|
|
38
|
+
- Smelly#x
|
|
39
|
+
"""
|
|
39
40
|
When I run reek -c .todo.reek smelly.rb
|
|
40
41
|
Then it succeeds
|
|
41
42
|
|
|
@@ -54,20 +55,21 @@ Feature: Auto-generate a todo file
|
|
|
54
55
|
And a file named ".todo.reek" with:
|
|
55
56
|
"""
|
|
56
57
|
---
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
detectors:
|
|
59
|
+
# smelly.rb reeks of UncommunicativeMethodName and UncommunicativeVariableName
|
|
60
|
+
# so the configuration below will partially mask this
|
|
61
|
+
UncommunicativeMethodName:
|
|
62
|
+
enabled: false
|
|
61
63
|
"""
|
|
62
|
-
When I run
|
|
64
|
+
When I run reek -c .todo.reek smelly.rb
|
|
63
65
|
Then it reports:
|
|
64
66
|
"""
|
|
65
67
|
smelly.rb -- 1 warning:
|
|
66
|
-
[5]:UncommunicativeVariableName: Smelly#x has the variable name 'y'
|
|
68
|
+
[5]:UncommunicativeVariableName: Smelly#x has the variable name 'y'
|
|
67
69
|
"""
|
|
68
|
-
When I run
|
|
70
|
+
When I run reek --todo smelly.rb
|
|
69
71
|
Then it succeeds
|
|
70
|
-
When I run
|
|
72
|
+
When I run reek -c .todo.reek smelly.rb
|
|
71
73
|
Then it reports nothing
|
|
72
74
|
|
|
73
75
|
Scenario: Ignore existing other configuration files that are passed explicitly
|
|
@@ -77,16 +79,17 @@ Feature: Auto-generate a todo file
|
|
|
77
79
|
---
|
|
78
80
|
# smelly.rb reeks of UncommunicativeMethodName and UncommunicativeVariableName
|
|
79
81
|
# so the configuration below will partially mask this
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
detectors:
|
|
83
|
+
UncommunicativeMethodName:
|
|
84
|
+
enabled: false
|
|
82
85
|
"""
|
|
83
|
-
When I run
|
|
86
|
+
When I run reek -c config.reek smelly.rb
|
|
84
87
|
Then it reports:
|
|
85
88
|
"""
|
|
86
89
|
smelly.rb -- 1 warning:
|
|
87
|
-
[5]:UncommunicativeVariableName: Smelly#x has the variable name 'y'
|
|
90
|
+
[5]:UncommunicativeVariableName: Smelly#x has the variable name 'y'
|
|
88
91
|
"""
|
|
89
|
-
When I run
|
|
92
|
+
When I run reek -c config.reek --todo smelly.rb
|
|
90
93
|
Then it succeeds
|
|
91
|
-
When I run
|
|
94
|
+
When I run reek -c .todo.reek smelly.rb
|
|
92
95
|
Then it reports nothing
|
data/lib/reek/ast/node.rb
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../cli/silencer'
|
|
4
|
-
|
|
5
|
-
Reek::CLI::Silencer.silently do
|
|
6
|
-
require 'parser'
|
|
7
|
-
end
|
|
4
|
+
Reek::CLI::Silencer.without_warnings { require 'parser' }
|
|
8
5
|
|
|
9
6
|
module Reek
|
|
10
7
|
module AST
|
|
@@ -33,59 +30,47 @@ module Reek
|
|
|
33
30
|
loc && loc.line
|
|
34
31
|
end
|
|
35
32
|
|
|
33
|
+
def name
|
|
34
|
+
to_s
|
|
35
|
+
end
|
|
36
|
+
|
|
36
37
|
#
|
|
37
|
-
# Carries out a depth-first traversal of this syntax tree, yielding
|
|
38
|
-
#
|
|
39
|
-
# whose type is listed in
|
|
40
|
-
# Takes a block as well.
|
|
41
|
-
#
|
|
42
|
-
# target_type - the type to look for, e.g. :send, :block
|
|
43
|
-
# ignoring - types to ignore, e.g. [:casgn, :class, :module]
|
|
44
|
-
# blk - block to execute for every hit. Gets passed in the matching element itself.
|
|
38
|
+
# Carries out a depth-first traversal of this syntax tree, yielding every
|
|
39
|
+
# Sexp of the searched for type or types. The traversal stops at any node
|
|
40
|
+
# whose type is listed in `ignoring`.
|
|
45
41
|
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
# context.each_node(:lvar).any? { |it| it.var_name == 'something' }
|
|
42
|
+
# If a type is searched for *and* listed in ignoring, it will be yielded
|
|
43
|
+
# but traversal will not continue to its children.
|
|
49
44
|
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
def each_node(target_type, ignoring = [], &blk)
|
|
53
|
-
if block_given?
|
|
54
|
-
look_for_type(target_type, ignoring, &blk)
|
|
55
|
-
else
|
|
56
|
-
result = []
|
|
57
|
-
look_for_type(target_type, ignoring) { |exp| result << exp }
|
|
58
|
-
result
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
45
|
+
# If the root's type is ignored, traversal does not stop, unless the root
|
|
46
|
+
# is of a target type.
|
|
62
47
|
#
|
|
63
|
-
# Carries out a depth-first traversal of this syntax tree, yielding
|
|
64
|
-
# every Sexp of type `target_type`. The traversal ignores any node
|
|
65
|
-
# whose type is listed in the Array `ignoring`, including the top node.
|
|
66
48
|
# Takes a block as well.
|
|
67
49
|
#
|
|
68
|
-
# target_types
|
|
69
|
-
#
|
|
70
|
-
#
|
|
50
|
+
# @param target_types [Symbol, Array<Symbol>] the type or types to look
|
|
51
|
+
# for
|
|
52
|
+
# @param ignoring [Array<Symbol>] types to ignore
|
|
53
|
+
# @param blk block to execute for every hit. Gets passed in the
|
|
54
|
+
# matching element itself.
|
|
71
55
|
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
56
|
+
# @example
|
|
57
|
+
# node.each_node(:send, [:mlhs]) do |call_node| .... end
|
|
58
|
+
# node.each_node(:lvar).any? { |it| it.var_name == 'something' }
|
|
59
|
+
# node.each_node([:block]).flat_map do |elem| ... end
|
|
74
60
|
#
|
|
75
61
|
# Returns an array with all matching nodes.
|
|
76
|
-
def
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
62
|
+
def each_node(target_types, ignoring = [], &blk)
|
|
63
|
+
return enum_for(:each_node, target_types, ignoring) unless block_given?
|
|
64
|
+
|
|
65
|
+
look_for(Array(target_types), ignoring, &blk)
|
|
80
66
|
end
|
|
81
67
|
|
|
82
68
|
def contains_nested_node?(target_type)
|
|
83
|
-
|
|
84
|
-
false
|
|
69
|
+
each_node(target_type).any?
|
|
85
70
|
end
|
|
86
71
|
|
|
87
|
-
# :reek:DuplicateMethodCall { max_calls: 2 } is ok for lines.first
|
|
88
|
-
# :reek:FeatureEnvy
|
|
72
|
+
# @quality :reek:DuplicateMethodCall { max_calls: 2 } is ok for lines.first
|
|
73
|
+
# @quality :reek:FeatureEnvy
|
|
89
74
|
def format_to_ruby
|
|
90
75
|
if location
|
|
91
76
|
lines = location.expression.source.split("\n").map(&:strip)
|
|
@@ -120,22 +105,22 @@ module Reek
|
|
|
120
105
|
protected
|
|
121
106
|
|
|
122
107
|
# See ".each_node" for documentation.
|
|
123
|
-
def
|
|
108
|
+
def look_for(target_types, ignoring, &blk)
|
|
109
|
+
if target_types.include? type
|
|
110
|
+
yield self
|
|
111
|
+
return if ignoring.include?(type)
|
|
112
|
+
end
|
|
124
113
|
each_sexp do |elem|
|
|
125
|
-
elem.
|
|
114
|
+
elem.look_for_recurse(target_types, ignoring, &blk)
|
|
126
115
|
end
|
|
127
|
-
yield self if type == target_type
|
|
128
116
|
end
|
|
129
117
|
|
|
130
|
-
# See ".
|
|
131
|
-
def
|
|
132
|
-
|
|
133
|
-
if
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
each_sexp do |elem|
|
|
137
|
-
elem.look_for_types(target_types, ignoring, &blk)
|
|
138
|
-
end
|
|
118
|
+
# See ".each_node" for documentation.
|
|
119
|
+
def look_for_recurse(target_types, ignoring, &blk)
|
|
120
|
+
yield self if target_types.include? type
|
|
121
|
+
return if ignoring.include? type
|
|
122
|
+
each_sexp do |elem|
|
|
123
|
+
elem.look_for_recurse(target_types, ignoring, &blk)
|
|
139
124
|
end
|
|
140
125
|
end
|
|
141
126
|
|
data/lib/reek/ast/object_refs.rb
CHANGED
|
@@ -12,7 +12,7 @@ module Reek
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def num_refs_to_self
|
|
15
|
-
(explicit_self_calls + implicit_self_calls).size
|
|
15
|
+
(explicit_self_calls.to_a + implicit_self_calls.to_a).size
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
private
|
|
@@ -20,9 +20,7 @@ module Reek
|
|
|
20
20
|
attr_reader :ast
|
|
21
21
|
|
|
22
22
|
def explicit_self_calls
|
|
23
|
-
[:self, :super, :zsuper, :ivar, :ivasgn]
|
|
24
|
-
ast.each_node(node_type)
|
|
25
|
-
end
|
|
23
|
+
ast.each_node([:self, :super, :zsuper, :ivar, :ivasgn])
|
|
26
24
|
end
|
|
27
25
|
|
|
28
26
|
def implicit_self_calls
|
|
@@ -9,8 +9,15 @@ module Reek
|
|
|
9
9
|
children.first
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
+
# @quality :reek:FeatureEnvy
|
|
12
13
|
def body_nodes(type, ignoring = [])
|
|
13
|
-
children[1..-1].compact.flat_map
|
|
14
|
+
children[1..-1].compact.flat_map do |child|
|
|
15
|
+
if ignoring.include? child.type
|
|
16
|
+
[]
|
|
17
|
+
else
|
|
18
|
+
child.each_node(type, ignoring).to_a
|
|
19
|
+
end
|
|
20
|
+
end
|
|
14
21
|
end
|
|
15
22
|
end
|
|
16
23
|
end
|
|
@@ -30,11 +30,9 @@ module Reek
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def body_nodes(types, ignoring = [])
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
[]
|
|
37
|
-
end
|
|
33
|
+
return [] unless body
|
|
34
|
+
return [] if ignoring.include?(body.type)
|
|
35
|
+
body.each_node(types, ignoring | types)
|
|
38
36
|
end
|
|
39
37
|
end
|
|
40
38
|
|
|
@@ -59,7 +57,7 @@ module Reek
|
|
|
59
57
|
end
|
|
60
58
|
|
|
61
59
|
def depends_on_instance?
|
|
62
|
-
ReferenceCollector.new(self).num_refs_to_self
|
|
60
|
+
ReferenceCollector.new(self).num_refs_to_self.positive?
|
|
63
61
|
end
|
|
64
62
|
end
|
|
65
63
|
|
data/lib/reek/cli/application.rb
CHANGED
|
@@ -6,6 +6,7 @@ require_relative '../configuration/app_configuration'
|
|
|
6
6
|
require_relative '../source/source_locator'
|
|
7
7
|
require_relative 'command/report_command'
|
|
8
8
|
require_relative 'command/todo_list_command'
|
|
9
|
+
require_relative '../errors/config_file_error'
|
|
9
10
|
|
|
10
11
|
module Reek
|
|
11
12
|
module CLI
|
|
@@ -42,7 +43,7 @@ module Reek
|
|
|
42
43
|
|
|
43
44
|
def configure_app_configuration(config_file)
|
|
44
45
|
Configuration::AppConfiguration.from_path(config_file)
|
|
45
|
-
rescue
|
|
46
|
+
rescue Errors::ConfigFileError => error
|
|
46
47
|
warn "Error: #{error}"
|
|
47
48
|
exit Status::DEFAULT_ERROR_EXIT_CODE
|
|
48
49
|
end
|
|
@@ -68,7 +69,7 @@ module Reek
|
|
|
68
69
|
options.argv
|
|
69
70
|
end
|
|
70
71
|
|
|
71
|
-
# :reek:UtilityFunction
|
|
72
|
+
# @quality :reek:UtilityFunction
|
|
72
73
|
def input_was_piped?
|
|
73
74
|
!$stdin.tty?
|
|
74
75
|
end
|
|
@@ -88,7 +89,7 @@ module Reek
|
|
|
88
89
|
end
|
|
89
90
|
|
|
90
91
|
def source_from_pipe
|
|
91
|
-
[$stdin]
|
|
92
|
+
[Source::SourceCode.from($stdin, origin: options.stdin_filename)]
|
|
92
93
|
end
|
|
93
94
|
|
|
94
95
|
def disable_progress_output_unless_verbose
|
|
@@ -38,7 +38,6 @@ module Reek
|
|
|
38
38
|
@reporter ||=
|
|
39
39
|
report_class.new(
|
|
40
40
|
warning_formatter: warning_formatter,
|
|
41
|
-
report_formatter: Report::Formatter,
|
|
42
41
|
sort_by_issue_count: sort_by_issue_count,
|
|
43
42
|
heading_formatter: heading_formatter,
|
|
44
43
|
progress_formatter: progress_formatter.new(sources.length))
|
|
@@ -53,7 +52,7 @@ module Reek
|
|
|
53
52
|
end
|
|
54
53
|
|
|
55
54
|
def warning_formatter_class
|
|
56
|
-
Report.warning_formatter_class(options.show_links ? :
|
|
55
|
+
Report.warning_formatter_class(options.show_links ? :documentation_links : :simple)
|
|
57
56
|
end
|
|
58
57
|
|
|
59
58
|
def location_formatter
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'base_command'
|
|
4
4
|
require_relative '../../examiner'
|
|
5
|
+
require_relative '../../configuration/app_configuration'
|
|
5
6
|
|
|
6
7
|
module Reek
|
|
7
8
|
module CLI
|
|
@@ -11,15 +12,15 @@ module Reek
|
|
|
11
12
|
# file that can serve as a todo list.
|
|
12
13
|
#
|
|
13
14
|
class TodoListCommand < BaseCommand
|
|
14
|
-
FILE_NAME = '.todo.reek'
|
|
15
|
+
FILE_NAME = '.todo.reek'
|
|
15
16
|
|
|
16
17
|
def execute
|
|
17
|
-
smells = scan_for_smells
|
|
18
18
|
if smells.empty?
|
|
19
19
|
puts "\n'.todo.reek' not generated because "\
|
|
20
20
|
'there were no smells found!'
|
|
21
21
|
else
|
|
22
|
-
File.write FILE_NAME,
|
|
22
|
+
File.write FILE_NAME,
|
|
23
|
+
{ Configuration::AppConfiguration::DETECTORS_KEY => groups }.to_yaml
|
|
23
24
|
puts "\n'.todo.reek' generated! You can now use "\
|
|
24
25
|
'this as a starting point for your configuration.'
|
|
25
26
|
end
|
|
@@ -28,14 +29,13 @@ module Reek
|
|
|
28
29
|
|
|
29
30
|
private
|
|
30
31
|
|
|
31
|
-
def
|
|
32
|
-
sources.map do |source|
|
|
33
|
-
Examiner.new(source,
|
|
34
|
-
filter_by_smells: smell_names)
|
|
32
|
+
def smells
|
|
33
|
+
@smells ||= sources.map do |source|
|
|
34
|
+
Examiner.new(source, filter_by_smells: smell_names)
|
|
35
35
|
end.map(&:smells).flatten
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
def
|
|
38
|
+
def groups
|
|
39
39
|
@groups ||=
|
|
40
40
|
begin
|
|
41
41
|
todos = smells.group_by(&:smell_class).map do |smell_class, smells_for_class|
|
data/lib/reek/cli/options.rb
CHANGED
|
@@ -4,6 +4,8 @@ require 'optparse'
|
|
|
4
4
|
require 'rainbow'
|
|
5
5
|
require_relative '../version'
|
|
6
6
|
require_relative 'status'
|
|
7
|
+
require_relative '../detector_repository'
|
|
8
|
+
require_relative '../documentation_link'
|
|
7
9
|
|
|
8
10
|
module Reek
|
|
9
11
|
module CLI
|
|
@@ -12,9 +14,9 @@ module Reek
|
|
|
12
14
|
#
|
|
13
15
|
# See {file:docs/Command-Line-Options.md} for details.
|
|
14
16
|
#
|
|
15
|
-
# :reek:TooManyInstanceVariables
|
|
16
|
-
# :reek:TooManyMethods
|
|
17
|
-
# :reek:Attribute
|
|
17
|
+
# @quality :reek:TooManyInstanceVariables { max_instance_variables: 12 }
|
|
18
|
+
# @quality :reek:TooManyMethods { max_methods: 18 }
|
|
19
|
+
# @quality :reek:Attribute { enabled: false }
|
|
18
20
|
#
|
|
19
21
|
class Options
|
|
20
22
|
attr_reader :argv, :parser, :smells_to_detect
|
|
@@ -26,6 +28,7 @@ module Reek
|
|
|
26
28
|
:show_empty,
|
|
27
29
|
:show_links,
|
|
28
30
|
:sorting,
|
|
31
|
+
:stdin_filename,
|
|
29
32
|
:success_exit_code,
|
|
30
33
|
:failure_exit_code,
|
|
31
34
|
:generate_todo_list,
|
|
@@ -64,12 +67,12 @@ module Reek
|
|
|
64
67
|
# processing by a machine, but will be viewed by a human. This means
|
|
65
68
|
# features like coloring can be safely enabled by default.
|
|
66
69
|
#
|
|
67
|
-
# :reek:UtilityFunction
|
|
70
|
+
# @quality :reek:UtilityFunction
|
|
68
71
|
def tty_output?
|
|
69
72
|
$stdout.tty?
|
|
70
73
|
end
|
|
71
74
|
|
|
72
|
-
# :reek:TooManyStatements
|
|
75
|
+
# @quality :reek:TooManyStatements { max_statements: 7 }
|
|
73
76
|
def set_up_parser
|
|
74
77
|
set_banner
|
|
75
78
|
set_configuration_options
|
|
@@ -91,12 +94,12 @@ module Reek
|
|
|
91
94
|
#{program_name} -s lib
|
|
92
95
|
cat my_class.rb | #{program_name}
|
|
93
96
|
|
|
94
|
-
See https://
|
|
97
|
+
See https://github.com/troessner/reek for detailed help.
|
|
95
98
|
|
|
96
99
|
BANNER
|
|
97
100
|
end
|
|
98
101
|
|
|
99
|
-
# :reek:TooManyStatements
|
|
102
|
+
# @quality :reek:TooManyStatements { max_statements: 7 }
|
|
100
103
|
def set_configuration_options
|
|
101
104
|
parser.separator 'Configuration:'
|
|
102
105
|
parser.on('-c', '--config FILE', 'Read configuration options from FILE') do |file|
|
|
@@ -104,11 +107,16 @@ module Reek
|
|
|
104
107
|
end
|
|
105
108
|
parser.on('--smell SMELL',
|
|
106
109
|
'Only look for a specific smell.',
|
|
107
|
-
'Call it like this: reek --smell
|
|
108
|
-
|
|
110
|
+
'Call it like this: reek --smell MissingSafeMethod source.rb',
|
|
111
|
+
"Check out #{DocumentationLink.build('Code Smells')} "\
|
|
109
112
|
'for a list of smells') do |smell|
|
|
110
113
|
smells_to_detect << smell
|
|
111
114
|
end
|
|
115
|
+
parser.on('--stdin-filename FILE',
|
|
116
|
+
'When passing code in via pipe, assume this filename when '\
|
|
117
|
+
'checking file or directory rules in the config.') do |file|
|
|
118
|
+
self.stdin_filename = file
|
|
119
|
+
end
|
|
112
120
|
end
|
|
113
121
|
|
|
114
122
|
def set_generate_todo_list_options
|
|
@@ -128,7 +136,7 @@ module Reek
|
|
|
128
136
|
end
|
|
129
137
|
end
|
|
130
138
|
|
|
131
|
-
# :reek:TooManyStatements
|
|
139
|
+
# @quality :reek:TooManyStatements { max_statements: 7 }
|
|
132
140
|
def set_report_formatting_options
|
|
133
141
|
parser.separator "\nText format options:"
|
|
134
142
|
set_up_color_option
|
|
@@ -150,8 +158,8 @@ module Reek
|
|
|
150
158
|
'Show headings for smell-free source files (default: false)') do |show_empty|
|
|
151
159
|
self.show_empty = show_empty
|
|
152
160
|
end
|
|
153
|
-
parser.on('-U', '--[no-]
|
|
154
|
-
'Show link to related
|
|
161
|
+
parser.on('-U', '--[no-]documentation',
|
|
162
|
+
'Show link to related documentation page for each smell (default: true)') do |show_links|
|
|
155
163
|
self.show_links = show_links
|
|
156
164
|
end
|
|
157
165
|
end
|
|
@@ -191,7 +199,7 @@ module Reek
|
|
|
191
199
|
end
|
|
192
200
|
end
|
|
193
201
|
|
|
194
|
-
# :reek:DuplicateMethodCall
|
|
202
|
+
# @quality :reek:DuplicateMethodCall { max_calls: 2 }
|
|
195
203
|
def set_exit_codes
|
|
196
204
|
parser.separator "\nExit codes:"
|
|
197
205
|
parser.on('--success-exit-code CODE',
|
|
@@ -206,13 +214,20 @@ module Reek
|
|
|
206
214
|
end
|
|
207
215
|
end
|
|
208
216
|
|
|
209
|
-
# :reek:TooManyStatements
|
|
217
|
+
# @quality :reek:TooManyStatements { max_statements: 12 }
|
|
210
218
|
def set_utility_options
|
|
211
219
|
parser.separator "\nUtility options:"
|
|
212
220
|
parser.on_tail('-h', '--help', 'Show this message') do
|
|
213
221
|
puts parser
|
|
214
222
|
exit
|
|
215
223
|
end
|
|
224
|
+
parser.on_tail('-l', '--list', 'List all available smell detectors') do
|
|
225
|
+
puts "All available smell detectors:\n\n"
|
|
226
|
+
puts DetectorRepository.available_detector_names
|
|
227
|
+
puts "\nCheck out #{DocumentationLink.build('Code Smells')} "\
|
|
228
|
+
'for a details on each detector'
|
|
229
|
+
exit
|
|
230
|
+
end
|
|
216
231
|
parser.on_tail('-v', '--version', 'Show version') do
|
|
217
232
|
puts "#{parser.program_name} #{Reek::Version::STRING}\n"
|
|
218
233
|
exit
|
data/lib/reek/cli/silencer.rb
CHANGED
|
@@ -8,17 +8,28 @@ module Reek
|
|
|
8
8
|
module Silencer
|
|
9
9
|
module_function
|
|
10
10
|
|
|
11
|
-
# :reek:TooManyStatements
|
|
11
|
+
# @quality :reek:TooManyStatements { max_statements: 9 }
|
|
12
12
|
def silently
|
|
13
13
|
old_verbose = $VERBOSE
|
|
14
|
+
old_stderr = $stderr
|
|
15
|
+
old_stdout = $stdout
|
|
16
|
+
|
|
14
17
|
$VERBOSE = false
|
|
15
18
|
$stderr = StringIO.new
|
|
16
19
|
$stdout = StringIO.new
|
|
17
20
|
yield
|
|
18
21
|
ensure
|
|
19
22
|
$VERBOSE = old_verbose
|
|
20
|
-
$stderr =
|
|
21
|
-
$stdout =
|
|
23
|
+
$stderr = old_stderr
|
|
24
|
+
$stdout = old_stdout
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def without_warnings
|
|
28
|
+
old_verbose = $VERBOSE
|
|
29
|
+
$VERBOSE = false
|
|
30
|
+
yield
|
|
31
|
+
ensure
|
|
32
|
+
$VERBOSE = old_verbose
|
|
22
33
|
end
|
|
23
34
|
end
|
|
24
35
|
end
|