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
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Reek
|
4
|
+
module Report
|
5
|
+
module ProgressFormatter
|
6
|
+
#
|
7
|
+
# Base class for progress formatters.
|
8
|
+
# Is responsible for formatting the progress emitted for each examiner
|
9
|
+
#
|
10
|
+
# @abstract Override {#header, #progress, #footer} to implement a progress formatter.
|
11
|
+
class Base
|
12
|
+
attr_reader :sources_count
|
13
|
+
|
14
|
+
def initialize(sources_count)
|
15
|
+
@sources_count = sources_count
|
16
|
+
end
|
17
|
+
|
18
|
+
def header
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
|
22
|
+
def progress(_examiner)
|
23
|
+
raise NotImplementedError
|
24
|
+
end
|
25
|
+
|
26
|
+
def footer
|
27
|
+
raise NotImplementedError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# Shows the status of each source as either a dot (.) or an S
|
33
|
+
#
|
34
|
+
class Dots < Base
|
35
|
+
NO_WARNINGS_COLOR = :green
|
36
|
+
WARNINGS_COLOR = :red
|
37
|
+
|
38
|
+
def header
|
39
|
+
"Inspecting #{sources_count} file(s):\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
def progress(examiner)
|
43
|
+
examiner.smelly? ? display_smelly : display_clean
|
44
|
+
end
|
45
|
+
|
46
|
+
def footer
|
47
|
+
"\n\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def display_clean
|
53
|
+
Rainbow('.').color(NO_WARNINGS_COLOR)
|
54
|
+
end
|
55
|
+
|
56
|
+
def display_smelly
|
57
|
+
Rainbow('S').color(WARNINGS_COLOR)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Does not show progress
|
63
|
+
#
|
64
|
+
class Quiet < Base
|
65
|
+
def header
|
66
|
+
''
|
67
|
+
end
|
68
|
+
|
69
|
+
def progress(_examiner)
|
70
|
+
''
|
71
|
+
end
|
72
|
+
|
73
|
+
def footer
|
74
|
+
''
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'code_climate/code_climate_formatter'
|
4
|
+
|
5
|
+
module Reek
|
6
|
+
module Report
|
7
|
+
#
|
8
|
+
# Basic formatter that just shows a simple message for each warning,
|
9
|
+
# prepended with the result of the passed-in location formatter.
|
10
|
+
#
|
11
|
+
class SimpleWarningFormatter
|
12
|
+
def initialize(location_formatter: BlankLocationFormatter)
|
13
|
+
@location_formatter = location_formatter
|
14
|
+
end
|
15
|
+
|
16
|
+
def format(warning)
|
17
|
+
"#{location_formatter.format(warning)}#{warning.base_message}"
|
18
|
+
end
|
19
|
+
|
20
|
+
# @quality :reek:UtilityFunction
|
21
|
+
def format_code_climate_hash(warning)
|
22
|
+
CodeClimateFormatter.new(warning).render
|
23
|
+
end
|
24
|
+
|
25
|
+
def format_list(warnings)
|
26
|
+
warnings.map { |warning| " #{format(warning)}" }.join("\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :location_formatter
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -49,8 +49,7 @@ module Reek
|
|
49
49
|
def summarize_single_examiner(examiner)
|
50
50
|
result = heading_formatter.header(examiner)
|
51
51
|
if examiner.smelly?
|
52
|
-
formatted_list =
|
53
|
-
formatter: warning_formatter)
|
52
|
+
formatted_list = warning_formatter.format_list(examiner.smells)
|
54
53
|
result += ":\n#{formatted_list}"
|
55
54
|
end
|
56
55
|
result
|
@@ -34,8 +34,8 @@ module Reek
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
# :reek:FeatureEnvy
|
38
|
-
# :reek:NestedIterators
|
37
|
+
# @quality :reek:FeatureEnvy
|
38
|
+
# @quality :reek:NestedIterators { max_allowed_nesting: 2 }
|
39
39
|
def file(name, smells)
|
40
40
|
REXML::Element.new('file').tap do |file|
|
41
41
|
file.add_attribute 'name', File.realpath(name)
|
@@ -47,7 +47,7 @@ module Reek
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
# :reek:UtilityFunction
|
50
|
+
# @quality :reek:UtilityFunction
|
51
51
|
def error(smell, line)
|
52
52
|
REXML::Element.new('error').tap do |error|
|
53
53
|
error.add_attributes 'column' => 0,
|
@@ -7,11 +7,11 @@ module Reek
|
|
7
7
|
class SmellConfiguration
|
8
8
|
# The name of the config field that specifies whether a smell is
|
9
9
|
# enabled. Set to +true+ or +false+.
|
10
|
-
ENABLED_KEY = 'enabled'
|
10
|
+
ENABLED_KEY = 'enabled'
|
11
11
|
|
12
12
|
# The name of the config field that sets scope-specific overrides
|
13
13
|
# for other values in the current smell detector's configuration.
|
14
|
-
OVERRIDES_KEY = 'overrides'
|
14
|
+
OVERRIDES_KEY = 'overrides'
|
15
15
|
|
16
16
|
def initialize(hash)
|
17
17
|
@options = hash
|
data/lib/reek/smell_detectors.rb
CHANGED
@@ -15,10 +15,9 @@ require_relative 'smell_detectors/manual_dispatch'
|
|
15
15
|
require_relative 'smell_detectors/module_initialize'
|
16
16
|
require_relative 'smell_detectors/nested_iterators'
|
17
17
|
require_relative 'smell_detectors/nil_check'
|
18
|
-
require_relative 'smell_detectors/
|
18
|
+
require_relative 'smell_detectors/missing_safe_method'
|
19
19
|
require_relative 'smell_detectors/repeated_conditional'
|
20
20
|
require_relative 'smell_detectors/subclassed_from_core_class'
|
21
|
-
require_relative 'smell_detectors/syntax'
|
22
21
|
require_relative 'smell_detectors/too_many_instance_variables'
|
23
22
|
require_relative 'smell_detectors/too_many_constants'
|
24
23
|
require_relative 'smell_detectors/too_many_methods'
|
@@ -15,14 +15,14 @@ module Reek
|
|
15
15
|
# - {file:README.md}
|
16
16
|
# for details.
|
17
17
|
#
|
18
|
-
# :reek:UnusedPrivateMethod
|
19
|
-
# :reek:TooManyMethods
|
18
|
+
# @quality :reek:UnusedPrivateMethod { exclude: [ smell_warning ] }
|
19
|
+
# @quality :reek:TooManyMethods { max_methods: 18 }
|
20
20
|
class BaseDetector
|
21
21
|
attr_reader :config
|
22
22
|
# The name of the config field that lists the names of code contexts
|
23
23
|
# that should not be checked. Add this field to the config for each
|
24
24
|
# smell that should ignore this code element.
|
25
|
-
EXCLUDE_KEY = 'exclude'
|
25
|
+
EXCLUDE_KEY = 'exclude'
|
26
26
|
|
27
27
|
# The default value for the +EXCLUDE_KEY+ if it isn't specified
|
28
28
|
# in any configuration file.
|
@@ -78,12 +78,9 @@ module Reek
|
|
78
78
|
ctx.config_for(self.class)
|
79
79
|
end
|
80
80
|
|
81
|
-
|
82
|
-
def smell_warning(options = {})
|
83
|
-
context = options.fetch(:context)
|
84
|
-
exp = context.exp
|
81
|
+
def smell_warning(**options)
|
85
82
|
SmellWarning.new(self,
|
86
|
-
source:
|
83
|
+
source: expression.source,
|
87
84
|
context: context.full_name,
|
88
85
|
lines: options.fetch(:lines),
|
89
86
|
message: options.fetch(:message),
|
@@ -99,7 +96,7 @@ module Reek
|
|
99
96
|
[:def, :defs]
|
100
97
|
end
|
101
98
|
|
102
|
-
# :reek:UtilityFunction
|
99
|
+
# @quality :reek:UtilityFunction
|
103
100
|
def default_config
|
104
101
|
{
|
105
102
|
SmellConfiguration::ENABLED_KEY => true,
|
@@ -138,14 +135,14 @@ module Reek
|
|
138
135
|
# Note that we assume a valid name - exceptions are not handled here.
|
139
136
|
#
|
140
137
|
# @param detector_name [String] the detector in question, e.g. 'DuplicateMethodCall'
|
141
|
-
# @return [SmellDetector]
|
138
|
+
# @return [SmellDetector] this will return the class, not an instance
|
142
139
|
#
|
143
140
|
def to_detector(detector_name)
|
144
141
|
SmellDetectors.const_get detector_name
|
145
142
|
end
|
146
143
|
|
147
144
|
#
|
148
|
-
# @return [Set<Symbol>]
|
145
|
+
# @return [Set<Symbol>] all configuration keys that are available for this detector
|
149
146
|
#
|
150
147
|
def configuration_keys
|
151
148
|
Set.new(default_config.keys.map(&:to_sym))
|
@@ -49,18 +49,32 @@ module Reek
|
|
49
49
|
#
|
50
50
|
# @return [Array<SmellWarning>]
|
51
51
|
#
|
52
|
-
# :reek:FeatureEnvy
|
53
52
|
def sniff
|
54
|
-
|
53
|
+
control_parameters.map do |control_parameter|
|
55
54
|
argument = control_parameter.name.to_s
|
56
55
|
smell_warning(
|
57
|
-
context: context,
|
58
56
|
lines: control_parameter.lines,
|
59
57
|
message: "is controlled by argument '#{argument}'",
|
60
58
|
parameters: { argument: argument })
|
61
59
|
end
|
62
60
|
end
|
63
61
|
|
62
|
+
private
|
63
|
+
|
64
|
+
def control_parameters
|
65
|
+
potential_parameters.
|
66
|
+
map { |param| FoundControlParameter.new(param, find_matches(param)) }.
|
67
|
+
select(&:smells?)
|
68
|
+
end
|
69
|
+
|
70
|
+
def potential_parameters
|
71
|
+
expression.parameter_names
|
72
|
+
end
|
73
|
+
|
74
|
+
def find_matches(param)
|
75
|
+
ControlParameterFinder.new(expression, param).find_matches
|
76
|
+
end
|
77
|
+
|
64
78
|
#
|
65
79
|
# Collects information about a single control parameter.
|
66
80
|
#
|
@@ -166,35 +180,6 @@ module Reek
|
|
166
180
|
end
|
167
181
|
|
168
182
|
private_constant :ControlParameterFinder
|
169
|
-
|
170
|
-
#
|
171
|
-
# Collects all control parameters in a given context.
|
172
|
-
#
|
173
|
-
class ControlParameterCollector
|
174
|
-
def initialize(context)
|
175
|
-
@context = context
|
176
|
-
end
|
177
|
-
|
178
|
-
def control_parameters
|
179
|
-
potential_parameters.
|
180
|
-
map { |param| FoundControlParameter.new(param, find_matches(param)) }.
|
181
|
-
select(&:smells?)
|
182
|
-
end
|
183
|
-
|
184
|
-
private
|
185
|
-
|
186
|
-
attr_reader :context
|
187
|
-
|
188
|
-
def potential_parameters
|
189
|
-
context.exp.parameter_names
|
190
|
-
end
|
191
|
-
|
192
|
-
def find_matches(param)
|
193
|
-
ControlParameterFinder.new(context.exp, param).find_matches
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
private_constant :ControlParameterCollector
|
198
183
|
end
|
199
184
|
end
|
200
185
|
end
|
@@ -24,7 +24,7 @@ module Reek
|
|
24
24
|
# reported as a DataClump unless there are more than this many
|
25
25
|
# methods containing those parameters.
|
26
26
|
#
|
27
|
-
MAX_COPIES_KEY = 'max_copies'
|
27
|
+
MAX_COPIES_KEY = 'max_copies'
|
28
28
|
DEFAULT_MAX_COPIES = 2
|
29
29
|
|
30
30
|
#
|
@@ -32,7 +32,7 @@ module Reek
|
|
32
32
|
# size. No group of common parameters will be reported as
|
33
33
|
# a DataClump unless it contains at least this many parameters.
|
34
34
|
#
|
35
|
-
MIN_CLUMP_SIZE_KEY = 'min_clump_size'
|
35
|
+
MIN_CLUMP_SIZE_KEY = 'min_clump_size'
|
36
36
|
DEFAULT_MIN_CLUMP_SIZE = 2
|
37
37
|
|
38
38
|
def self.contexts # :nodoc:
|
@@ -54,7 +54,6 @@ module Reek
|
|
54
54
|
MethodGroup.new(context, min_clump_size, max_copies).clumps.map do |clump, methods|
|
55
55
|
methods_length = methods.length
|
56
56
|
smell_warning(
|
57
|
-
context: context,
|
58
57
|
lines: methods.map(&:line),
|
59
58
|
message: "takes parameters #{DataClump.print_clump(clump)} " \
|
60
59
|
"to #{methods_length} methods",
|
@@ -101,7 +100,7 @@ module Reek
|
|
101
100
|
end.uniq
|
102
101
|
end
|
103
102
|
|
104
|
-
# :reek:UtilityFunction
|
103
|
+
# @quality :reek:UtilityFunction
|
105
104
|
def common_argument_names_for(methods)
|
106
105
|
methods.map(&:arg_names).inject(:&)
|
107
106
|
end
|
@@ -21,13 +21,13 @@ module Reek
|
|
21
21
|
class DuplicateMethodCall < BaseDetector
|
22
22
|
# The name of the config field that sets the maximum number of
|
23
23
|
# identical calls to be permitted within any single method.
|
24
|
-
MAX_ALLOWED_CALLS_KEY = 'max_calls'
|
24
|
+
MAX_ALLOWED_CALLS_KEY = 'max_calls'
|
25
25
|
DEFAULT_MAX_CALLS = 1
|
26
26
|
|
27
27
|
# The name of the config field that sets the names of any
|
28
28
|
# methods for which identical calls should be to be permitted
|
29
29
|
# within any single method.
|
30
|
-
ALLOW_CALLS_KEY = 'allow_calls'
|
30
|
+
ALLOW_CALLS_KEY = 'allow_calls'
|
31
31
|
DEFAULT_ALLOW_CALLS = [].freeze
|
32
32
|
|
33
33
|
def self.default_config
|
@@ -47,7 +47,6 @@ module Reek
|
|
47
47
|
call = found_call.call
|
48
48
|
occurs = found_call.occurs
|
49
49
|
smell_warning(
|
50
|
-
context: context,
|
51
50
|
lines: found_call.lines,
|
52
51
|
message: "calls '#{call}' #{occurs} times",
|
53
52
|
parameters: { name: call, count: occurs })
|
@@ -118,8 +117,8 @@ module Reek
|
|
118
117
|
|
119
118
|
attr_reader :allow_calls, :max_allowed_calls
|
120
119
|
|
121
|
-
# :reek:TooManyStatements
|
122
|
-
# :reek:DuplicateMethodCall
|
120
|
+
# @quality :reek:TooManyStatements { max_statements: 6 }
|
121
|
+
# @quality :reek:DuplicateMethodCall { max_calls: 2 }
|
123
122
|
def collect_calls(result)
|
124
123
|
context.local_nodes(:send, [:mlhs]) do |call_node|
|
125
124
|
next if call_node.object_creation_call?
|
@@ -135,7 +134,7 @@ module Reek
|
|
135
134
|
found_call.occurs > max_allowed_calls && !allow_calls?(found_call.call)
|
136
135
|
end
|
137
136
|
|
138
|
-
# :reek:UtilityFunction
|
137
|
+
# @quality :reek:UtilityFunction
|
139
138
|
def simple_method_call?(call_node)
|
140
139
|
!call_node.receiver && call_node.args.empty?
|
141
140
|
end
|
@@ -47,7 +47,6 @@ module Reek
|
|
47
47
|
return [] unless context.references_self?
|
48
48
|
envious_receivers.map do |name, lines|
|
49
49
|
smell_warning(
|
50
|
-
context: context,
|
51
50
|
lines: lines,
|
52
51
|
message: "refers to '#{name}' more than self (maybe move it to another class?)",
|
53
52
|
parameters: { name: name.to_s })
|