reek 4.8.2 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
- data/.rubocop.yml +17 -3
- data/.simplecov +1 -0
- data/.travis.yml +0 -5
- data/.yardopts +1 -1
- data/CHANGELOG.md +28 -0
- data/Gemfile +1 -1
- data/README.md +113 -98
- 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/{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 +43 -4
- data/docs/Uncommunicative-Module-Name.md +48 -6
- data/docs/Uncommunicative-Parameter-Name.md +42 -4
- data/docs/Uncommunicative-Variable-Name.md +73 -2
- data/docs/Unused-Private-Method.md +1 -1
- data/docs/defaults.reek.yml +129 -0
- data/docs/yard_plugin.rb +1 -0
- data/features/command_line_interface/options.feature +46 -4
- data/features/command_line_interface/stdin.feature +27 -5
- data/features/configuration_files/accept_setting.feature +39 -22
- data/features/configuration_files/directory_specific_directives.feature +58 -53
- data/features/configuration_files/exclude_directives.feature +8 -7
- data/features/configuration_files/masking_smells.feature +35 -6
- data/features/configuration_files/mix_accept_reject_setting.feature +24 -21
- data/features/configuration_files/reject_setting.feature +45 -34
- data/features/configuration_files/schema_validation.feature +59 -0
- data/features/configuration_files/unused_private_method.feature +14 -12
- data/features/configuration_loading.feature +50 -7
- data/features/rake_task/rake_task.feature +5 -5
- data/features/reports/json.feature +4 -1
- data/features/reports/reports.feature +12 -12
- data/features/reports/yaml.feature +3 -0
- data/features/rspec_matcher.feature +9 -1
- 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 +16 -13
- data/lib/reek/ast/node.rb +3 -6
- data/lib/reek/ast/object_refs.rb +1 -1
- data/lib/reek/ast/sexp_extensions/if.rb +1 -1
- data/lib/reek/ast/sexp_extensions/methods.rb +1 -1
- 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 +4 -2
- data/lib/reek/cli/options.rb +27 -13
- 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 +4 -4
- data/lib/reek/context/method_context.rb +2 -2
- data/lib/reek/context/module_context.rb +1 -1
- data/lib/reek/context_builder.rb +9 -9
- data/lib/reek/detector_repository.rb +6 -0
- data/lib/reek/documentation_link.rb +2 -2
- data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +1 -1
- data/lib/reek/errors/bad_detector_in_comment_error.rb +1 -1
- data/lib/reek/errors/config_file_error.rb +11 -0
- data/lib/reek/errors/encoding_error.rb +2 -2
- data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +1 -1
- data/lib/reek/errors/incomprehensible_source_error.rb +2 -2
- data/lib/reek/errors/syntax_error.rb +41 -0
- data/lib/reek/examiner.rb +9 -19
- data/lib/reek/rake/task.rb +3 -3
- data/lib/reek/report.rb +15 -10
- data/lib/reek/report/base_report.rb +8 -12
- data/lib/reek/report/code_climate/code_climate_configuration.yml +5 -9
- 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/smell_configuration.rb +2 -2
- data/lib/reek/smell_detectors.rb +1 -2
- data/lib/reek/smell_detectors/attribute.rb +0 -1
- data/lib/reek/smell_detectors/base_detector.rb +8 -11
- data/lib/reek/smell_detectors/boolean_parameter.rb +0 -1
- data/lib/reek/smell_detectors/class_variable.rb +0 -1
- 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 +5 -6
- data/lib/reek/smell_detectors/feature_envy.rb +0 -1
- data/lib/reek/smell_detectors/instance_variable_assumption.rb +0 -1
- 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 +2 -2
- data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +6 -7
- data/lib/reek/smell_detectors/module_initialize.rb +0 -1
- data/lib/reek/smell_detectors/nested_iterators.rb +4 -5
- 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 +1 -2
- 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 +4 -5
- 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 +1 -2
- data/lib/reek/smell_warning.rb +10 -8
- data/lib/reek/source/source_code.rb +40 -55
- data/lib/reek/source/source_locator.rb +7 -7
- data/lib/reek/spec.rb +6 -6
- 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/tree_dresser.rb +5 -5
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +3 -3
- data/samples/checkstyle.xml +1 -1
- data/samples/{clean.rb → clean_source/clean.rb} +0 -0
- 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/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
- data/samples/configuration/partial_mask.reek +3 -2
- data/samples/configuration/regular_configuration/.reek.yml +4 -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/paths.rb +5 -4
- 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/.hidden/hidden.rb +1 -0
- data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
- data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
- data/spec/reek/ast/node_spec.rb +5 -5
- data/spec/reek/cli/application_spec.rb +18 -4
- data/spec/reek/cli/command/todo_list_command_spec.rb +4 -2
- data/spec/reek/cli/silencer_spec.rb +28 -0
- data/spec/reek/code_comment_spec.rb +0 -7
- data/spec/reek/configuration/app_configuration_spec.rb +44 -31
- 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 +3 -4
- data/spec/reek/configuration/excluded_paths_spec.rb +5 -5
- 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 +1 -1
- data/spec/reek/examiner_spec.rb +28 -1
- 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 +1 -1
- data/spec/reek/report/yaml_report_spec.rb +9 -38
- data/spec/reek/report_spec.rb +3 -3
- data/spec/reek/smell_detectors/feature_envy_spec.rb +2 -2
- data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +9 -9
- 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 +6 -6
- data/spec/reek/smell_detectors/unused_private_method_spec.rb +1 -1
- data/spec/reek/smell_warning_spec.rb +4 -0
- data/spec/reek/source/source_code_spec.rb +16 -22
- data/spec/reek/source/source_locator_spec.rb +11 -11
- data/spec/reek/spec/should_reek_of_spec.rb +0 -4
- data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
- data/spec/reek/spec/should_reek_spec.rb +1 -1
- data/spec/reek/tree_dresser_spec.rb +2 -6
- data/spec/spec_helper.rb +3 -5
- data/tasks/configuration.rake +8 -5
- metadata +56 -35
- data/defaults.reek +0 -131
- data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
- data/lib/reek/report/formatter.rb +0 -33
- 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 -23
- 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
@@ -15,20 +15,30 @@ module Reek
|
|
15
15
|
# @public
|
16
16
|
class AppConfiguration
|
17
17
|
include ConfigurationValidator
|
18
|
-
EXCLUDE_PATHS_KEY = 'exclude_paths'
|
18
|
+
EXCLUDE_PATHS_KEY = 'exclude_paths'
|
19
|
+
DIRECTORIES_KEY = 'directories'
|
20
|
+
DETECTORS_KEY = 'detectors'
|
19
21
|
|
20
|
-
# Instantiate a configuration via
|
22
|
+
# Instantiate a configuration via the given path.
|
21
23
|
#
|
22
|
-
# @param path [Pathname] the path to the config file
|
23
|
-
# default path.
|
24
|
+
# @param path [Pathname] the path to the config file.
|
24
25
|
#
|
25
26
|
# @return [AppConfiguration]
|
26
27
|
#
|
27
28
|
# @public
|
28
|
-
def self.from_path(path
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
def self.from_path(path)
|
30
|
+
values = ConfigurationFileFinder.find_and_load(path: path)
|
31
|
+
new(values: values)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Instantiate a configuration via the default path.
|
35
|
+
#
|
36
|
+
# @return [AppConfiguration]
|
37
|
+
#
|
38
|
+
# @public
|
39
|
+
def self.from_default_path
|
40
|
+
values = ConfigurationFileFinder.find_and_load(path: nil)
|
41
|
+
new(values: values)
|
32
42
|
end
|
33
43
|
|
34
44
|
# Instantiate a configuration by passing everything in.
|
@@ -40,21 +50,17 @@ module Reek
|
|
40
50
|
# @return [AppConfiguration]
|
41
51
|
#
|
42
52
|
# @public
|
43
|
-
def self.from_hash(hash
|
44
|
-
|
45
|
-
instance.instance_eval do
|
46
|
-
load_values hash
|
47
|
-
end
|
48
|
-
end
|
53
|
+
def self.from_hash(hash)
|
54
|
+
new(values: hash)
|
49
55
|
end
|
50
56
|
|
51
57
|
def self.default
|
52
|
-
new
|
58
|
+
new(values: {})
|
53
59
|
end
|
54
60
|
|
55
61
|
# Returns the directive for a given directory.
|
56
62
|
#
|
57
|
-
# @param source_via [String]
|
63
|
+
# @param source_via [String] the source of the code inspected
|
58
64
|
#
|
59
65
|
# @return [Hash] the directory directive for the source with the default directive
|
60
66
|
# reverse-merged into it.
|
@@ -67,18 +73,22 @@ module Reek
|
|
67
73
|
excluded_paths.map(&:expand_path).include?(path.expand_path)
|
68
74
|
end
|
69
75
|
|
70
|
-
def load_values(
|
71
|
-
|
76
|
+
def load_values(values)
|
77
|
+
values.each do |key, value|
|
72
78
|
if key == EXCLUDE_PATHS_KEY
|
73
79
|
excluded_paths.add value
|
74
|
-
elsif
|
75
|
-
|
76
|
-
|
77
|
-
|
80
|
+
elsif key == DIRECTORIES_KEY
|
81
|
+
directory_directives.add value
|
82
|
+
elsif key == DETECTORS_KEY
|
83
|
+
default_directive.add value
|
78
84
|
end
|
79
85
|
end
|
80
86
|
end
|
81
87
|
|
88
|
+
def initialize(values: {})
|
89
|
+
load_values(values)
|
90
|
+
end
|
91
|
+
|
82
92
|
private
|
83
93
|
|
84
94
|
attr_writer :directory_directives, :default_directive, :excluded_paths
|
@@ -94,12 +104,6 @@ module Reek
|
|
94
104
|
def excluded_paths
|
95
105
|
@excluded_paths ||= [].extend(ExcludedPaths)
|
96
106
|
end
|
97
|
-
|
98
|
-
def find_and_load(path: nil)
|
99
|
-
configuration_hash = ConfigurationFileFinder.find_and_load(path: path)
|
100
|
-
|
101
|
-
load_values(configuration_hash)
|
102
|
-
end
|
103
107
|
end
|
104
108
|
end
|
105
109
|
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './configuration_validator'
|
4
|
+
|
5
|
+
module Reek
|
6
|
+
module Configuration
|
7
|
+
# Responsible for converting marked strings coming from the outside world
|
8
|
+
# into proper regexes.
|
9
|
+
class ConfigurationConverter
|
10
|
+
REGEXABLE_ATTRIBUTES = %w(accept reject exclude).freeze
|
11
|
+
include ConfigurationValidator
|
12
|
+
attr_reader :configuration
|
13
|
+
|
14
|
+
# @param configuration [Hash] e.g.
|
15
|
+
#
|
16
|
+
# detectors => {
|
17
|
+
# "UnusedPrivateMethod" => {"exclude"=>["/exclude regexp/"]},
|
18
|
+
# "UncommunicativeMethodName"=>{"reject"=>["reject name"], "accept"=>["accept name"]
|
19
|
+
# },
|
20
|
+
# directories => {
|
21
|
+
# "app/controllers" => {
|
22
|
+
# "UnusedPrivateMethod" => {"exclude"=>["/exclude regexp/"]},
|
23
|
+
# "UncommunicativeMethodName"=>{"reject"=>["reject name"], "accept"=>["accept name"]}
|
24
|
+
# }
|
25
|
+
# }
|
26
|
+
def initialize(configuration)
|
27
|
+
@configuration = configuration
|
28
|
+
end
|
29
|
+
|
30
|
+
# Converts all marked strings across the whole configuration to regexes.
|
31
|
+
# @return [Hash]
|
32
|
+
#
|
33
|
+
def convert
|
34
|
+
strings_to_regexes_for_detectors
|
35
|
+
strings_to_regexes_for_directories
|
36
|
+
|
37
|
+
configuration
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# @param value [String] String that is potentially marked as regex, e.g. "/foobar/".
|
43
|
+
# @return [Bool] if the string in question is marked as regex.
|
44
|
+
#
|
45
|
+
# @quality :reek:UtilityFunction
|
46
|
+
def marked_as_regex?(value)
|
47
|
+
value.start_with?('/') && value.end_with?('/')
|
48
|
+
end
|
49
|
+
|
50
|
+
# @param value [value] String that is potentially marked as regex, e.g. "/foobar/".
|
51
|
+
# @return [Regexp] e.g. /foobar/.
|
52
|
+
#
|
53
|
+
def to_regex(value)
|
54
|
+
marked_as_regex?(value) ? Regexp.new(value[1..-2]) : value
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param detector_configuration [Hash] e.g.
|
58
|
+
# { "UnusedPrivateMethod" => {"exclude"=>["/exclude regexp/"] }
|
59
|
+
# @return [Array] all the attributes from the detector configuration that potentially contain regexes.
|
60
|
+
# Using this example above this would just be "exclude".
|
61
|
+
#
|
62
|
+
# @quality :reek:UtilityFunction
|
63
|
+
def convertible_attributes(detector_configuration)
|
64
|
+
detector_configuration.keys & REGEXABLE_ATTRIBUTES
|
65
|
+
end
|
66
|
+
|
67
|
+
# Iterates over our detector configuration and converts all marked strings into regexes.
|
68
|
+
# @return nil
|
69
|
+
#
|
70
|
+
# @quality :reek:DuplicateMethodCall { max_calls: 3 }
|
71
|
+
# @quality :reek:NestedIterators { max_allowed_nesting: 3 }
|
72
|
+
# @quality :reek:TooManyStatements { max_statements: 6 }
|
73
|
+
def strings_to_regexes_for_detectors
|
74
|
+
return unless configuration[AppConfiguration::DETECTORS_KEY]
|
75
|
+
|
76
|
+
configuration[AppConfiguration::DETECTORS_KEY].tap do |detectors|
|
77
|
+
detectors.keys.each do |detector|
|
78
|
+
convertible_attributes(detectors[detector]).each do |attribute|
|
79
|
+
detectors[detector][attribute] = detectors[detector][attribute].map do |item|
|
80
|
+
to_regex item
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Iterates over our directory configuration and converts all marked strings into regexes.
|
88
|
+
# @return nil
|
89
|
+
#
|
90
|
+
# @quality :reek:DuplicateMethodCall { max_calls: 3 }
|
91
|
+
# @quality :reek:NestedIterators { max_allowed_nesting: 4 }
|
92
|
+
# @quality :reek:TooManyStatements { max_statements: 7 }
|
93
|
+
def strings_to_regexes_for_directories
|
94
|
+
return unless configuration[AppConfiguration::DIRECTORIES_KEY]
|
95
|
+
|
96
|
+
configuration[AppConfiguration::DIRECTORIES_KEY].tap do |directories|
|
97
|
+
directories.keys.each do |directory|
|
98
|
+
directories[directory].each do |detector, configuration|
|
99
|
+
convertible_attributes(configuration).each do |attribute|
|
100
|
+
directories[directory][detector][attribute] = directories[directory][detector][attribute].map do |item|
|
101
|
+
to_regex item
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -1,35 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'pathname'
|
4
|
+
require_relative './configuration_converter'
|
5
|
+
require_relative './schema_validator'
|
6
|
+
require_relative '../errors/config_file_error'
|
4
7
|
|
5
8
|
module Reek
|
6
9
|
module Configuration
|
7
|
-
# Raised when config file is not properly readable.
|
8
|
-
class ConfigFileException < StandardError; end
|
9
10
|
#
|
10
11
|
# ConfigurationFileFinder is responsible for finding Reek's configuration.
|
11
12
|
#
|
12
13
|
# There are 3 ways of passing `reek` a configuration file:
|
13
14
|
# 1. Using the cli "-c" switch
|
14
|
-
# 2. Having a file
|
15
|
+
# 2. Having a file .reek.yml either in your current working
|
15
16
|
# directory or in a parent directory
|
16
|
-
# 3. Having a file
|
17
|
+
# 3. Having a file .reek.yml in your HOME directory
|
17
18
|
#
|
18
19
|
# The order in which ConfigurationFileFinder tries to find such a
|
19
20
|
# configuration file is exactly like above.
|
20
21
|
module ConfigurationFileFinder
|
21
|
-
|
22
|
-
|
23
|
-
Error: Found multiple configuration files %<files>s
|
24
|
-
while scanning directory %<directory>s.
|
25
|
-
|
26
|
-
Reek supports only one configuration file. You have 2 options now:
|
27
|
-
1) Remove all offending files.
|
28
|
-
2) Be specific about which one you want to load via the -c switch.
|
29
|
-
|
30
|
-
MESSAGE
|
22
|
+
DEFAULT_FILE_NAME = '.reek.yml'
|
31
23
|
|
32
24
|
class << self
|
25
|
+
include ConfigurationValidator
|
33
26
|
#
|
34
27
|
# Finds and loads a configuration file from a given path.
|
35
28
|
#
|
@@ -47,7 +40,7 @@ module Reek
|
|
47
40
|
#
|
48
41
|
# @return [File|nil]
|
49
42
|
#
|
50
|
-
# :reek:ControlParameter
|
43
|
+
# @quality :reek:ControlParameter
|
51
44
|
def find(path: nil, current: Pathname.pwd, home: Pathname.new(Dir.home))
|
52
45
|
path || find_by_dir(current) || find_in_dir(home)
|
53
46
|
end
|
@@ -59,19 +52,18 @@ module Reek
|
|
59
52
|
# @param path [String]
|
60
53
|
# @return [Hash]
|
61
54
|
#
|
62
|
-
# :reek:TooManyStatements
|
55
|
+
# @quality :reek:TooManyStatements { max_statements: 6 }
|
63
56
|
def load_from_file(path)
|
64
57
|
return {} unless path
|
58
|
+
|
65
59
|
begin
|
66
60
|
configuration = YAML.load_file(path) || {}
|
67
61
|
rescue StandardError => error
|
68
|
-
raise ConfigFileException, "Invalid configuration file #{path}, error is #{error}"
|
62
|
+
raise Errors::ConfigFileException, "Invalid configuration file #{path}, error is #{error}"
|
69
63
|
end
|
70
64
|
|
71
|
-
|
72
|
-
|
73
|
-
end
|
74
|
-
configuration
|
65
|
+
SchemaValidator.new(configuration).validate
|
66
|
+
ConfigurationConverter.new(configuration).convert
|
75
67
|
end
|
76
68
|
|
77
69
|
private
|
@@ -90,29 +82,12 @@ module Reek
|
|
90
82
|
|
91
83
|
#
|
92
84
|
# Checks a given directory for a configuration file and returns it.
|
93
|
-
# Raises an exception if we find more than one.
|
94
85
|
#
|
95
86
|
# @return [File|nil]
|
96
87
|
#
|
97
|
-
# :reek:FeatureEnvy
|
88
|
+
# @quality :reek:FeatureEnvy
|
98
89
|
def find_in_dir(dir)
|
99
|
-
|
100
|
-
if found.size > 1
|
101
|
-
escalate_too_many_configuration_files found, dir
|
102
|
-
else
|
103
|
-
found.first
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
#
|
108
|
-
# Writes a proper warning message to STDERR and then exits the program.
|
109
|
-
#
|
110
|
-
# @return [undefined]
|
111
|
-
#
|
112
|
-
def escalate_too_many_configuration_files(found, directory)
|
113
|
-
offensive_files = found.map { |file| "'#{file.basename}'" }.join(', ')
|
114
|
-
warn format(TOO_MANY_CONFIGURATION_FILES_MESSAGE, files: offensive_files, directory: directory)
|
115
|
-
exit 1
|
90
|
+
dir.children.detect { |item| item.file? && item.basename.to_s == DEFAULT_FILE_NAME }
|
116
91
|
end
|
117
92
|
end
|
118
93
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative '../errors/config_file_error'
|
4
|
+
|
3
5
|
module Reek
|
4
6
|
module Configuration
|
5
7
|
#
|
@@ -8,37 +10,24 @@ module Reek
|
|
8
10
|
module ConfigurationValidator
|
9
11
|
private
|
10
12
|
|
11
|
-
# :reek:UtilityFunction
|
13
|
+
# @quality :reek:UtilityFunction
|
12
14
|
def smell_type?(key)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
when String
|
17
|
-
begin
|
18
|
-
Reek::SmellDetectors.const_defined? key
|
19
|
-
rescue NameError
|
20
|
-
false
|
21
|
-
end
|
22
|
-
end
|
15
|
+
Reek::SmellDetectors.const_defined? key
|
16
|
+
rescue NameError
|
17
|
+
false
|
23
18
|
end
|
24
19
|
|
25
|
-
# :reek:UtilityFunction
|
20
|
+
# @quality :reek:UtilityFunction
|
26
21
|
def key_to_smell_detector(key)
|
27
|
-
|
28
|
-
when Class
|
29
|
-
key
|
30
|
-
else
|
31
|
-
Reek::SmellDetectors.const_get key
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def error_message_for_file_given(pathname)
|
36
|
-
"Configuration error: `#{pathname}` is supposed to be a directory but is a file"
|
22
|
+
Reek::SmellDetectors.const_get key
|
37
23
|
end
|
38
24
|
|
39
25
|
def with_valid_directory(path)
|
40
26
|
directory = Pathname.new path.to_s.chomp('/')
|
41
|
-
|
27
|
+
if directory.file?
|
28
|
+
raise Errors::ConfigFileError,
|
29
|
+
"`#{directory}` is supposed to be a directory but is a file"
|
30
|
+
end
|
42
31
|
yield directory if block_given?
|
43
32
|
end
|
44
33
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative './configuration_validator'
|
4
|
+
|
3
5
|
module Reek
|
4
6
|
module Configuration
|
5
7
|
#
|
@@ -8,9 +10,21 @@ module Reek
|
|
8
10
|
module DefaultDirective
|
9
11
|
include ConfigurationValidator
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
# Adds the configuration for detectors as default directive.
|
14
|
+
#
|
15
|
+
# @param detectors_configuration [Hash] the configuration e.g.:
|
16
|
+
# {
|
17
|
+
# :IrresponsibleModule => {:enabled=>false},
|
18
|
+
# :Attribute => {:enabled=>true}
|
19
|
+
# }
|
20
|
+
#
|
21
|
+
# @return [self]
|
22
|
+
def add(detectors_configuration)
|
23
|
+
detectors_configuration.each do |name, configuration|
|
24
|
+
detector = key_to_smell_detector(name)
|
25
|
+
self[detector] = (self[detector] || {}).merge configuration
|
26
|
+
end
|
27
|
+
self
|
14
28
|
end
|
15
29
|
end
|
16
30
|
end
|
@@ -24,17 +24,23 @@ module Reek
|
|
24
24
|
|
25
25
|
# Adds a directive and returns self.
|
26
26
|
#
|
27
|
-
# @param
|
28
|
-
#
|
27
|
+
# @param directory_config [Hash] the configuration e.g.:
|
28
|
+
# {
|
29
|
+
# "samples/two_smelly_files" => {:IrresponsibleModule=>{:enabled=>false}},
|
30
|
+
# "samples/three_clean_files" => {:Attribute=>{:enabled=>true}}
|
31
|
+
# }
|
29
32
|
#
|
30
33
|
# @return [self]
|
31
34
|
#
|
32
|
-
# :reek:NestedIterators
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
# @quality :reek:NestedIterators { max_allowed_nesting: 3 }
|
36
|
+
# @quality :reek:TooManyStatements { max_statements: 6 }
|
37
|
+
def add(directory_config)
|
38
|
+
directory_config.each do |path, detector_config|
|
39
|
+
with_valid_directory(path) do |directory|
|
40
|
+
self[directory] = detector_config.each_with_object({}) do |(key, value), hash|
|
41
|
+
abort(error_message_for_invalid_smell_type(key)) unless smell_type?(key)
|
42
|
+
hash[key_to_smell_detector(key)] = value
|
43
|
+
end
|
38
44
|
end
|
39
45
|
end
|
40
46
|
self
|
@@ -42,8 +48,8 @@ module Reek
|
|
42
48
|
|
43
49
|
private
|
44
50
|
|
45
|
-
# :reek:DuplicateMethodCall
|
46
|
-
# :reek:FeatureEnvy
|
51
|
+
# @quality :reek:DuplicateMethodCall { max_calls: 2 }
|
52
|
+
# @quality :reek:FeatureEnvy
|
47
53
|
def best_match_for(source_base_dir)
|
48
54
|
keys.
|
49
55
|
select { |pathname| source_base_dir.to_s.match(/#{Regexp.escape(pathname.to_s)}/) }.
|
@@ -52,7 +58,7 @@ module Reek
|
|
52
58
|
|
53
59
|
def error_message_for_invalid_smell_type(klass)
|
54
60
|
"You are trying to configure smell type #{klass} but we can't find one with that name.\n" \
|
55
|
-
"Please make sure you spelled it right. (See 'defaults.reek' in the Reek\n" \
|
61
|
+
"Please make sure you spelled it right. (See 'docs/defaults.reek' in the Reek\n" \
|
56
62
|
'repository for a list of all available smell types.)'
|
57
63
|
end
|
58
64
|
end
|