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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require_relative 'smell_detectors'
|
|
3
4
|
require_relative 'smell_detectors/base_detector'
|
|
4
5
|
require_relative 'configuration/app_configuration'
|
|
@@ -34,31 +35,31 @@ module Reek
|
|
|
34
35
|
configuration: {})
|
|
35
36
|
@configuration = configuration
|
|
36
37
|
@smell_types = smell_types
|
|
37
|
-
@detectors = smell_types.map { |klass| klass.new configuration_for(klass) }
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def examine(context)
|
|
41
|
-
smell_detectors_for(context.type).flat_map do |
|
|
42
|
-
detector.
|
|
41
|
+
smell_detectors_for(context.type).flat_map do |klass|
|
|
42
|
+
detector = klass.new configuration: configuration_for(klass), context: context
|
|
43
|
+
detector.run
|
|
43
44
|
end
|
|
44
45
|
end
|
|
45
46
|
|
|
47
|
+
# @return [Array<String>] The names of all known SmellDetectors
|
|
48
|
+
# e.g. ["BooleanParameter", "ClassVariable"].
|
|
49
|
+
def self.available_detector_names
|
|
50
|
+
smell_types.map(&:smell_type)
|
|
51
|
+
end
|
|
52
|
+
|
|
46
53
|
private
|
|
47
54
|
|
|
48
|
-
attr_reader :configuration, :smell_types
|
|
55
|
+
attr_reader :configuration, :smell_types
|
|
49
56
|
|
|
50
57
|
def configuration_for(klass)
|
|
51
58
|
configuration.fetch klass, {}
|
|
52
59
|
end
|
|
53
60
|
|
|
54
61
|
def smell_detectors_for(type)
|
|
55
|
-
|
|
56
|
-
detector.contexts.include? type
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def enabled_detectors
|
|
61
|
-
detectors.select { |detector| detector.config.enabled? }
|
|
62
|
+
smell_types.select { |detector| detector.contexts.include? type }
|
|
62
63
|
end
|
|
63
64
|
end
|
|
64
65
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Reek
|
|
4
|
+
# Generate versioned links to our documentation
|
|
5
|
+
module DocumentationLink
|
|
6
|
+
HELP_LINK_TEMPLATE = 'https://github.com/troessner/reek/blob/v%<version>s/docs/%<item>s.md'
|
|
7
|
+
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
# Build link to the documentation about the given subject for the current
|
|
11
|
+
# version of Reek. The subject can be either a smell type like
|
|
12
|
+
# 'FeatureEnvy' or a general subject like 'Rake Task'.
|
|
13
|
+
#
|
|
14
|
+
# @param subject [String]
|
|
15
|
+
# @return [String] the full URL for the relevant documentation
|
|
16
|
+
def build(subject)
|
|
17
|
+
Kernel.format(HELP_LINK_TEMPLATE, version: Version::STRING, item: name_to_param(subject))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Convert the given subject name to a form that is acceptable in a URL.
|
|
21
|
+
def name_to_param(name)
|
|
22
|
+
# Splits the subject on the start of capitalized words, optionally
|
|
23
|
+
# preceded by a space. The space is discarded, the start of the word is
|
|
24
|
+
# not.
|
|
25
|
+
name.split(/ *(?=[A-Z][a-z])/).join('-')
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -1,35 +1,37 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require_relative 'base_error'
|
|
4
|
+
require_relative '../documentation_link'
|
|
3
5
|
|
|
4
6
|
module Reek
|
|
5
7
|
module Errors
|
|
6
8
|
# Gets raised when trying to configure a detector with an option
|
|
7
9
|
# which is unknown to it.
|
|
8
10
|
class BadDetectorConfigurationKeyInCommentError < BaseError
|
|
9
|
-
UNKNOWN_SMELL_DETECTOR_MESSAGE = <<-
|
|
11
|
+
UNKNOWN_SMELL_DETECTOR_MESSAGE = <<-MESSAGE
|
|
10
12
|
|
|
11
|
-
Error: You are trying to configure the smell detector '
|
|
12
|
-
in one of your source code comments with the unknown option
|
|
13
|
-
The source is '
|
|
13
|
+
Error: You are trying to configure the smell detector '%<detector>s'
|
|
14
|
+
in one of your source code comments with the unknown option %<option>s.
|
|
15
|
+
The source is '%<source>s' and the comment belongs to the expression starting in line %<line>d.
|
|
14
16
|
Here's the original comment:
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
%<comment>s
|
|
17
19
|
|
|
18
20
|
Please see the Reek docs for:
|
|
19
|
-
* how to configure Reek via source code comments:
|
|
20
|
-
* what basic options are available:
|
|
21
|
+
* how to configure Reek via source code comments: #{DocumentationLink.build('Smell Suppression')}
|
|
22
|
+
* what basic options are available: #{DocumentationLink.build('Basic Smell Options')}
|
|
21
23
|
* what custom options are available by checking the detector specific documentation in /docs
|
|
22
24
|
Update the offensive comment (or remove it if no longer applicable) and re-run Reek.
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
MESSAGE
|
|
25
27
|
|
|
26
28
|
def initialize(detector_name:, offensive_keys:, source:, line:, original_comment:)
|
|
27
29
|
message = format(UNKNOWN_SMELL_DETECTOR_MESSAGE,
|
|
28
|
-
detector_name,
|
|
29
|
-
offensive_keys,
|
|
30
|
-
source,
|
|
31
|
-
line,
|
|
32
|
-
original_comment)
|
|
30
|
+
detector: detector_name,
|
|
31
|
+
option: offensive_keys,
|
|
32
|
+
source: source,
|
|
33
|
+
line: line,
|
|
34
|
+
comment: original_comment)
|
|
33
35
|
super message
|
|
34
36
|
end
|
|
35
37
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require_relative 'base_error'
|
|
4
|
+
require_relative '../documentation_link'
|
|
3
5
|
|
|
4
6
|
module Reek
|
|
5
7
|
module Errors
|
|
@@ -7,28 +9,28 @@ module Reek
|
|
|
7
9
|
# This might happen for multiple reasons. The users might have a typo in
|
|
8
10
|
# his comment or he might use a detector that does not exist anymore.
|
|
9
11
|
class BadDetectorInCommentError < BaseError
|
|
10
|
-
UNKNOWN_SMELL_DETECTOR_MESSAGE = <<-
|
|
12
|
+
UNKNOWN_SMELL_DETECTOR_MESSAGE = <<-MESSAGE
|
|
11
13
|
|
|
12
|
-
Error: You are trying to configure an unknown smell detector '
|
|
14
|
+
Error: You are trying to configure an unknown smell detector '%<detector>s' in one
|
|
13
15
|
of your source code comments.
|
|
14
|
-
The source is '
|
|
16
|
+
The source is '%<source>s' and the comment belongs to the expression starting in line %<line>d.
|
|
15
17
|
Here's the original comment:
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
%<comment>s
|
|
18
20
|
|
|
19
21
|
Please see the Reek docs for:
|
|
20
|
-
* how to configure Reek via source code comments:
|
|
21
|
-
* what smell detectors are available:
|
|
22
|
+
* how to configure Reek via source code comments: #{DocumentationLink.build('Smell Suppression')}
|
|
23
|
+
* what smell detectors are available: #{DocumentationLink.build('Code Smells')}
|
|
22
24
|
Update the offensive comment (or remove it if no longer applicable) and re-run Reek.
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
MESSAGE
|
|
25
27
|
|
|
26
28
|
def initialize(detector_name:, source:, line:, original_comment:)
|
|
27
29
|
message = format(UNKNOWN_SMELL_DETECTOR_MESSAGE,
|
|
28
|
-
detector_name,
|
|
29
|
-
source,
|
|
30
|
-
line,
|
|
31
|
-
original_comment)
|
|
30
|
+
detector: detector_name,
|
|
31
|
+
source: source,
|
|
32
|
+
line: line,
|
|
33
|
+
comment: original_comment)
|
|
32
34
|
super message
|
|
33
35
|
end
|
|
34
36
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_error'
|
|
4
|
+
|
|
5
|
+
module Reek
|
|
6
|
+
module Errors
|
|
7
|
+
# Gets raised when Reek is unable to process the source due to an EncodingError
|
|
8
|
+
class EncodingError < BaseError
|
|
9
|
+
TEMPLATE = "Source '%<source>s' cannot be processed by Reek due to an encoding error in the source file."
|
|
10
|
+
|
|
11
|
+
LONG_TEMPLATE = <<-MESSAGE
|
|
12
|
+
!!!
|
|
13
|
+
%<message>s
|
|
14
|
+
|
|
15
|
+
This is a problem that is outside of Reek's scope and should be fixed by you, the
|
|
16
|
+
user, in order for Reek being able to continue.
|
|
17
|
+
Check out this article for an idea on how to get started:
|
|
18
|
+
https://www.justinweiss.com/articles/3-steps-to-fix-encoding-problems-in-ruby/
|
|
19
|
+
|
|
20
|
+
Exception message:
|
|
21
|
+
|
|
22
|
+
%<exception>s
|
|
23
|
+
|
|
24
|
+
Original backtrace:
|
|
25
|
+
|
|
26
|
+
%<original>s
|
|
27
|
+
|
|
28
|
+
!!!
|
|
29
|
+
MESSAGE
|
|
30
|
+
|
|
31
|
+
def initialize(origin:)
|
|
32
|
+
super format(TEMPLATE, source: origin)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def long_message
|
|
36
|
+
format(LONG_TEMPLATE,
|
|
37
|
+
message: message,
|
|
38
|
+
exception: cause.inspect,
|
|
39
|
+
original: cause.backtrace.join("\n\t"))
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -1,33 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require_relative 'base_error'
|
|
4
|
+
require_relative '../documentation_link'
|
|
3
5
|
|
|
4
6
|
module Reek
|
|
5
7
|
module Errors
|
|
6
8
|
# Gets raised when trying to use a configuration for a detector
|
|
7
9
|
# that can't be parsed into a hash.
|
|
8
10
|
class GarbageDetectorConfigurationInCommentError < BaseError
|
|
9
|
-
BAD_DETECTOR_CONFIGURATION_MESSAGE = <<-
|
|
11
|
+
BAD_DETECTOR_CONFIGURATION_MESSAGE = <<-MESSAGE
|
|
10
12
|
|
|
11
|
-
Error: You are trying to configure the smell detector '
|
|
12
|
-
Unfortunately we
|
|
13
|
-
The source is '
|
|
13
|
+
Error: You are trying to configure the smell detector '%<detector>s'.
|
|
14
|
+
Unfortunately we cannot parse the configuration you have given.
|
|
15
|
+
The source is '%<source>s' and the comment belongs to the expression starting in line %<line>d.
|
|
14
16
|
Here's the original comment:
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
%<comment>s
|
|
17
19
|
|
|
18
20
|
Please see the Reek docs for:
|
|
19
|
-
* how to configure Reek via source code comments:
|
|
20
|
-
* what smell detectors are available:
|
|
21
|
+
* how to configure Reek via source code comments: #{DocumentationLink.build('Smell Suppression')}
|
|
22
|
+
* what smell detectors are available: #{DocumentationLink.build('Code Smells')}
|
|
21
23
|
Update the offensive comment (or remove it if no longer applicable) and re-run Reek.
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
MESSAGE
|
|
24
26
|
|
|
25
27
|
def initialize(detector_name:, source:, line:, original_comment:)
|
|
26
28
|
message = format(BAD_DETECTOR_CONFIGURATION_MESSAGE,
|
|
27
|
-
detector_name,
|
|
28
|
-
source,
|
|
29
|
-
line,
|
|
30
|
-
original_comment)
|
|
29
|
+
detector: detector_name,
|
|
30
|
+
source: source,
|
|
31
|
+
line: line,
|
|
32
|
+
comment: original_comment)
|
|
31
33
|
super message
|
|
32
34
|
end
|
|
33
35
|
end
|
|
@@ -1,46 +1,45 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require_relative 'base_error'
|
|
3
4
|
|
|
4
5
|
module Reek
|
|
5
6
|
module Errors
|
|
6
7
|
# Gets raised when Reek is unable to process the source
|
|
7
8
|
class IncomprehensibleSourceError < BaseError
|
|
8
|
-
|
|
9
|
-
!!!
|
|
10
|
-
Source %s can not be processed by Reek.
|
|
9
|
+
TEMPLATE = 'Source %<source>s cannot be processed by Reek.'
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
LONG_TEMPLATE = <<-MESSAGE
|
|
12
|
+
!!!
|
|
13
|
+
%<message>s
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
below into account - you might have misspelled a smell detector for instance.
|
|
17
|
-
(In the future Reek will handle configuration errors more gracefully, something
|
|
18
|
-
we are working on already).
|
|
15
|
+
This is most likely a Reek bug.
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
team by opening up a corresponding issue at https://github.com/troessner/reek/issues.
|
|
17
|
+
It would be great if you could report this back to the Reek team by opening a
|
|
18
|
+
corresponding issue at https://github.com/troessner/reek/issues.
|
|
23
19
|
|
|
24
|
-
Please make sure to include the source in question, the Reek version
|
|
25
|
-
|
|
20
|
+
Please make sure to include the source in question, the Reek version and the
|
|
21
|
+
original exception below.
|
|
26
22
|
|
|
27
23
|
Exception message:
|
|
28
24
|
|
|
29
|
-
|
|
25
|
+
%<exception>s
|
|
30
26
|
|
|
31
27
|
Original exception:
|
|
32
28
|
|
|
33
|
-
|
|
29
|
+
%<original>s
|
|
34
30
|
|
|
35
31
|
!!!
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def initialize(origin
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
MESSAGE
|
|
33
|
+
|
|
34
|
+
def initialize(origin:)
|
|
35
|
+
super format(TEMPLATE, source: origin)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def long_message
|
|
39
|
+
format(LONG_TEMPLATE,
|
|
40
|
+
message: message,
|
|
41
|
+
exception: cause.inspect,
|
|
42
|
+
original: cause.backtrace.join("\n\t"))
|
|
44
43
|
end
|
|
45
44
|
end
|
|
46
45
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_error'
|
|
4
|
+
|
|
5
|
+
module Reek
|
|
6
|
+
module Errors
|
|
7
|
+
# Gets raised when Reek is unable to process the source due to a SyntaxError
|
|
8
|
+
class SyntaxError < BaseError
|
|
9
|
+
TEMPLATE = "Source '%<source>s' cannot be processed by Reek due to a syntax error in the source file."
|
|
10
|
+
|
|
11
|
+
LONG_TEMPLATE = <<-MESSAGE
|
|
12
|
+
!!!
|
|
13
|
+
%<message>s
|
|
14
|
+
|
|
15
|
+
This is a problem that is outside of Reek's scope and should be fixed by you, the
|
|
16
|
+
user, in order for Reek being able to continue.
|
|
17
|
+
|
|
18
|
+
Exception message:
|
|
19
|
+
|
|
20
|
+
%<exception>s
|
|
21
|
+
|
|
22
|
+
Original backtrace:
|
|
23
|
+
|
|
24
|
+
%<original>s
|
|
25
|
+
|
|
26
|
+
!!!
|
|
27
|
+
MESSAGE
|
|
28
|
+
|
|
29
|
+
def initialize(origin:)
|
|
30
|
+
super format(TEMPLATE, source: origin)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def long_message
|
|
34
|
+
format(LONG_TEMPLATE,
|
|
35
|
+
message: message,
|
|
36
|
+
exception: cause.inspect,
|
|
37
|
+
original: cause.backtrace.join("\n\t"))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/reek/examiner.rb
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require_relative 'context_builder'
|
|
3
4
|
require_relative 'detector_repository'
|
|
4
5
|
require_relative 'errors/incomprehensible_source_error'
|
|
6
|
+
require_relative 'errors/encoding_error'
|
|
7
|
+
require_relative 'errors/syntax_error'
|
|
5
8
|
require_relative 'source/source_code'
|
|
6
9
|
|
|
7
10
|
module Reek
|
|
@@ -9,6 +12,7 @@ module Reek
|
|
|
9
12
|
# Applies all available smell detectors to a source.
|
|
10
13
|
#
|
|
11
14
|
# @public
|
|
15
|
+
# @quality :reek:TooManyInstanceVariables { max_instance_variables: 5 }
|
|
12
16
|
class Examiner
|
|
13
17
|
# Handles no errors
|
|
14
18
|
class NullHandler
|
|
@@ -37,26 +41,17 @@ module Reek
|
|
|
37
41
|
detector_repository_class: DetectorRepository,
|
|
38
42
|
error_handler: NullHandler.new)
|
|
39
43
|
@source = Source::SourceCode.from(source)
|
|
44
|
+
@origin = @source.origin
|
|
40
45
|
@smell_types = detector_repository_class.eligible_smell_types(filter_by_smells)
|
|
41
46
|
@detector_repository = detector_repository_class.new(smell_types: @smell_types,
|
|
42
|
-
configuration: configuration.directive_for(
|
|
47
|
+
configuration: configuration.directive_for(@origin))
|
|
43
48
|
@error_handler = error_handler
|
|
44
49
|
end
|
|
45
50
|
|
|
46
51
|
# @return [String] origin of the source being analysed
|
|
47
52
|
#
|
|
48
53
|
# @public
|
|
49
|
-
|
|
50
|
-
@origin ||= source.origin
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# @return [String] description of the source being analysed
|
|
54
|
-
#
|
|
55
|
-
# @public
|
|
56
|
-
# @deprecated Use origin
|
|
57
|
-
def description
|
|
58
|
-
origin
|
|
59
|
-
end
|
|
54
|
+
attr_reader :origin
|
|
60
55
|
|
|
61
56
|
#
|
|
62
57
|
# @return [Array<SmellWarning>] the smells found in the source
|
|
@@ -94,15 +89,26 @@ module Reek
|
|
|
94
89
|
#
|
|
95
90
|
# @return [Array<SmellWarning>] the smells found in the source
|
|
96
91
|
#
|
|
97
|
-
# :reek:TooManyStatements { max_statements: 8 }
|
|
98
92
|
def run
|
|
99
|
-
|
|
100
|
-
begin
|
|
93
|
+
wrap_exceptions do
|
|
101
94
|
examine_tree
|
|
102
|
-
rescue Errors::BaseError => exception
|
|
103
|
-
raise unless @error_handler.handle exception
|
|
104
|
-
[]
|
|
105
95
|
end
|
|
96
|
+
rescue StandardError => exception
|
|
97
|
+
raise unless @error_handler.handle exception
|
|
98
|
+
[]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @quality :reek:TooManyStatements { max_statements: 6 }
|
|
102
|
+
def wrap_exceptions
|
|
103
|
+
yield
|
|
104
|
+
rescue Errors::BaseError
|
|
105
|
+
raise
|
|
106
|
+
rescue EncodingError
|
|
107
|
+
raise Errors::EncodingError, origin: origin
|
|
108
|
+
rescue Parser::SyntaxError
|
|
109
|
+
raise Errors::SyntaxError, origin: origin
|
|
110
|
+
rescue StandardError
|
|
111
|
+
raise Errors::IncomprehensibleSourceError, origin: origin
|
|
106
112
|
end
|
|
107
113
|
|
|
108
114
|
def syntax_tree
|
|
@@ -113,10 +119,6 @@ module Reek
|
|
|
113
119
|
ContextBuilder.new(syntax_tree).context_tree.flat_map do |element|
|
|
114
120
|
detector_repository.examine(element)
|
|
115
121
|
end
|
|
116
|
-
rescue Errors::BaseError
|
|
117
|
-
raise
|
|
118
|
-
rescue StandardError => exception
|
|
119
|
-
raise Errors::IncomprehensibleSourceError, origin: origin, original_exception: exception
|
|
120
122
|
end
|
|
121
123
|
end
|
|
122
124
|
end
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'errors/
|
|
4
|
-
require_relative 'errors/garbage_detector_configuration_in_comment_error'
|
|
5
|
-
require_relative 'errors/incomprehensible_source_error'
|
|
2
|
+
|
|
3
|
+
require_relative 'errors/base_error'
|
|
6
4
|
|
|
7
5
|
module Reek
|
|
8
6
|
# Handles errors by logging to stderr
|
|
9
7
|
class LoggingErrorHandler
|
|
10
8
|
def handle(exception)
|
|
11
|
-
|
|
9
|
+
case exception
|
|
10
|
+
when Errors::BaseError
|
|
11
|
+
warn exception.long_message
|
|
12
|
+
else
|
|
13
|
+
warn exception
|
|
14
|
+
end
|
|
12
15
|
true
|
|
13
16
|
end
|
|
14
17
|
end
|
data/lib/reek/rake/task.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
3
|
require 'rake'
|
|
@@ -34,8 +33,8 @@ module Reek
|
|
|
34
33
|
#
|
|
35
34
|
# @public
|
|
36
35
|
#
|
|
37
|
-
# :reek:TooManyInstanceVariables
|
|
38
|
-
# :reek:Attribute
|
|
36
|
+
# @quality :reek:TooManyInstanceVariables { max_instance_variables: 6 }
|
|
37
|
+
# @quality :reek:Attribute
|
|
39
38
|
class Task < ::Rake::TaskLib
|
|
40
39
|
# Name of Reek task. Defaults to :reek.
|
|
41
40
|
# @public
|
|
@@ -74,10 +73,14 @@ module Reek
|
|
|
74
73
|
@name = name
|
|
75
74
|
@reek_opts = ENV['REEK_OPTS'] || ''
|
|
76
75
|
@fail_on_error = true
|
|
77
|
-
@source_files = FileList[ENV['REEK_SRC'] || 'lib/**/*.rb']
|
|
78
76
|
@verbose = false
|
|
79
77
|
|
|
80
78
|
yield self if block_given?
|
|
79
|
+
|
|
80
|
+
if (reek_src = ENV['REEK_SRC'])
|
|
81
|
+
@source_files = FileList[reek_src]
|
|
82
|
+
end
|
|
83
|
+
@source_files ||= FileList['lib/**/*.rb']
|
|
81
84
|
define_task
|
|
82
85
|
end
|
|
83
86
|
|
|
@@ -111,7 +114,7 @@ module Reek
|
|
|
111
114
|
reject(&:empty?)
|
|
112
115
|
end
|
|
113
116
|
|
|
114
|
-
# :reek:UtilityFunction
|
|
117
|
+
# @quality :reek:UtilityFunction
|
|
115
118
|
def sys_call_failed?
|
|
116
119
|
!$CHILD_STATUS.success?
|
|
117
120
|
end
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require 'json'
|
|
3
4
|
require 'pathname'
|
|
4
5
|
require 'rainbow'
|
|
5
6
|
|
|
6
|
-
require_relative 'formatter'
|
|
7
|
-
|
|
8
7
|
module Reek
|
|
9
8
|
# @public
|
|
10
9
|
module Report
|
|
@@ -15,22 +14,20 @@ module Reek
|
|
|
15
14
|
#
|
|
16
15
|
# @public
|
|
17
16
|
#
|
|
18
|
-
# :reek:TooManyInstanceVariables
|
|
17
|
+
# @quality :reek:TooManyInstanceVariables { max_instance_variables: 7 }
|
|
19
18
|
class BaseReport
|
|
20
19
|
NO_WARNINGS_COLOR = :green
|
|
21
20
|
WARNINGS_COLOR = :red
|
|
22
21
|
|
|
23
22
|
# @public
|
|
24
23
|
#
|
|
25
|
-
# :reek:BooleanParameter
|
|
26
|
-
def initialize(heading_formatter:
|
|
27
|
-
report_formatter: Formatter,
|
|
24
|
+
# @quality :reek:BooleanParameter
|
|
25
|
+
def initialize(heading_formatter: QuietHeadingFormatter,
|
|
28
26
|
sort_by_issue_count: false,
|
|
29
|
-
warning_formatter:
|
|
30
|
-
progress_formatter:
|
|
27
|
+
warning_formatter: SimpleWarningFormatter.new,
|
|
28
|
+
progress_formatter: ProgressFormatter::Quiet.new(0))
|
|
31
29
|
@examiners = []
|
|
32
|
-
@heading_formatter = heading_formatter.new
|
|
33
|
-
@report_formatter = report_formatter
|
|
30
|
+
@heading_formatter = heading_formatter.new
|
|
34
31
|
@progress_formatter = progress_formatter
|
|
35
32
|
@sort_by_issue_count = sort_by_issue_count
|
|
36
33
|
@total_smell_count = 0
|
|
@@ -57,7 +54,7 @@ module Reek
|
|
|
57
54
|
end
|
|
58
55
|
|
|
59
56
|
def smells?
|
|
60
|
-
total_smell_count
|
|
57
|
+
total_smell_count.positive?
|
|
61
58
|
end
|
|
62
59
|
|
|
63
60
|
def smells
|
|
@@ -70,7 +67,7 @@ module Reek
|
|
|
70
67
|
|
|
71
68
|
private
|
|
72
69
|
|
|
73
|
-
attr_reader :examiners, :heading_formatter,
|
|
70
|
+
attr_reader :examiners, :heading_formatter,
|
|
74
71
|
:sort_by_issue_count, :warning_formatter, :progress_formatter
|
|
75
72
|
end
|
|
76
73
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Reek
|
|
3
4
|
module Report
|
|
4
5
|
# loads the smell type metadata to present in Code Climate
|
|
5
6
|
module CodeClimateConfiguration
|
|
6
7
|
def self.load
|
|
7
|
-
config_file = File.expand_path('
|
|
8
|
+
config_file = File.expand_path('code_climate_configuration.yml', __dir__)
|
|
8
9
|
YAML.load_file config_file
|
|
9
10
|
end
|
|
10
11
|
end
|