reek 5.6.0 → 6.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +9 -0
- data/.github/workflows/ruby.yml +52 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +3 -1
- data/.rubocop_todo.yml +27 -20
- data/.simplecov +1 -0
- data/CHANGELOG.md +29 -0
- data/CONTRIBUTING.md +3 -0
- data/Dockerfile +2 -1
- data/Gemfile +14 -17
- data/README.md +11 -11
- data/bin/code_climate_reek +12 -2
- data/lib/reek.rb +1 -0
- data/lib/reek/ast/ast_node_class_map.rb +1 -1
- data/lib/reek/ast/node.rb +1 -1
- data/lib/reek/ast/sexp_extensions/arguments.rb +11 -0
- data/lib/reek/cli/options.rb +3 -3
- data/lib/reek/code_comment.rb +36 -29
- data/lib/reek/configuration/app_configuration.rb +4 -3
- data/lib/reek/configuration/configuration_converter.rb +2 -2
- data/lib/reek/configuration/directory_directives.rb +9 -3
- data/lib/reek/configuration/excluded_paths.rb +2 -1
- data/lib/reek/context/code_context.rb +1 -1
- data/lib/reek/context/module_context.rb +3 -1
- data/lib/reek/context/refinement_context.rb +16 -0
- data/lib/reek/context_builder.rb +16 -2
- data/lib/reek/errors/legacy_comment_separator_error.rb +36 -0
- data/lib/reek/report.rb +5 -7
- data/lib/reek/report/code_climate/code_climate_configuration.yml +1 -1
- data/lib/reek/report/code_climate/code_climate_formatter.rb +1 -3
- data/lib/reek/report/code_climate/code_climate_report.rb +2 -1
- data/lib/reek/report/simple_warning_formatter.rb +0 -7
- data/lib/reek/smell_detectors/base_detector.rb +2 -10
- data/lib/reek/smell_detectors/boolean_parameter.rb +3 -1
- data/lib/reek/smell_detectors/data_clump.rb +23 -56
- data/lib/reek/smell_detectors/nil_check.rb +1 -12
- data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +1 -1
- data/lib/reek/smell_warning.rb +2 -3
- data/lib/reek/source/source_locator.rb +14 -13
- data/lib/reek/spec/smell_matcher.rb +2 -1
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +17 -7
- metadata +23 -246
- data/.travis.yml +0 -35
- data/docs/API.md +0 -174
- data/docs/Attribute.md +0 -39
- data/docs/Basic-Smell-Options.md +0 -85
- data/docs/Boolean-Parameter.md +0 -54
- data/docs/Class-Variable.md +0 -40
- data/docs/Code-Smells.md +0 -39
- data/docs/Command-Line-Options.md +0 -119
- data/docs/Control-Couple.md +0 -26
- data/docs/Control-Parameter.md +0 -32
- data/docs/Data-Clump.md +0 -46
- data/docs/Duplicate-Method-Call.md +0 -264
- data/docs/Feature-Envy.md +0 -93
- data/docs/How-To-Write-New-Detectors.md +0 -132
- data/docs/How-reek-works-internally.md +0 -114
- data/docs/Instance-Variable-Assumption.md +0 -163
- data/docs/Irresponsible-Module.md +0 -47
- data/docs/Large-Class.md +0 -16
- data/docs/Long-Parameter-List.md +0 -39
- data/docs/Long-Yield-List.md +0 -37
- data/docs/Manual-Dispatch.md +0 -30
- data/docs/Missing-Safe-Method.md +0 -92
- data/docs/Module-Initialize.md +0 -62
- data/docs/Nested-Iterators.md +0 -59
- data/docs/Nil-Check.md +0 -44
- data/docs/RSpec-matchers.md +0 -129
- data/docs/Rake-Task.md +0 -66
- data/docs/Reek-4-to-Reek-5-migration.md +0 -188
- data/docs/Reek-Driven-Development.md +0 -46
- data/docs/Repeated-Conditional.md +0 -47
- data/docs/Simulated-Polymorphism.md +0 -16
- data/docs/Smell-Suppression.md +0 -96
- data/docs/Style-Guide.md +0 -19
- data/docs/Subclassed-From-Core-Class.md +0 -79
- data/docs/Too-Many-Constants.md +0 -37
- data/docs/Too-Many-Instance-Variables.md +0 -43
- data/docs/Too-Many-Methods.md +0 -56
- data/docs/Too-Many-Statements.md +0 -54
- data/docs/Uncommunicative-Method-Name.md +0 -94
- data/docs/Uncommunicative-Module-Name.md +0 -92
- data/docs/Uncommunicative-Name.md +0 -18
- data/docs/Uncommunicative-Parameter-Name.md +0 -90
- data/docs/Uncommunicative-Variable-Name.md +0 -96
- data/docs/Unused-Parameters.md +0 -28
- data/docs/Unused-Private-Method.md +0 -101
- data/docs/Utility-Function.md +0 -56
- data/docs/Versioning-Policy.md +0 -7
- data/docs/YAML-Reports.md +0 -93
- data/docs/defaults.reek.yml +0 -129
- data/docs/templates/default/docstring/html/public_api_marker.erb +0 -3
- data/docs/templates/default/docstring/setup.rb +0 -37
- data/docs/templates/default/fulldoc/html/css/common.css +0 -1
- data/docs/yard_plugin.rb +0 -17
- data/features/command_line_interface/basic_usage.feature +0 -15
- data/features/command_line_interface/options.feature +0 -124
- data/features/command_line_interface/show_progress.feature +0 -33
- data/features/command_line_interface/smell_selection.feature +0 -15
- data/features/command_line_interface/smells_count.feature +0 -38
- data/features/command_line_interface/stdin.feature +0 -65
- data/features/configuration_files/accept_setting.feature +0 -87
- data/features/configuration_files/directory_specific_directives.feature +0 -274
- data/features/configuration_files/exclude_directives.feature +0 -35
- data/features/configuration_files/exclude_paths_directives.feature +0 -42
- data/features/configuration_files/masking_smells.feature +0 -94
- data/features/configuration_files/mix_accept_reject_setting.feature +0 -84
- data/features/configuration_files/reject_setting.feature +0 -89
- data/features/configuration_files/schema_validation.feature +0 -59
- data/features/configuration_files/show_configuration_file.feature +0 -44
- data/features/configuration_files/unused_private_method.feature +0 -68
- data/features/configuration_loading.feature +0 -91
- data/features/configuration_via_source_comments/erroneous_source_comments.feature +0 -68
- data/features/configuration_via_source_comments/well_formed_source_comments.feature +0 -116
- data/features/locales.feature +0 -32
- data/features/programmatic_access.feature +0 -41
- data/features/rake_task/rake_task.feature +0 -138
- data/features/reports/codeclimate.feature +0 -59
- data/features/reports/json.feature +0 -59
- data/features/reports/reports.feature +0 -219
- data/features/reports/yaml.feature +0 -52
- data/features/rspec_matcher.feature +0 -41
- data/features/samples.feature +0 -305
- data/features/step_definitions/.rubocop.yml +0 -5
- data/features/step_definitions/reek_steps.rb +0 -98
- data/features/step_definitions/sample_file_steps.rb +0 -63
- data/features/support/env.rb +0 -34
- data/features/todo_list.feature +0 -108
- data/samples/checkstyle.xml +0 -7
- data/samples/clean_source/clean.rb +0 -6
- data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +0 -29
- data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +0 -30
- data/samples/configuration/corrupt.reek +0 -1
- data/samples/configuration/empty.reek +0 -0
- data/samples/configuration/full_configuration.reek +0 -13
- data/samples/configuration/full_mask.reek +0 -6
- data/samples/configuration/home/home.reek.yml +0 -4
- data/samples/configuration/partial_mask.reek +0 -4
- data/samples/configuration/regular_configuration/.reek.yml +0 -4
- data/samples/configuration/regular_configuration/empty_sub_directory/.gitignore +0 -0
- data/samples/configuration/with_excluded_paths.reek +0 -5
- data/samples/no_config_file/.keep +0 -0
- data/samples/paths.rb +0 -5
- data/samples/smelly_source/inline.rb +0 -704
- data/samples/smelly_source/optparse.rb +0 -1788
- data/samples/smelly_source/redcloth.rb +0 -1130
- data/samples/smelly_source/ruby.rb +0 -368
- data/samples/smelly_source/smelly.rb +0 -7
- data/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +0 -5
- data/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +0 -2
- data/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +0 -6
- data/samples/source_with_exclude_paths/nested/uncommunicative_variable_name.rb +0 -6
- data/samples/source_with_hidden_directories/.hidden/hidden.rb +0 -1
- data/samples/source_with_hidden_directories/not_hidden.rb +0 -1
- data/samples/source_with_non_ruby_files/gibberish +0 -1
- data/samples/source_with_non_ruby_files/python_source.py +0 -1
- data/samples/source_with_non_ruby_files/ruby.rb +0 -6
- data/spec/factories/factories.rb +0 -37
- data/spec/performance/reek/smell_detectors/runtime_speed_spec.rb +0 -17
- data/spec/quality/documentation_spec.rb +0 -40
- data/spec/quality/reek_source_spec.rb +0 -11
- data/spec/reek/ast/node_spec.rb +0 -211
- data/spec/reek/ast/object_refs_spec.rb +0 -83
- data/spec/reek/ast/reference_collector_spec.rb +0 -47
- data/spec/reek/ast/sexp_extensions_spec.rb +0 -516
- data/spec/reek/cli/application_spec.rb +0 -168
- data/spec/reek/cli/command/report_command_spec.rb +0 -44
- data/spec/reek/cli/command/todo_list_command_spec.rb +0 -86
- data/spec/reek/cli/options_spec.rb +0 -51
- data/spec/reek/cli/silencer_spec.rb +0 -28
- data/spec/reek/code_comment_spec.rb +0 -185
- data/spec/reek/configuration/app_configuration_spec.rb +0 -195
- data/spec/reek/configuration/configuration_file_finder_spec.rb +0 -230
- data/spec/reek/configuration/default_directive_spec.rb +0 -13
- data/spec/reek/configuration/directory_directives_spec.rb +0 -116
- data/spec/reek/configuration/excluded_paths_spec.rb +0 -16
- data/spec/reek/configuration/rake_task_converter_spec.rb +0 -33
- data/spec/reek/configuration/schema_validator_spec.rb +0 -165
- data/spec/reek/context/code_context_spec.rb +0 -192
- data/spec/reek/context/ghost_context_spec.rb +0 -60
- data/spec/reek/context/method_context_spec.rb +0 -72
- data/spec/reek/context/module_context_spec.rb +0 -55
- data/spec/reek/context/root_context_spec.rb +0 -12
- data/spec/reek/context/statement_counter_spec.rb +0 -24
- data/spec/reek/context_builder_spec.rb +0 -460
- data/spec/reek/detector_repository_spec.rb +0 -22
- data/spec/reek/documentation_link_spec.rb +0 -20
- data/spec/reek/errors/base_error_spec.rb +0 -13
- data/spec/reek/examiner_spec.rb +0 -309
- data/spec/reek/logging_error_handler_spec.rb +0 -24
- data/spec/reek/rake/task_spec.rb +0 -56
- data/spec/reek/report/code_climate/code_climate_configuration_spec.rb +0 -24
- data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +0 -126
- data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +0 -51
- data/spec/reek/report/code_climate/code_climate_report_spec.rb +0 -56
- data/spec/reek/report/html_report_spec.rb +0 -19
- data/spec/reek/report/json_report_spec.rb +0 -58
- data/spec/reek/report/location_formatter_spec.rb +0 -32
- data/spec/reek/report/progress_formatter_spec.rb +0 -68
- data/spec/reek/report/text_report_spec.rb +0 -89
- data/spec/reek/report/xml_report_spec.rb +0 -24
- data/spec/reek/report/yaml_report_spec.rb +0 -55
- data/spec/reek/report_spec.rb +0 -28
- data/spec/reek/smell_configuration_spec.rb +0 -56
- data/spec/reek/smell_detectors/attribute_spec.rb +0 -197
- data/spec/reek/smell_detectors/base_detector_spec.rb +0 -60
- data/spec/reek/smell_detectors/boolean_parameter_spec.rb +0 -93
- data/spec/reek/smell_detectors/class_variable_spec.rb +0 -106
- data/spec/reek/smell_detectors/control_parameter_spec.rb +0 -300
- data/spec/reek/smell_detectors/data_clump_spec.rb +0 -120
- data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +0 -211
- data/spec/reek/smell_detectors/feature_envy_spec.rb +0 -295
- data/spec/reek/smell_detectors/instance_variable_assumption_spec.rb +0 -96
- data/spec/reek/smell_detectors/irresponsible_module_spec.rb +0 -226
- data/spec/reek/smell_detectors/long_parameter_list_spec.rb +0 -61
- data/spec/reek/smell_detectors/long_yield_list_spec.rb +0 -49
- data/spec/reek/smell_detectors/manual_dispatch_spec.rb +0 -75
- data/spec/reek/smell_detectors/missing_safe_method_spec.rb +0 -62
- data/spec/reek/smell_detectors/module_initialize_spec.rb +0 -77
- data/spec/reek/smell_detectors/nested_iterators_spec.rb +0 -333
- data/spec/reek/smell_detectors/nil_check_spec.rb +0 -100
- data/spec/reek/smell_detectors/repeated_conditional_spec.rb +0 -100
- data/spec/reek/smell_detectors/subclassed_from_core_class_spec.rb +0 -77
- data/spec/reek/smell_detectors/too_many_constants_spec.rb +0 -144
- data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +0 -132
- data/spec/reek/smell_detectors/too_many_methods_spec.rb +0 -54
- data/spec/reek/smell_detectors/too_many_statements_spec.rb +0 -90
- data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +0 -78
- data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +0 -78
- data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +0 -147
- data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +0 -201
- data/spec/reek/smell_detectors/unused_parameters_spec.rb +0 -114
- data/spec/reek/smell_detectors/unused_private_method_spec.rb +0 -205
- data/spec/reek/smell_detectors/utility_function_spec.rb +0 -293
- data/spec/reek/smell_warning_spec.rb +0 -137
- data/spec/reek/source/source_code_spec.rb +0 -66
- data/spec/reek/source/source_locator_spec.rb +0 -166
- data/spec/reek/spec/should_reek_of_spec.rb +0 -154
- data/spec/reek/spec/should_reek_only_of_spec.rb +0 -91
- data/spec/reek/spec/should_reek_spec.rb +0 -52
- data/spec/reek/spec/smell_matcher_spec.rb +0 -87
- data/spec/reek/tree_dresser_spec.rb +0 -46
- data/spec/spec_helper.rb +0 -96
- data/tasks/configuration.rake +0 -19
- data/tasks/console.rake +0 -5
- data/tasks/reek.rake +0 -6
- data/tasks/rubocop.rake +0 -11
- data/tasks/test.rake +0 -32
@@ -1,119 +0,0 @@
|
|
1
|
-
# Command Line Options
|
2
|
-
|
3
|
-
## Introduction
|
4
|
-
|
5
|
-
Reek follows standard Unix convention for passing arguments.
|
6
|
-
|
7
|
-
Check out
|
8
|
-
|
9
|
-
```Bash
|
10
|
-
reek -h
|
11
|
-
```
|
12
|
-
|
13
|
-
for details.
|
14
|
-
|
15
|
-
## Telling Reek to use a specific configuration file
|
16
|
-
|
17
|
-
In case your configuration file is not in the standard location (that would be your project directory or
|
18
|
-
whatever directory you're running Reek from) you can specify a configuration file with the `-c` option
|
19
|
-
like this:
|
20
|
-
|
21
|
-
```Bash
|
22
|
-
reek -c /somewhere/on/your/filesystem/reek_config.yml lib/
|
23
|
-
```
|
24
|
-
|
25
|
-
## Telling Reek Which Code to Check
|
26
|
-
|
27
|
-
Probably the most standard use case would be to check all Ruby files in the lib directory:
|
28
|
-
|
29
|
-
```Bash
|
30
|
-
reek lib/*.rb
|
31
|
-
```
|
32
|
-
|
33
|
-
In general, if any command-line argument is a directory, Reek searches that directory and all sub-directories for Ruby source files. Thus
|
34
|
-
|
35
|
-
```Bash
|
36
|
-
reek lib
|
37
|
-
```
|
38
|
-
|
39
|
-
would be equivalent to
|
40
|
-
|
41
|
-
```Bash
|
42
|
-
reek lib/**/*.rb
|
43
|
-
```
|
44
|
-
|
45
|
-
Occasionally you may want to quickly check a code snippet without going to the trouble of creating a file to hold it. You can pass the snippet directly to Reek's standard input:
|
46
|
-
|
47
|
-
```Bash
|
48
|
-
echo "def x() true end" | reek
|
49
|
-
```
|
50
|
-
|
51
|
-
To just check all Ruby files in the current directory, you can simply run it
|
52
|
-
with no parameters:
|
53
|
-
|
54
|
-
```Bash
|
55
|
-
reek
|
56
|
-
```
|
57
|
-
|
58
|
-
## Telling Reek Which Smells to Detect
|
59
|
-
|
60
|
-
You can tell Reek to only check particular smells by using the `--smell`
|
61
|
-
option and passing in the smell name.
|
62
|
-
|
63
|
-
For example, to only check for [Utility Function](Utility-Function.md), you
|
64
|
-
would use:
|
65
|
-
|
66
|
-
```Bash
|
67
|
-
reek --smell UtilityFunction
|
68
|
-
```
|
69
|
-
|
70
|
-
You can select several smells by repeating the `--smell` option like so:
|
71
|
-
|
72
|
-
```Bash
|
73
|
-
reek --smell UtilityFunction --smell UncommunicativeMethodName
|
74
|
-
```
|
75
|
-
|
76
|
-
## Output options
|
77
|
-
|
78
|
-
### Output smell's line number
|
79
|
-
|
80
|
-
By passing in a "-n" flag to the _reek_ command, the output will suppress the line numbers:
|
81
|
-
|
82
|
-
```Bash
|
83
|
-
$ reek -n mess.rb
|
84
|
-
```
|
85
|
-
|
86
|
-
```
|
87
|
-
mess.rb -- 2 warnings:
|
88
|
-
x doesn't depend on instance state (UtilityFunction)
|
89
|
-
x has the name 'x' (UncommunicativeMethodName)
|
90
|
-
```
|
91
|
-
|
92
|
-
Otherwise line numbers will be shown as default at the beginning of each warning in square brackets:
|
93
|
-
|
94
|
-
```Bash
|
95
|
-
$ reek mess.rb
|
96
|
-
```
|
97
|
-
|
98
|
-
```
|
99
|
-
mess.rb -- 2 warnings:
|
100
|
-
[2]:x doesn't depend on instance state (UtilityFunction)
|
101
|
-
[2]:x has the name 'x' (UncommunicativeMethodName)
|
102
|
-
```
|
103
|
-
|
104
|
-
### Enable the verbose mode
|
105
|
-
|
106
|
-
_reek_ has a verbose mode which you might find helpful as a beginner. "verbose" just means that behind each warning a helpful link will be displayed which leads directly to the corresponding _reek_ documentation page.
|
107
|
-
This mode can be enabled via the "-U" or "--documentation" flag.
|
108
|
-
|
109
|
-
So for instance, if your test file would smell of _ClassVariable_, this is what the _reek_ output would look like:
|
110
|
-
|
111
|
-
```Bash
|
112
|
-
reek -U test.rb
|
113
|
-
```
|
114
|
-
```
|
115
|
-
test.rb -- 1 warning:
|
116
|
-
[2]:Dummy declares the class variable @@class_variable (ClassVariable) [https://github.com/troessner/reek/blob/master/docs/Class-Variable.md]
|
117
|
-
```
|
118
|
-
|
119
|
-
Note the link at the end.
|
data/docs/Control-Couple.md
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
# Control Couple
|
2
|
-
|
3
|
-
## Introduction
|
4
|
-
|
5
|
-
Control coupling occurs when a method or block checks the value of a parameter
|
6
|
-
in order to decide which execution path to take. The offending parameter is
|
7
|
-
often called a _Control Couple_.
|
8
|
-
|
9
|
-
Control Coupling is a kind of duplication, because the calling method already knows which path should be taken.
|
10
|
-
|
11
|
-
Control Coupling reduces the code's flexibility by creating a dependency
|
12
|
-
between the caller and callee: any change to the possible values of the
|
13
|
-
controlling parameter must be reflected on both sides of the call. A _Control
|
14
|
-
Couple_ also reveals a loss of simplicity: the called method probably has more
|
15
|
-
than one responsibility, because it includes at least two different code paths.
|
16
|
-
|
17
|
-
You can find a good write-up regarding this problem [here](http://solnic.eu/2012/04/11/get-rid-of-that-code-smell-control-couple.html).
|
18
|
-
|
19
|
-
## Current Support in Reek
|
20
|
-
|
21
|
-
Reek performs the following checks that fall in this category:
|
22
|
-
|
23
|
-
* [Control-Parameter](Control-Parameter.md) - a method parameter or block
|
24
|
-
parameter is the tested value in a conditional statement
|
25
|
-
* [Boolean-Parameter](Boolean-Parameter.md) - a method parameter is defaulted
|
26
|
-
to `true` or `false`.
|
data/docs/Control-Parameter.md
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
# Control Parameter
|
2
|
-
|
3
|
-
## Introduction
|
4
|
-
|
5
|
-
_Control Parameter_ is a case of [Control Couple](Control-Couple.md).
|
6
|
-
|
7
|
-
## Example
|
8
|
-
|
9
|
-
A simple example would be the `quoted` parameter in the following method:
|
10
|
-
|
11
|
-
```Ruby
|
12
|
-
def write(quoted)
|
13
|
-
if quoted
|
14
|
-
write_quoted @value
|
15
|
-
else
|
16
|
-
write_unquoted @value
|
17
|
-
end
|
18
|
-
end
|
19
|
-
```
|
20
|
-
|
21
|
-
Fixing those problems is out of the scope of this document but an easy solution
|
22
|
-
could be to remove the `write` method altogether and to move the calls to
|
23
|
-
`write_quoted` and `write_unquoted` to the caller of `write`.
|
24
|
-
|
25
|
-
## Current Support in Reek
|
26
|
-
|
27
|
-
Reek warns about _Control Parameter_ when a method parameter or block parameter is
|
28
|
-
the tested value in a conditional statement.
|
29
|
-
|
30
|
-
## Configuration
|
31
|
-
|
32
|
-
_Control Parameter_ supports the [Basic Smell Options](Basic-Smell-Options.md).
|
data/docs/Data-Clump.md
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
# Data Clump
|
2
|
-
|
3
|
-
## Introduction
|
4
|
-
|
5
|
-
In general, a _Data Clump_ occurs when the same two or three items frequently
|
6
|
-
appear together in classes and parameter lists, or when a group of instance
|
7
|
-
variable names start or end with similar substrings.
|
8
|
-
|
9
|
-
The recurrence of the items often means there is duplicate code spread around to handle them. There may be an abstraction missing from the code, making the system harder to understand.
|
10
|
-
|
11
|
-
## Example
|
12
|
-
|
13
|
-
Given
|
14
|
-
|
15
|
-
```Ruby
|
16
|
-
class Dummy
|
17
|
-
def x(y1,y2); end
|
18
|
-
def y(y1,y2); end
|
19
|
-
def z(y1,y2); end
|
20
|
-
end
|
21
|
-
```
|
22
|
-
|
23
|
-
Reek would emit the following warning:
|
24
|
-
|
25
|
-
```
|
26
|
-
test.rb -- 1 warning:
|
27
|
-
[2, 3, 4]:Dummy takes parameters [y1, y2] to 3 methods (DataClump)
|
28
|
-
```
|
29
|
-
|
30
|
-
A possible way to fix this problem (quoting from [Martin Fowler](http://martinfowler.com/bliki/DataClump.html)):
|
31
|
-
|
32
|
-
> The first step is to replace data clumps with objects and use the objects whenever you see them. An immediate benefit is that you'll shrink some parameter lists. The interesting stuff happens as you begin to look for behavior to move into the new objects.
|
33
|
-
|
34
|
-
## Current Support in Reek
|
35
|
-
|
36
|
-
Reek looks for a group of two or more parameters with the same names that are expected by three or more methods of a class.
|
37
|
-
|
38
|
-
## Configuration
|
39
|
-
|
40
|
-
Reek's _Data Clump_ detector offers the [Basic Smell Options](Basic-Smell-Options.md), plus:
|
41
|
-
|
42
|
-
| Option | Value | Effect |
|
43
|
-
| -----------------|-------------|---------|
|
44
|
-
| `max_copies` | integer | The maximum number of methods that are permitted to take the same group of parameters. Defaults to 2. |
|
45
|
-
| `min_clump_size` | integer | The smallest number of parameters that can be reported as a clump. Defaults to 2. |
|
46
|
-
|
@@ -1,264 +0,0 @@
|
|
1
|
-
# Duplicate Method Call
|
2
|
-
|
3
|
-
## Introduction
|
4
|
-
|
5
|
-
Duplication occurs when two fragments of code look nearly identical, or when two fragments of code have nearly identical effects at some conceptual level.
|
6
|
-
|
7
|
-
Let's look at an example that is quite common in the Rails world:
|
8
|
-
|
9
|
-
```Ruby
|
10
|
-
def not_production?
|
11
|
-
Rails.env.development? || Rails.env.test?
|
12
|
-
end
|
13
|
-
```
|
14
|
-
|
15
|
-
While this duplicate usage of `Rails.env` might seem innocuous there are 2 problems with it:
|
16
|
-
|
17
|
-
1.) Efficiency
|
18
|
-
|
19
|
-
```Ruby
|
20
|
-
Rails.env.development? || Rails.env.test?
|
21
|
-
```
|
22
|
-
|
23
|
-
is not as efficient as it could be. If the call to `env` is not memoized your basically paying twice in terms of computation for something that you should only pay once.
|
24
|
-
|
25
|
-
Here
|
26
|
-
|
27
|
-
```Ruby
|
28
|
-
Rails.env.development? || Rails.env.test?
|
29
|
-
```
|
30
|
-
|
31
|
-
you have 4 method calls while here:
|
32
|
-
|
33
|
-
```Ruby
|
34
|
-
env = Rails.env
|
35
|
-
env.development? || env.test?
|
36
|
-
```
|
37
|
-
|
38
|
-
you have one assignment (which is very cheap in terms of computation) and 3 method calls.
|
39
|
-
The difference might not be much here but just imagine you're writing a high performance app or you doing some expensive database calls in each method call.
|
40
|
-
|
41
|
-
It doesn't really matter though if the efficiency difference is significant. This is a matter of principle - we believe that being efficient is one of the vital traits of good software.
|
42
|
-
|
43
|
-
2.) Maintainability
|
44
|
-
|
45
|
-
The second point is a bit more subtle. This
|
46
|
-
|
47
|
-
```Ruby
|
48
|
-
env = Rails.env
|
49
|
-
env.development? || env.test?
|
50
|
-
```
|
51
|
-
|
52
|
-
is a lot more intention revealing than
|
53
|
-
|
54
|
-
```Ruby
|
55
|
-
Rails.env.development? || Rails.env.test?
|
56
|
-
```
|
57
|
-
|
58
|
-
Here
|
59
|
-
|
60
|
-
```Ruby
|
61
|
-
env = Rails.env
|
62
|
-
env.development? || env.test?
|
63
|
-
```
|
64
|
-
|
65
|
-
I'm very clear on what I do: I get the environment and then I run some checks on it.
|
66
|
-
|
67
|
-
Here
|
68
|
-
|
69
|
-
```Ruby
|
70
|
-
Rails.env.development? || Rails.env.test?
|
71
|
-
```
|
72
|
-
|
73
|
-
I'm not very clear on what I do and it requires quite more mental effort: Ok, so I'm talking to Rails, getting the environment and then running a check on it ...or .....oh, I get the same Rails constant again, get the same environment and run another check on it.
|
74
|
-
|
75
|
-
## Example
|
76
|
-
|
77
|
-
Here's a very much simplified and contrived example. The following method will report a warning:
|
78
|
-
|
79
|
-
```Ruby
|
80
|
-
def double_thing
|
81
|
-
@other.thing + @other.thing
|
82
|
-
end
|
83
|
-
```
|
84
|
-
|
85
|
-
One quick approach to silence Reek would be to refactor the code thus:
|
86
|
-
|
87
|
-
```Ruby
|
88
|
-
def double_thing
|
89
|
-
thing = @other.thing
|
90
|
-
thing + thing
|
91
|
-
end
|
92
|
-
```
|
93
|
-
|
94
|
-
A slightly different approach would be to replace all calls in `double_thing` by calls to `thing`:
|
95
|
-
|
96
|
-
```Ruby
|
97
|
-
class Other
|
98
|
-
def double_thing
|
99
|
-
thing + thing
|
100
|
-
end
|
101
|
-
|
102
|
-
def thing
|
103
|
-
@other.thing
|
104
|
-
end
|
105
|
-
end
|
106
|
-
```
|
107
|
-
|
108
|
-
The approach you take will depend on balancing other factors in your code.
|
109
|
-
|
110
|
-
## Current support in Reek
|
111
|
-
|
112
|
-
Reek's Duplicate Method Call detector checks for repeated identical method calls within
|
113
|
-
any one method definition. This is intended to complement the checks performed by tools
|
114
|
-
such as [Flay](http://ruby.sadi.st/Flay.html) and [Simian](http://www.redhillconsulting.com.au/products/simian/).
|
115
|
-
|
116
|
-
## Edge cases
|
117
|
-
|
118
|
-
Be aware that there are some edge cases like this code:
|
119
|
-
|
120
|
-
```Ruby
|
121
|
-
class Foo
|
122
|
-
def bar(switch)
|
123
|
-
case switch
|
124
|
-
when :a
|
125
|
-
->(arg) { arg.call_me(:maybe); do_something }
|
126
|
-
when :b
|
127
|
-
->(arg) { arg.call_me(:maybe); do_something_else }
|
128
|
-
when :c
|
129
|
-
->(arg) { arg.call_me(:maybe); do_something_different }
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
```
|
134
|
-
|
135
|
-
Reek cannot reliably detect that each call's receiver is a different arg and will report:
|
136
|
-
|
137
|
-
```
|
138
|
-
[5, 7, 9]:DuplicateMethodCall: Foo#bar calls 'arg.call_me(:maybe)' 3 times
|
139
|
-
```
|
140
|
-
|
141
|
-
If you're running into this problem you can disable this smell detector for this method either via
|
142
|
-
configuration:
|
143
|
-
|
144
|
-
```Yaml
|
145
|
-
---
|
146
|
-
DuplicateMethodCall:
|
147
|
-
exclude:
|
148
|
-
- 'Foo#bar'
|
149
|
-
```
|
150
|
-
|
151
|
-
or via source code comment:
|
152
|
-
|
153
|
-
```Ruby
|
154
|
-
class Foo
|
155
|
-
# :reek:DuplicateMethodCall
|
156
|
-
def bar(switch)
|
157
|
-
# ....
|
158
|
-
end
|
159
|
-
end
|
160
|
-
```
|
161
|
-
|
162
|
-
## Configuration
|
163
|
-
|
164
|
-
Reek's Duplicate Method Call detector currently offers the [Basic Smell Options](Basic-Smell-Options.md), plus:
|
165
|
-
|
166
|
-
Option | Value | Effect
|
167
|
-
-------|-------|-------
|
168
|
-
`max_calls` | integer | The maximum number of duplicate calls allowed within a method. Defaults to 1.
|
169
|
-
`allow_calls` | an array of strings or regular expressions | Ignores any context who matches it |
|
170
|
-
|
171
|
-
## Example configuration
|
172
|
-
|
173
|
-
### Adjusting `max_calls`
|
174
|
-
|
175
|
-
Imagine code like this:
|
176
|
-
|
177
|
-
```Ruby
|
178
|
-
class Alfa
|
179
|
-
def bravo
|
180
|
-
charlie.delta
|
181
|
-
charlie.delta
|
182
|
-
end
|
183
|
-
end
|
184
|
-
```
|
185
|
-
|
186
|
-
This would report:
|
187
|
-
|
188
|
-
>>
|
189
|
-
src.rb -- 1 warning:
|
190
|
-
[4, 5]:DuplicateMethodCall: Alfa#bravo calls 'charlie.delta' 2 times
|
191
|
-
|
192
|
-
If you want to allow those double calls here you can disable it in 2 different ways:
|
193
|
-
|
194
|
-
1.) Via source code comment:
|
195
|
-
|
196
|
-
```Ruby
|
197
|
-
class Alfa
|
198
|
-
# :reek:DuplicateMethodCall { max_calls: 2 }
|
199
|
-
def bravo
|
200
|
-
charlie.delta
|
201
|
-
charlie.delta
|
202
|
-
end
|
203
|
-
end
|
204
|
-
```
|
205
|
-
|
206
|
-
2.) Via configuration file:
|
207
|
-
|
208
|
-
```Yaml
|
209
|
-
DuplicateMethodCall:
|
210
|
-
max_calls: 2
|
211
|
-
```
|
212
|
-
|
213
|
-
Note though that the latter way will set `max_calls` to 2 for all instances
|
214
|
-
of the smell detector which might not be what you want - in this case
|
215
|
-
you'll have to use source code comments.
|
216
|
-
|
217
|
-
### Adjusting `allow_calls`
|
218
|
-
|
219
|
-
Imagine code like this:
|
220
|
-
|
221
|
-
```Ruby
|
222
|
-
class Alfa
|
223
|
-
def bravo
|
224
|
-
charlie.delta
|
225
|
-
charlie.delta
|
226
|
-
echo.foxtrot
|
227
|
-
echo.foxtrot
|
228
|
-
end
|
229
|
-
end
|
230
|
-
```
|
231
|
-
|
232
|
-
This would report:
|
233
|
-
|
234
|
-
>>
|
235
|
-
src.rb -- 2 warnings:
|
236
|
-
[4, 5]:DuplicateMethodCall: Alfa#bravo calls charlie.delta 2 times
|
237
|
-
[6, 7]:DuplicateMethodCall: Alfa#bravo calls echo.foxtrot 2 times
|
238
|
-
|
239
|
-
So let's say you're ok with the `echo.foxtrot` calls you can stop reporting them like this:
|
240
|
-
|
241
|
-
1.) Via source code comment:
|
242
|
-
|
243
|
-
```Ruby
|
244
|
-
class Alfa
|
245
|
-
# :reek:DuplicateMethodCall { allow_calls: ['echo.foxtrot'] }
|
246
|
-
def bravo
|
247
|
-
charlie.delta
|
248
|
-
charlie.delta
|
249
|
-
echo.foxtrot
|
250
|
-
echo.foxtrot
|
251
|
-
end
|
252
|
-
end
|
253
|
-
```
|
254
|
-
|
255
|
-
2.) Via configuration file:
|
256
|
-
|
257
|
-
```Yaml
|
258
|
-
DuplicateMethodCall:
|
259
|
-
allow_calls:
|
260
|
-
- 'echo.foxtrot'
|
261
|
-
```
|
262
|
-
|
263
|
-
Note though that the latter way will allow those calls across your source code which might not be what you want.
|
264
|
-
In this case you'll have to use source code comments.
|