reek 4.6.0 → 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 +79 -26
- data/.simplecov +1 -0
- data/.travis.yml +3 -9
- data/.yardopts +1 -1
- data/CHANGELOG.md +76 -0
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +5 -5
- data/README.md +138 -107
- data/Rakefile +16 -3
- data/bin/code_climate_reek +1 -0
- data/bin/reek +2 -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 +7 -7
- 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 +3 -3
- 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 +31 -5
- data/features/configuration_files/accept_setting.feature +45 -28
- data/features/configuration_files/directory_specific_directives.feature +80 -75
- 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 +3 -3
- data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
- data/features/locales.feature +32 -0
- data/features/rake_task/rake_task.feature +58 -18
- data/features/reports/codeclimate.feature +59 -0
- 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 +40 -0
- data/features/samples.feature +287 -287
- data/features/step_definitions/reek_steps.rb +14 -2
- data/features/step_definitions/sample_file_steps.rb +9 -4
- data/features/support/env.rb +2 -11
- data/features/todo_list.feature +26 -23
- data/lib/reek/ast/ast_node_class_map.rb +1 -0
- data/lib/reek/ast/builder.rb +16 -0
- data/lib/reek/ast/node.rb +50 -58
- data/lib/reek/ast/object_refs.rb +2 -1
- data/lib/reek/ast/reference_collector.rb +3 -4
- data/lib/reek/ast/sexp_extensions/arguments.rb +1 -0
- data/lib/reek/ast/sexp_extensions/attribute_assignments.rb +1 -0
- data/lib/reek/ast/sexp_extensions/begin.rb +17 -0
- data/lib/reek/ast/sexp_extensions/block.rb +1 -0
- data/lib/reek/ast/sexp_extensions/case.rb +2 -1
- data/lib/reek/ast/sexp_extensions/constant.rb +1 -0
- data/lib/reek/ast/sexp_extensions/if.rb +9 -1
- data/lib/reek/ast/sexp_extensions/lambda.rb +1 -0
- data/lib/reek/ast/sexp_extensions/literal.rb +1 -0
- data/lib/reek/ast/sexp_extensions/logical_operators.rb +2 -1
- data/lib/reek/ast/sexp_extensions/methods.rb +5 -6
- data/lib/reek/ast/sexp_extensions/module.rb +55 -8
- data/lib/reek/ast/sexp_extensions/nested_assignables.rb +1 -0
- data/lib/reek/ast/sexp_extensions/self.rb +1 -0
- data/lib/reek/ast/sexp_extensions/send.rb +1 -4
- data/lib/reek/ast/sexp_extensions/super.rb +1 -0
- data/lib/reek/ast/sexp_extensions/symbols.rb +1 -0
- data/lib/reek/ast/sexp_extensions/variables.rb +1 -0
- data/lib/reek/ast/sexp_extensions/when.rb +1 -0
- data/lib/reek/ast/sexp_extensions/yield.rb +1 -0
- data/lib/reek/ast/sexp_extensions.rb +2 -0
- data/lib/reek/cli/application.rb +5 -3
- data/lib/reek/cli/command/base_command.rb +1 -0
- data/lib/reek/cli/command/report_command.rb +2 -2
- data/lib/reek/cli/command/todo_list_command.rb +9 -8
- data/lib/reek/cli/options.rb +32 -16
- data/lib/reek/cli/silencer.rb +15 -3
- data/lib/reek/cli/status.rb +1 -0
- data/lib/reek/code_comment.rb +14 -16
- data/lib/reek/configuration/app_configuration.rb +34 -28
- data/lib/reek/configuration/configuration_converter.rb +110 -0
- data/lib/reek/configuration/configuration_file_finder.rb +17 -41
- data/lib/reek/configuration/configuration_validator.rb +13 -23
- data/lib/reek/configuration/default_directive.rb +18 -3
- data/lib/reek/configuration/directory_directives.rb +18 -11
- data/lib/reek/configuration/excluded_paths.rb +2 -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 +4 -3
- data/lib/reek/context/class_context.rb +1 -0
- data/lib/reek/context/code_context.rb +49 -44
- data/lib/reek/context/ghost_context.rb +1 -2
- data/lib/reek/context/method_context.rb +26 -18
- data/lib/reek/context/module_context.rb +11 -11
- data/lib/reek/context/root_context.rb +1 -4
- data/lib/reek/context/send_context.rb +3 -2
- data/lib/reek/context/singleton_attribute_context.rb +1 -0
- data/lib/reek/context/singleton_method_context.rb +1 -0
- data/lib/reek/context/statement_counter.rb +1 -0
- data/lib/reek/context/visibility_tracker.rb +1 -0
- data/lib/reek/context_builder.rb +44 -44
- data/lib/reek/detector_repository.rb +12 -11
- data/lib/reek/documentation_link.rb +28 -0
- data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +15 -13
- data/lib/reek/errors/bad_detector_in_comment_error.rb +13 -11
- 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 +43 -0
- data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +14 -12
- data/lib/reek/errors/incomprehensible_source_error.rb +23 -24
- data/lib/reek/errors/syntax_error.rb +41 -0
- data/lib/reek/examiner.rb +24 -22
- data/lib/reek/logging_error_handler.rb +8 -5
- data/lib/reek/rake/task.rb +8 -5
- data/lib/reek/report/base_report.rb +9 -12
- data/lib/reek/report/code_climate/code_climate_configuration.rb +2 -1
- data/lib/reek/report/code_climate/code_climate_configuration.yml +6 -6
- data/lib/reek/report/code_climate/code_climate_fingerprint.rb +1 -0
- data/lib/reek/report/code_climate/code_climate_formatter.rb +1 -0
- data/lib/reek/report/code_climate/code_climate_report.rb +1 -0
- data/lib/reek/report/code_climate.rb +1 -0
- data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
- data/lib/reek/report/heading_formatter.rb +54 -0
- data/lib/reek/report/html_report.rb +1 -0
- data/lib/reek/report/json_report.rb +2 -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 +2 -2
- data/lib/reek/report/xml_report.rb +4 -3
- data/lib/reek/report/yaml_report.rb +2 -1
- data/lib/reek/report.rb +16 -10
- data/lib/reek/smell_configuration.rb +3 -2
- data/lib/reek/smell_detectors/attribute.rb +6 -11
- data/lib/reek/smell_detectors/base_detector.rb +31 -26
- data/lib/reek/smell_detectors/boolean_parameter.rb +4 -5
- data/lib/reek/smell_detectors/class_variable.rb +6 -14
- data/lib/reek/smell_detectors/control_parameter.rb +19 -33
- data/lib/reek/smell_detectors/data_clump.rb +16 -9
- data/lib/reek/smell_detectors/duplicate_method_call.rb +24 -17
- data/lib/reek/smell_detectors/feature_envy.rb +10 -7
- data/lib/reek/smell_detectors/instance_variable_assumption.rb +15 -23
- data/lib/reek/smell_detectors/irresponsible_module.rb +6 -12
- data/lib/reek/smell_detectors/long_parameter_list.rb +11 -7
- data/lib/reek/smell_detectors/long_yield_list.rb +11 -7
- data/lib/reek/smell_detectors/manual_dispatch.rb +5 -5
- data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +21 -20
- data/lib/reek/smell_detectors/module_initialize.rb +4 -5
- data/lib/reek/smell_detectors/nested_iterators.rb +17 -24
- data/lib/reek/smell_detectors/nil_check.rb +9 -15
- data/lib/reek/smell_detectors/repeated_conditional.rb +14 -11
- data/lib/reek/smell_detectors/subclassed_from_core_class.rb +8 -8
- data/lib/reek/smell_detectors/too_many_constants.rb +11 -9
- data/lib/reek/smell_detectors/too_many_instance_variables.rb +11 -6
- data/lib/reek/smell_detectors/too_many_methods.rb +12 -7
- data/lib/reek/smell_detectors/too_many_statements.rb +11 -6
- data/lib/reek/smell_detectors/uncommunicative_method_name.rb +11 -11
- data/lib/reek/smell_detectors/uncommunicative_module_name.rb +15 -18
- data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +18 -22
- data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +27 -27
- data/lib/reek/smell_detectors/unused_parameters.rb +5 -6
- data/lib/reek/smell_detectors/unused_private_method.rb +14 -20
- data/lib/reek/smell_detectors/utility_function.rb +13 -16
- data/lib/reek/smell_detectors.rb +2 -1
- data/lib/reek/smell_warning.rb +16 -8
- data/lib/reek/source/source_code.rb +65 -46
- data/lib/reek/source/source_locator.rb +9 -8
- data/lib/reek/spec/should_reek.rb +3 -2
- data/lib/reek/spec/should_reek_of.rb +13 -26
- data/lib/reek/spec/should_reek_only_of.rb +5 -4
- data/lib/reek/spec/smell_matcher.rb +2 -1
- data/lib/reek/spec.rb +7 -6
- data/lib/reek/tree_dresser.rb +9 -8
- data/lib/reek/version.rb +2 -1
- data/lib/reek.rb +1 -0
- data/reek.gemspec +5 -6
- 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 +15 -34
- data/spec/reek/cli/application_spec.rb +52 -42
- 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 -51
- 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 +70 -106
- data/spec/reek/context/ghost_context_spec.rb +9 -9
- data/spec/reek/context/method_context_spec.rb +2 -2
- data/spec/reek/context/module_context_spec.rb +3 -3
- data/spec/reek/context/root_context_spec.rb +1 -1
- data/spec/reek/context/statement_counter_spec.rb +1 -0
- data/spec/reek/context_builder_spec.rb +20 -0
- 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 +137 -29
- data/spec/reek/rake/task_spec.rb +25 -2
- data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +82 -78
- data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
- data/spec/reek/report/code_climate/code_climate_report_spec.rb +22 -22
- 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 +17 -46
- data/spec/reek/report_spec.rb +3 -3
- data/spec/reek/smell_detectors/base_detector_spec.rb +4 -5
- 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/irresponsible_module_spec.rb +59 -21
- data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +10 -10
- 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 +36 -15
- 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 +21 -10
- data/spec/reek/smell_detectors/utility_function_spec.rb +57 -5
- data/spec/reek/smell_warning_spec.rb +12 -8
- data/spec/reek/source/source_code_spec.rb +27 -38
- data/spec/reek/source/source_locator_spec.rb +42 -12
- data/spec/reek/spec/should_reek_of_spec.rb +25 -30
- data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
- data/spec/reek/spec/should_reek_spec.rb +8 -8
- data/spec/reek/spec/smell_matcher_spec.rb +23 -23
- data/spec/reek/tree_dresser_spec.rb +12 -17
- data/spec/spec_helper.rb +7 -17
- data/tasks/configuration.rake +8 -5
- metadata +77 -40
- data/defaults.reek +0 -128
- data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
- data/lib/reek/errors/parse_error.rb +0 -19
- data/lib/reek/report/formatter/heading_formatter.rb +0 -51
- data/lib/reek/report/formatter/location_formatter.rb +0 -41
- data/lib/reek/report/formatter/progress_formatter.rb +0 -80
- data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
- data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -35
- data/lib/reek/report/formatter.rb +0 -32
- 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/{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,8 +6,8 @@ When /^I pass "([^\"]*)" to reek *(.*)$/ do |stdin, args|
|
|
|
6
6
|
reek_with_pipe(stdin, args)
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
When /^I
|
|
10
|
-
|
|
9
|
+
When /^I pass a stdin to reek *(.*) with:$/ do |args, stdin|
|
|
10
|
+
reek_with_pipe(stdin, args)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
Then /^it reports nothing$/ do
|
|
@@ -84,3 +84,15 @@ end
|
|
|
84
84
|
Then /^it reports the current version$/ do
|
|
85
85
|
expect(last_command_started).to have_output("reek #{Reek::Version::STRING}")
|
|
86
86
|
end
|
|
87
|
+
|
|
88
|
+
Then /^it reports this Code Climate output:$/ do |expected_output|
|
|
89
|
+
expected_issues = expected_output.split('NULL_BYTE_CHARACTER').map do |issue|
|
|
90
|
+
JSON.parse(issue)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
actual_issues = last_command_started.stdout.split("\0").map do |issue|
|
|
94
|
+
JSON.parse(issue)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
expect(actual_issues).to eq(expected_issues)
|
|
98
|
+
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,23 +13,14 @@ 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
|
|
24
|
-
|
|
25
|
-
def rake(name, task_def)
|
|
26
|
-
header = <<-EOS.strip_heredoc
|
|
27
|
-
require 'reek/rake/task'
|
|
28
|
-
|
|
29
|
-
EOS
|
|
30
|
-
write_file 'Rakefile', header + task_def
|
|
31
|
-
run_simple("rake #{name}", false)
|
|
32
|
-
end
|
|
33
24
|
end
|
|
34
25
|
|
|
35
26
|
World do
|
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
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Reek
|
|
4
|
+
module AST
|
|
5
|
+
#
|
|
6
|
+
# An AST Builder for ruby parser.
|
|
7
|
+
#
|
|
8
|
+
class Builder < ::Parser::Builders::Default
|
|
9
|
+
# This is a work around for parsing ruby code that has a string with invalid sequence as UTF-8.
|
|
10
|
+
# See. https://github.com/whitequark/parser/issues/283
|
|
11
|
+
def string_value(token)
|
|
12
|
+
value(token)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/reek/ast/node.rb
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require_relative '../cli/silencer'
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
end
|
|
3
|
+
require_relative '../cli/silencer'
|
|
4
|
+
Reek::CLI::Silencer.without_warnings { require 'parser' }
|
|
7
5
|
|
|
8
6
|
module Reek
|
|
9
7
|
module AST
|
|
@@ -11,11 +9,8 @@ module Reek
|
|
|
11
9
|
# methods to ease the transition from Sexp to AST::Node.
|
|
12
10
|
#
|
|
13
11
|
class Node < ::Parser::AST::Node
|
|
14
|
-
attr_reader :parent
|
|
15
|
-
|
|
16
12
|
def initialize(type, children = [], options = {})
|
|
17
13
|
@comments = options.fetch(:comments, [])
|
|
18
|
-
@parent = options.fetch(:parent, nil)
|
|
19
14
|
super
|
|
20
15
|
end
|
|
21
16
|
|
|
@@ -35,59 +30,47 @@ module Reek
|
|
|
35
30
|
loc && loc.line
|
|
36
31
|
end
|
|
37
32
|
|
|
33
|
+
def name
|
|
34
|
+
to_s
|
|
35
|
+
end
|
|
36
|
+
|
|
38
37
|
#
|
|
39
|
-
# Carries out a depth-first traversal of this syntax tree, yielding
|
|
40
|
-
#
|
|
41
|
-
# whose type is listed in
|
|
42
|
-
# Takes a block as well.
|
|
43
|
-
#
|
|
44
|
-
# target_type - the type to look for, e.g. :send, :block
|
|
45
|
-
# ignoring - types to ignore, e.g. [:casgn, :class, :module]
|
|
46
|
-
# 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`.
|
|
47
41
|
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
# 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.
|
|
51
44
|
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
def each_node(target_type, ignoring = [], &blk)
|
|
55
|
-
if block_given?
|
|
56
|
-
look_for_type(target_type, ignoring, &blk)
|
|
57
|
-
else
|
|
58
|
-
result = []
|
|
59
|
-
look_for_type(target_type, ignoring) { |exp| result << exp }
|
|
60
|
-
result
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
45
|
+
# If the root's type is ignored, traversal does not stop, unless the root
|
|
46
|
+
# is of a target type.
|
|
64
47
|
#
|
|
65
|
-
# Carries out a depth-first traversal of this syntax tree, yielding
|
|
66
|
-
# every Sexp of type `target_type`. The traversal ignores any node
|
|
67
|
-
# whose type is listed in the Array `ignoring`, including the top node.
|
|
68
48
|
# Takes a block as well.
|
|
69
49
|
#
|
|
70
|
-
# target_types
|
|
71
|
-
#
|
|
72
|
-
#
|
|
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.
|
|
73
55
|
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
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
|
|
76
60
|
#
|
|
77
61
|
# Returns an array with all matching nodes.
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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)
|
|
82
66
|
end
|
|
83
67
|
|
|
84
68
|
def contains_nested_node?(target_type)
|
|
85
|
-
|
|
86
|
-
false
|
|
69
|
+
each_node(target_type).any?
|
|
87
70
|
end
|
|
88
71
|
|
|
89
|
-
# :reek:DuplicateMethodCall { max_calls: 2 } is ok for lines.first
|
|
90
|
-
# :reek:FeatureEnvy
|
|
72
|
+
# @quality :reek:DuplicateMethodCall { max_calls: 2 } is ok for lines.first
|
|
73
|
+
# @quality :reek:FeatureEnvy
|
|
91
74
|
def format_to_ruby
|
|
92
75
|
if location
|
|
93
76
|
lines = location.expression.source.split("\n").map(&:strip)
|
|
@@ -106,6 +89,15 @@ module Reek
|
|
|
106
89
|
1
|
|
107
90
|
end
|
|
108
91
|
|
|
92
|
+
# Most nodes represent only one statement (although they can have nested
|
|
93
|
+
# statements). The special type :begin exists primarily to contain more
|
|
94
|
+
# statements.
|
|
95
|
+
#
|
|
96
|
+
# @return Array of unique outer-level statements contained in this node
|
|
97
|
+
def statements
|
|
98
|
+
[self]
|
|
99
|
+
end
|
|
100
|
+
|
|
109
101
|
def source
|
|
110
102
|
loc.expression.source_buffer.name
|
|
111
103
|
end
|
|
@@ -113,22 +105,22 @@ module Reek
|
|
|
113
105
|
protected
|
|
114
106
|
|
|
115
107
|
# See ".each_node" for documentation.
|
|
116
|
-
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
|
|
117
113
|
each_sexp do |elem|
|
|
118
|
-
elem.
|
|
114
|
+
elem.look_for_recurse(target_types, ignoring, &blk)
|
|
119
115
|
end
|
|
120
|
-
yield self if type == target_type
|
|
121
116
|
end
|
|
122
117
|
|
|
123
|
-
# See ".
|
|
124
|
-
def
|
|
125
|
-
|
|
126
|
-
if
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
each_sexp do |elem|
|
|
130
|
-
elem.look_for_types(target_types, ignoring, &blk)
|
|
131
|
-
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)
|
|
132
124
|
end
|
|
133
125
|
end
|
|
134
126
|
|
data/lib/reek/ast/object_refs.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Reek
|
|
3
4
|
# Represents functionality related to an Abstract Syntax Tree.
|
|
4
5
|
module AST
|
|
@@ -49,7 +50,7 @@ module Reek
|
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
def self_is_max?
|
|
52
|
-
refs.empty? || most_popular.
|
|
53
|
+
refs.empty? || most_popular.key?(:self)
|
|
53
54
|
end
|
|
54
55
|
|
|
55
56
|
private
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Reek
|
|
3
4
|
module AST
|
|
4
5
|
#
|
|
@@ -11,7 +12,7 @@ module Reek
|
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def num_refs_to_self
|
|
14
|
-
(explicit_self_calls + implicit_self_calls).size
|
|
15
|
+
(explicit_self_calls.to_a + implicit_self_calls.to_a).size
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
private
|
|
@@ -19,9 +20,7 @@ module Reek
|
|
|
19
20
|
attr_reader :ast
|
|
20
21
|
|
|
21
22
|
def explicit_self_calls
|
|
22
|
-
[:self, :super, :zsuper, :ivar, :ivasgn]
|
|
23
|
-
ast.each_node(node_type)
|
|
24
|
-
end
|
|
23
|
+
ast.each_node([:self, :super, :zsuper, :ivar, :ivasgn])
|
|
25
24
|
end
|
|
26
25
|
|
|
27
26
|
def implicit_self_calls
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Reek
|
|
4
|
+
module AST
|
|
5
|
+
module SexpExtensions
|
|
6
|
+
# Utility methods for :begin nodes.
|
|
7
|
+
module BeginNode
|
|
8
|
+
# The special type :begin exists primarily to contain more statements.
|
|
9
|
+
# Therefore, this method overrides the default implementation to return
|
|
10
|
+
# this node's children.
|
|
11
|
+
def statements
|
|
12
|
+
children
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Reek
|
|
3
4
|
module AST
|
|
4
5
|
module SexpExtensions
|
|
@@ -9,7 +10,7 @@ module Reek
|
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def body_nodes(type, ignoring = [])
|
|
12
|
-
children[1..-1].compact.flat_map { |child| child.
|
|
13
|
+
children[1..-1].compact.flat_map { |child| child.each_node(type, ignoring).to_a }
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def else_body
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Reek
|
|
3
4
|
module AST
|
|
4
5
|
module SexpExtensions
|
|
@@ -8,8 +9,15 @@ module Reek
|
|
|
8
9
|
children.first
|
|
9
10
|
end
|
|
10
11
|
|
|
12
|
+
# @quality :reek:FeatureEnvy
|
|
11
13
|
def body_nodes(type, ignoring = [])
|
|
12
|
-
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
|
|
13
21
|
end
|
|
14
22
|
end
|
|
15
23
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Reek
|
|
3
4
|
module AST
|
|
4
5
|
module SexpExtensions
|
|
@@ -9,7 +10,7 @@ module Reek
|
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def body_nodes(type, ignoring = [])
|
|
12
|
-
children[1].
|
|
13
|
+
children[1].each_node type, ignoring
|
|
13
14
|
end
|
|
14
15
|
end
|
|
15
16
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Reek
|
|
3
4
|
module AST
|
|
4
5
|
module SexpExtensions
|
|
@@ -29,11 +30,9 @@ module Reek
|
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
def body_nodes(types, ignoring = [])
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
[]
|
|
36
|
-
end
|
|
33
|
+
return [] unless body
|
|
34
|
+
return [] if ignoring.include?(body.type)
|
|
35
|
+
body.each_node(types, ignoring | types)
|
|
37
36
|
end
|
|
38
37
|
end
|
|
39
38
|
|
|
@@ -58,7 +57,7 @@ module Reek
|
|
|
58
57
|
end
|
|
59
58
|
|
|
60
59
|
def depends_on_instance?
|
|
61
|
-
ReferenceCollector.new(self).num_refs_to_self
|
|
60
|
+
ReferenceCollector.new(self).num_refs_to_self.positive?
|
|
62
61
|
end
|
|
63
62
|
end
|
|
64
63
|
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Reek
|
|
3
4
|
module AST
|
|
4
5
|
module SexpExtensions
|
|
5
|
-
# Base module for utility methods for module
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
# Base module for utility methods for nodes that define constants: module
|
|
7
|
+
# definition, class definition and constant assignment.
|
|
8
|
+
module ConstantDefiningNodeBase
|
|
9
|
+
# The full name of the constant, including the name of any
|
|
8
10
|
# module or class it is nested inside of.
|
|
9
11
|
#
|
|
10
12
|
# For example, given code like this:
|
|
@@ -15,7 +17,8 @@ module Reek
|
|
|
15
17
|
# end
|
|
16
18
|
#
|
|
17
19
|
# The full name for the inner class will be 'Foo::Bar::Baz'. To return
|
|
18
|
-
# the correct name, the name of the outer context has to be passed into
|
|
20
|
+
# the correct name, the name of the outer context has to be passed into
|
|
21
|
+
# this method.
|
|
19
22
|
#
|
|
20
23
|
# @param outer [String] full name of the wrapping module or class
|
|
21
24
|
# @return the module's full name
|
|
@@ -31,27 +34,71 @@ module Reek
|
|
|
31
34
|
def simple_name
|
|
32
35
|
name.split('::').last
|
|
33
36
|
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Base module for utility methods for module nodes.
|
|
40
|
+
module ModuleNodeBase
|
|
41
|
+
include ConstantDefiningNodeBase
|
|
34
42
|
|
|
35
43
|
def name
|
|
36
44
|
children.first.format_to_ruby
|
|
37
45
|
end
|
|
46
|
+
|
|
47
|
+
# In the AST, the set of children of a module that a human might identify
|
|
48
|
+
# is coded in three different ways.
|
|
49
|
+
#
|
|
50
|
+
# If there are no children, the last element of the module node is nil,
|
|
51
|
+
# like so:
|
|
52
|
+
#
|
|
53
|
+
# s(:class,
|
|
54
|
+
# s(:const, nil, :C),
|
|
55
|
+
# nil,
|
|
56
|
+
# nil)
|
|
57
|
+
#
|
|
58
|
+
# If there is one child, the last element of the module node is that
|
|
59
|
+
# child, like so:
|
|
60
|
+
#
|
|
61
|
+
# s(:class,
|
|
62
|
+
# s(:const, nil, :C),
|
|
63
|
+
# nil,
|
|
64
|
+
# s(:def, :f, s(:args), nil))
|
|
65
|
+
#
|
|
66
|
+
# If there is more than one child, those are wrapped as children in a
|
|
67
|
+
# node of type :begin, like so:
|
|
68
|
+
#
|
|
69
|
+
# s(:class,
|
|
70
|
+
# s(:const, nil, :Alfa),
|
|
71
|
+
# nil,
|
|
72
|
+
# s(:begin,
|
|
73
|
+
# s(:def, :bravo, s(:args), nil),
|
|
74
|
+
# s(:class, s(:const, nil, :Charlie), nil, nil)))
|
|
75
|
+
#
|
|
76
|
+
# This method unifies those three ways to avoid having to handle them
|
|
77
|
+
# differently.
|
|
78
|
+
#
|
|
79
|
+
# @return an array of directly visible children of the module
|
|
80
|
+
#
|
|
81
|
+
def direct_children
|
|
82
|
+
contents = children.last or return []
|
|
83
|
+
contents.statements
|
|
84
|
+
end
|
|
38
85
|
end
|
|
39
86
|
|
|
40
|
-
# Utility methods for :module nodes.
|
|
87
|
+
# Utility methods for module definition (:module) nodes.
|
|
41
88
|
module ModuleNode
|
|
42
89
|
include ModuleNodeBase
|
|
43
90
|
end
|
|
44
91
|
|
|
45
|
-
# Utility methods for :class nodes.
|
|
92
|
+
# Utility methods for class definition (:class) nodes.
|
|
46
93
|
module ClassNode
|
|
47
94
|
include ModuleNodeBase
|
|
48
95
|
|
|
49
96
|
def superclass() children[1] end
|
|
50
97
|
end
|
|
51
98
|
|
|
52
|
-
# Utility methods for :casgn nodes.
|
|
99
|
+
# Utility methods for constant assignment (:casgn) nodes.
|
|
53
100
|
module CasgnNode
|
|
54
|
-
include
|
|
101
|
+
include ConstantDefiningNodeBase
|
|
55
102
|
|
|
56
103
|
def defines_module?
|
|
57
104
|
call = constant_definition
|