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
data/Rakefile
CHANGED
@@ -3,6 +3,19 @@ require 'rake/clean'
|
|
3
3
|
|
4
4
|
Dir['tasks/**/*.rake'].each { |t| load t }
|
5
5
|
|
6
|
-
task
|
7
|
-
|
8
|
-
|
6
|
+
task :ci do
|
7
|
+
[
|
8
|
+
'test:spec',
|
9
|
+
'configuration:update_default_configuration',
|
10
|
+
'test:features',
|
11
|
+
:rubocop,
|
12
|
+
'test:quality',
|
13
|
+
:ataru
|
14
|
+
].each do |name|
|
15
|
+
puts "\n=== Running #{name}...\n"
|
16
|
+
Rake::Task[name].invoke
|
17
|
+
puts "\n=== Running #{name} -> Done\n"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
task default: :ci
|
data/bin/reek
CHANGED
data/docs/API.md
CHANGED
@@ -89,7 +89,7 @@ XMLReport
|
|
89
89
|
|
90
90
|
## Configuration
|
91
91
|
|
92
|
-
Given you have the following configuration file called
|
92
|
+
Given you have the following configuration file called `.reek.yml` in your root directory:
|
93
93
|
|
94
94
|
```Yaml
|
95
95
|
---
|
@@ -106,7 +106,7 @@ You can now use either
|
|
106
106
|
Reek::Configuration::AppConfiguration.from_path Pathname.new('config.reek')
|
107
107
|
```
|
108
108
|
|
109
|
-
but you can also pass a hash with the contents of the
|
109
|
+
but you can also pass a hash with the contents of the `.reek.yml` YAML file
|
110
110
|
to `Reek::Configuration::AppConfiguration.from_hash`.
|
111
111
|
|
112
112
|
Given the example above you would load that as follows:
|
@@ -140,13 +140,6 @@ string -- 2 warnings:
|
|
140
140
|
Dirty#call_me has the parameter name 'b' (UncommunicativeParameterName)
|
141
141
|
```
|
142
142
|
|
143
|
-
Instead of the smell detector names you can also use the full detector class in
|
144
|
-
your configuration hash, for example:
|
145
|
-
|
146
|
-
```ruby
|
147
|
-
config_hash = { Reek::SmellDetectors::IrresponsibleModule => { 'enabled' => false } }
|
148
|
-
```
|
149
|
-
|
150
143
|
Of course, directory specific configuration and excluded paths are supported as
|
151
144
|
well:
|
152
145
|
|
data/docs/Basic-Smell-Options.md
CHANGED
@@ -7,14 +7,14 @@ Every smell detector in Reek offers at least the following configuration options
|
|
7
7
|
| Option | Value | Effect |
|
8
8
|
| ---------------|-------------|---------|
|
9
9
|
| `enabled` | Boolean | Determines whether the smell detector is active. Defaults to `true` |
|
10
|
-
| `exclude` | an array of strings
|
10
|
+
| `exclude` | an array of strings that will be converted into regular expressions | Ignores any context whose full description matches any element of this array. |
|
11
11
|
|
12
|
-
The file `defaults.reek` (shipped with the Reek gem) lists any default
|
12
|
+
The file `docs/defaults.reek.yml` (shipped with the Reek gem) lists any default
|
13
13
|
exclusions for each smell.
|
14
14
|
|
15
15
|
## Examples
|
16
16
|
|
17
|
-
|
17
|
+
**An easy one:**
|
18
18
|
|
19
19
|
To stop Reek reporting smells in any method called `write` you might create a configuration file containing this:
|
20
20
|
|
@@ -24,15 +24,9 @@ DuplicateMethodCall:
|
|
24
24
|
- write
|
25
25
|
```
|
26
26
|
|
27
|
-
|
27
|
+
Internally Reek will convert this to the Regexp /write/.
|
28
28
|
|
29
|
-
|
30
|
-
DuplicateMethodCall:
|
31
|
-
exclude:
|
32
|
-
- !ruby/regexp /write/
|
33
|
-
```
|
34
|
-
|
35
|
-
<u>A more sophisticated one:</u>
|
29
|
+
**A more sophisticated one:**
|
36
30
|
|
37
31
|
```yaml
|
38
32
|
FeatureEnvy:
|
@@ -43,3 +37,49 @@ FeatureEnvy:
|
|
43
37
|
```
|
44
38
|
|
45
39
|
This would not report FeatureEnvy for the instance method `MyModel#do_things`, the whole module `MyHelper` and the `respond` instance method of `ApplicationController`
|
40
|
+
|
41
|
+
## Advanced configuration
|
42
|
+
|
43
|
+
Sometimes just strings are not enough for configuration. E.g. consider this code sample:
|
44
|
+
|
45
|
+
```Ruby
|
46
|
+
class Klass
|
47
|
+
def foo1; end
|
48
|
+
def foo1bar; end
|
49
|
+
end
|
50
|
+
```
|
51
|
+
Both "Klass#foo1" and "Klass#foo1bar" will smell of UncommunicativeMethodName. Now let's assume
|
52
|
+
you are ok with "Klass#foo1" but not "Klass#foo1bar".
|
53
|
+
Just having this configuration
|
54
|
+
|
55
|
+
```yaml
|
56
|
+
UncommunicativeMethodName:
|
57
|
+
exclude:
|
58
|
+
- "Klass#foo1"
|
59
|
+
```
|
60
|
+
|
61
|
+
wouldn't work because now "Klass#foo1bar" wouldn't smell as well.
|
62
|
+
|
63
|
+
For this reason Reek has a special syntax that allows you to use regexes by using a forward slash at the beginning and the end of the string.
|
64
|
+
Everything within the forward slashes will be loaded as a regex.
|
65
|
+
|
66
|
+
A possible configuration that hat excludes "Klass#foo1" from this scan but not "Klass#foo1bar" could look like this:
|
67
|
+
|
68
|
+
```yaml
|
69
|
+
UncommunicativeMethodName:
|
70
|
+
exclude:
|
71
|
+
- "/Klass#foo1$/"
|
72
|
+
```
|
73
|
+
|
74
|
+
## Reek 4
|
75
|
+
|
76
|
+
In Reek 4 you could also pass regexes to `exclude`, meaning this was perfectly valid as well:
|
77
|
+
|
78
|
+
```yaml
|
79
|
+
DuplicateMethodCall:
|
80
|
+
exclude:
|
81
|
+
- !ruby/regexp /write/
|
82
|
+
```
|
83
|
+
|
84
|
+
Support for this has been scrapped with Reek 5 to make the Reek configuration more yaml standard compliant.
|
85
|
+
You can still pass in regexes, you just have to wrap them into a string. Please see "Advanced configuration" above.
|
data/docs/Code-Smells.md
CHANGED
@@ -23,7 +23,7 @@ Reek currently includes checks for the following smells:
|
|
23
23
|
* [Utility Function](Utility-Function.md)
|
24
24
|
* [Module Initialize](Module-Initialize.md)
|
25
25
|
* [Nested Iterators](Nested-Iterators.md)
|
26
|
-
* [
|
26
|
+
* [Missing Safe Method](Missing-Safe-Method.md), formerly known as Prima Donna Method
|
27
27
|
* [Simulated Polymorphism](Simulated-Polymorphism.md), including
|
28
28
|
* [Manual Dispatch](Manual-Dispatch.md)
|
29
29
|
* [Nil Check](Nil-Check.md)
|
@@ -12,6 +12,16 @@ reek -h
|
|
12
12
|
|
13
13
|
for details.
|
14
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
|
+
|
15
25
|
## Telling Reek Which Code to Check
|
16
26
|
|
17
27
|
Probably the most standard use case would be to check all Ruby files in the lib directory:
|
@@ -91,10 +101,10 @@ mess.rb -- 2 warnings:
|
|
91
101
|
[2]:x has the name 'x' (UncommunicativeMethodName)
|
92
102
|
```
|
93
103
|
|
94
|
-
### Enable the
|
104
|
+
### Enable the verbose mode
|
95
105
|
|
96
|
-
_reek_ has a
|
97
|
-
This mode can be enabled via the "-U" or "--
|
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.
|
98
108
|
|
99
109
|
So for instance, if your test file would smell of _ClassVariable_, this is what the _reek_ output would look like:
|
100
110
|
|
@@ -103,7 +113,7 @@ reek -U test.rb
|
|
103
113
|
```
|
104
114
|
```
|
105
115
|
test.rb -- 1 warning:
|
106
|
-
[2]:Dummy declares the class variable @@class_variable (ClassVariable) [https://github.com/troessner/reek/
|
116
|
+
[2]:Dummy declares the class variable @@class_variable (ClassVariable) [https://github.com/troessner/reek/blob/master/docs/Class-Variable.md]
|
107
117
|
```
|
108
118
|
|
109
119
|
Note the link at the end.
|
@@ -42,7 +42,55 @@ The approach you take will depend on balancing other factors in your code.
|
|
42
42
|
|
43
43
|
## Current support in Reek
|
44
44
|
|
45
|
-
Reek's Duplicate Method Call detector checks for repeated identical method calls within
|
45
|
+
Reek's Duplicate Method Call detector checks for repeated identical method calls within
|
46
|
+
any one method definition. This is intended to complement the checks performed by tools
|
47
|
+
such as [Flay](http://ruby.sadi.st/Flay.html) and [Simian](http://www.redhillconsulting.com.au/products/simian/).
|
48
|
+
|
49
|
+
## Edge cases
|
50
|
+
|
51
|
+
Be aware that there are some edge cases like this code:
|
52
|
+
|
53
|
+
```Ruby
|
54
|
+
class Foo
|
55
|
+
def bar(switch)
|
56
|
+
case switch
|
57
|
+
when :a
|
58
|
+
->(arg) { arg.call_me(:maybe); do_something }
|
59
|
+
when :b
|
60
|
+
->(arg) { arg.call_me(:maybe); do_something_else }
|
61
|
+
when :c
|
62
|
+
->(arg) { arg.call_me(:maybe); do_something_different }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
Reek cannot reliably detect that each call's receiver is a different arg and will report:
|
69
|
+
|
70
|
+
```
|
71
|
+
[5, 7, 9]:DuplicateMethodCall: Foo#bar calls 'arg.call_me(:maybe)' 3 times
|
72
|
+
```
|
73
|
+
|
74
|
+
If you're running into this problem you can disable this smell detector for this method either via
|
75
|
+
configuration:
|
76
|
+
|
77
|
+
```Yaml
|
78
|
+
---
|
79
|
+
DuplicateMethodCall:
|
80
|
+
exclude:
|
81
|
+
- 'Foo#bar'
|
82
|
+
```
|
83
|
+
|
84
|
+
or via source code comment:
|
85
|
+
|
86
|
+
```Ruby
|
87
|
+
class Foo
|
88
|
+
# :reek:DuplicateMethodCall
|
89
|
+
def bar(switch)
|
90
|
+
# ....
|
91
|
+
end
|
92
|
+
end
|
93
|
+
```
|
46
94
|
|
47
95
|
## Configuration
|
48
96
|
|
data/docs/Feature-Envy.md
CHANGED
@@ -40,6 +40,50 @@ belongs to the Item class, not the Warehouse.
|
|
40
40
|
|
41
41
|
_Feature Envy_ reports any method that refers to self less often than it refers to (ie. send messages to) some other object.
|
42
42
|
|
43
|
+
## Edge cases
|
44
|
+
|
45
|
+
Be aware that there are some edge cases like this code:
|
46
|
+
|
47
|
+
```Ruby
|
48
|
+
class Foo
|
49
|
+
def initialize
|
50
|
+
@map = {
|
51
|
+
a: ->(arg) { arg.css('table') },
|
52
|
+
b: ->(arg) { arg.css('div') },
|
53
|
+
c: ->(arg) { arg.css('span') }
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
Reek cannot reliably detect that each call's receiver is a different arg and will report:
|
60
|
+
|
61
|
+
```
|
62
|
+
[4, 5, 6]:FeatureEnvy: Foo#initialize refers to 'arg' more than self (maybe move it to another class?)
|
63
|
+
```
|
64
|
+
|
65
|
+
If you're running into this problem you can disable this smell detector for this method either via
|
66
|
+
configuration:
|
67
|
+
|
68
|
+
```Yaml
|
69
|
+
---
|
70
|
+
FeatureEnvy:
|
71
|
+
exclude:
|
72
|
+
- 'Foo#bar'
|
73
|
+
```
|
74
|
+
|
75
|
+
or via source code comment:
|
76
|
+
|
77
|
+
```Ruby
|
78
|
+
class Foo
|
79
|
+
# :reek:FeatureEnvy
|
80
|
+
def initialize
|
81
|
+
@map = {
|
82
|
+
# ....
|
83
|
+
end
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
43
87
|
## Differences to _Utility Function_
|
44
88
|
|
45
89
|
_Feature Envy_ is only triggered if there are some references to self and _[Utility Function](Utility-Function.md)_ is triggered if there are no references to self.
|
@@ -41,7 +41,6 @@ module Reek
|
|
41
41
|
# "smell_warning" is defined in BaseDetector and should be used by you
|
42
42
|
# to construct smell warnings
|
43
43
|
smell_warning(
|
44
|
-
context: context,
|
45
44
|
lines: [], # lines on which the smell was detected
|
46
45
|
message: "...", # the message that is printed on STDOUT
|
47
46
|
# whatever you interpolate into the "message" should go into
|
@@ -62,7 +61,7 @@ end
|
|
62
61
|
|
63
62
|
For your detector to be properly loaded you need to require it in `lib/reek/smell_detectors.rb` as well.
|
64
63
|
|
65
|
-
### defaults.reek
|
64
|
+
### defaults.reek.yml
|
66
65
|
|
67
66
|
After you ran
|
68
67
|
|
@@ -70,7 +69,7 @@ After you ran
|
|
70
69
|
bundle exec rake
|
71
70
|
```
|
72
71
|
|
73
|
-
for the first time with your shiny new detector in place the `defaults.reek`
|
72
|
+
for the first time with your shiny new detector in place the `docs/defaults.reek.yml`
|
74
73
|
file should have been updated automatically. Make sure you don't forget to check
|
75
74
|
in those changes as well.
|
76
75
|
|
@@ -1,8 +1,8 @@
|
|
1
|
-
#
|
1
|
+
# Missing Safe Method
|
2
2
|
|
3
3
|
## Introduction
|
4
4
|
|
5
|
-
Candidate methods for the
|
5
|
+
Candidate methods for the _Missing Safe Method_ smell are methods whose names
|
6
6
|
end with an exclamation mark.
|
7
7
|
|
8
8
|
An exclamation mark in method names means (the explanation below is taken from
|
@@ -13,14 +13,16 @@ An exclamation mark in method names means (the explanation below is taken from
|
|
13
13
|
> equivalent method, with the same name minus the !. “Danger” is relative; the
|
14
14
|
> ! doesn’t mean anything at all unless the method name it’s in corresponds to
|
15
15
|
> a similar but bang-less method name.
|
16
|
-
>
|
16
|
+
>
|
17
17
|
> So, for example, gsub! is the dangerous version of gsub. exit! is the
|
18
18
|
> dangerous version of exit. flatten! is the dangerous version of flatten. And
|
19
19
|
> so forth.
|
20
20
|
|
21
|
-
Such a method is called
|
21
|
+
Such a method is called _Missing Safe Method_ if and only if the non-bang
|
22
22
|
version does not exist and this method is reported as a smell.
|
23
23
|
|
24
|
+
Missing Safe Method was formerly known as Prima Donna Method.
|
25
|
+
|
24
26
|
## Example
|
25
27
|
|
26
28
|
Given
|
@@ -33,7 +35,7 @@ class C
|
|
33
35
|
end
|
34
36
|
```
|
35
37
|
|
36
|
-
Reek would report the
|
38
|
+
Reek would report the _Missing Safe Method_ smell for `bar!`, but not for `foo!`.
|
37
39
|
|
38
40
|
Reek reports this smell only in a class context, not in a module context in order to allow perfectly legit code like this:
|
39
41
|
|
@@ -55,12 +57,12 @@ class Daughter < Parent
|
|
55
57
|
end
|
56
58
|
```
|
57
59
|
|
58
|
-
In this example, Reek would not report the
|
60
|
+
In this example, Reek would not report the _Missing Safe Method_ smell for the
|
59
61
|
method `foo` of the `Dangerous` module.
|
60
62
|
|
61
63
|
## Configuration
|
62
64
|
|
63
|
-
|
65
|
+
_Missing Safe Method_ offers the [Basic Smell Options](Basic-Smell-Options.md).
|
64
66
|
|
65
67
|
## Example configuration via source comment
|
66
68
|
|
@@ -77,12 +79,12 @@ This would report:
|
|
77
79
|
|
78
80
|
>>
|
79
81
|
ruby.rb -- 1 warning:
|
80
|
-
[1]:
|
82
|
+
[1]:MissingSafeMethod: Alfa has missing safe method 'bravo!'
|
81
83
|
|
82
84
|
If you want to suppress this warning you can do this via source comment like this:
|
83
85
|
|
84
86
|
```Ruby
|
85
|
-
# :reek:
|
87
|
+
# :reek:MissingSafeMethod { exclude: [ bravo! ] }
|
86
88
|
class Alfa
|
87
89
|
def bravo!
|
88
90
|
end
|
data/docs/Rake-Task.md
CHANGED
@@ -33,7 +33,7 @@ An more sophisticated rake task that would make use of all available configurati
|
|
33
33
|
```Ruby
|
34
34
|
Reek::Rake::Task.new do |t|
|
35
35
|
t.name = 'custom_rake' # Whatever name you want. Defaults to "reek".
|
36
|
-
t.config_file = 'config
|
36
|
+
t.config_file = 'config/.reek.yml' # Defaults to nothing.
|
37
37
|
t.source_files = 'vendor/**/*.rb' # Glob pattern to match source files. Defaults to lib/**/*.rb
|
38
38
|
t.reek_opts = '-U' # Defaults to ''. You can pass all the options here in that are shown by "reek -h"
|
39
39
|
t.fail_on_error = false # Defaults to true
|
@@ -0,0 +1,193 @@
|
|
1
|
+
## Reek 4 to Reek 5 migration
|
2
|
+
|
3
|
+
### Schema validation
|
4
|
+
|
5
|
+
Reek now uses a schema to validate your configuration against on start up and will faily loudly in
|
6
|
+
case you misspelled an option or used the wrong data type for a value like this:
|
7
|
+
|
8
|
+
```
|
9
|
+
Error: We found some problems with your configuration file: [/detectors/DetectorWithTypo] key 'DetectorWithTypo:' is undefined.
|
10
|
+
```
|
11
|
+
|
12
|
+
Obviously this might affect existing configuration files that until now contained an error nobody noticed.
|
13
|
+
|
14
|
+
### Scoping detectors under `detectors`
|
15
|
+
|
16
|
+
In Reek 4 you could just configure your detectors on top level like this:
|
17
|
+
|
18
|
+
```yaml
|
19
|
+
UncommunicativeMethodName:
|
20
|
+
accept:
|
21
|
+
- foobar
|
22
|
+
UnusedPrivateMethod:
|
23
|
+
exclude:
|
24
|
+
- app/controllers
|
25
|
+
```
|
26
|
+
|
27
|
+
In Reek 5 you have to scope your detector configurations under the `detectors` key:
|
28
|
+
|
29
|
+
```yaml
|
30
|
+
detectors:
|
31
|
+
UncommunicativeMethodName:
|
32
|
+
accept:
|
33
|
+
- foobar
|
34
|
+
UnusedPrivateMethod:
|
35
|
+
exclude:
|
36
|
+
- app/controllers
|
37
|
+
```
|
38
|
+
|
39
|
+
### Move directory directives under a special key
|
40
|
+
|
41
|
+
In Reek 4 you could apply directory specific directives like this:
|
42
|
+
|
43
|
+
```Yaml
|
44
|
+
---
|
45
|
+
"web_app/app/controllers":
|
46
|
+
NestedIterators:
|
47
|
+
enabled: false
|
48
|
+
"web_app/app/helpers":
|
49
|
+
UtilityFunction:
|
50
|
+
enabled: false
|
51
|
+
```
|
52
|
+
|
53
|
+
which was nice and easy but also quite messy. With Reek 5 you'll have to scope this under a `directories`
|
54
|
+
key like this:
|
55
|
+
|
56
|
+
```Yaml
|
57
|
+
---
|
58
|
+
directories:
|
59
|
+
"web_app/app/controllers":
|
60
|
+
NestedIterators:
|
61
|
+
enabled: false
|
62
|
+
"web_app/app/helpers":
|
63
|
+
UtilityFunction:
|
64
|
+
enabled: false
|
65
|
+
```
|
66
|
+
|
67
|
+
### No more regular expressions in Reeks configuration
|
68
|
+
|
69
|
+
In Reek 4 you could pass regular expressions to the `accept` or `reject` settings of
|
70
|
+
|
71
|
+
* [Uncommunicative Method Name](Uncommunicative-Method-Name.md)
|
72
|
+
* [Uncommunicative Module Name](Uncommunicative-Module-Name.md)
|
73
|
+
* [Uncommunicative Parameter Name](Uncommunicative-Parameter-Name.md)
|
74
|
+
* [Uncommunicative Variable Name](Uncommunicative-Variable-Name.md)
|
75
|
+
|
76
|
+
and to the `exclude` settings which are part of our [Basic Smell Options](docs/Basic-Smell-Options.md).
|
77
|
+
|
78
|
+
This means that this configuration was perfectly valid:
|
79
|
+
|
80
|
+
```yaml
|
81
|
+
detectors:
|
82
|
+
UncommunicativeMethodName:
|
83
|
+
accept:
|
84
|
+
- !ruby/regexp /foobar/
|
85
|
+
UnusedPrivateMethod:
|
86
|
+
exclude:
|
87
|
+
- !ruby/regexp /i am(.*)unused/
|
88
|
+
```
|
89
|
+
|
90
|
+
Support for this has been scrapped with Reek 5 to make the Reek configuration more yaml standard compliant.
|
91
|
+
You can still pass in regexes, you just have to wrap them into a string using a forward slash at the
|
92
|
+
beginning and at the end of the string like this:
|
93
|
+
|
94
|
+
```Yaml
|
95
|
+
---
|
96
|
+
UncommunicativeMethodName:
|
97
|
+
accept:
|
98
|
+
- "/^foobar$/"
|
99
|
+
UnusedPrivateMethod:
|
100
|
+
exclude:
|
101
|
+
- "/i am(.*)unused/"
|
102
|
+
```
|
103
|
+
|
104
|
+
Everything within the forward slashes will be loaded as a regex.
|
105
|
+
|
106
|
+
### No more single item shortcuts for list items
|
107
|
+
|
108
|
+
You cant use a configuration option that is supposed to be a list with a single element like this anymore:
|
109
|
+
|
110
|
+
```Yaml
|
111
|
+
---
|
112
|
+
UncommunicativeMethodName:
|
113
|
+
accept: foobar
|
114
|
+
UnusedPrivateMethod:
|
115
|
+
exclude: omg
|
116
|
+
```
|
117
|
+
|
118
|
+
You'll have to use a proper list here like this:
|
119
|
+
|
120
|
+
```Yaml
|
121
|
+
---
|
122
|
+
UncommunicativeMethodName:
|
123
|
+
accept:
|
124
|
+
- foobar
|
125
|
+
UnusedPrivateMethod:
|
126
|
+
exclude:
|
127
|
+
- omg
|
128
|
+
```
|
129
|
+
|
130
|
+
## Failing on syntax errors in source files
|
131
|
+
|
132
|
+
Previously Reek would just continue on syntax errors in source files which might have been convenient but
|
133
|
+
not necessarily fitting for a tool that's all about code quality. With Reek 5, Reek will fail hard on
|
134
|
+
invalid source files.
|
135
|
+
|
136
|
+
### API changes
|
137
|
+
|
138
|
+
This is something that will only affect very advanced users. In case you have no idea what this might be about
|
139
|
+
you can just skip it or check out our [Developer API](docs/API.md).
|
140
|
+
|
141
|
+
#### Allow only detector names in configuration hash
|
142
|
+
|
143
|
+
In Reek 4 you could build your configuration like this:
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
config_hash = { Reek::SmellDetectors::IrresponsibleModule => { 'enabled' => false } }
|
147
|
+
```
|
148
|
+
|
149
|
+
or like this:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
config_hash = { 'IrresponsibleModule' => { 'enabled' => false } }
|
153
|
+
```
|
154
|
+
|
155
|
+
Starting with Reek 5, the first way is not working anymore and the latter one is what you'll have to use.
|
156
|
+
|
157
|
+
#### Do not accept a class as parameter for reek_of
|
158
|
+
|
159
|
+
In the same vein as the change above you also can't use fully qualified detector names like this:
|
160
|
+
|
161
|
+
```Ruby
|
162
|
+
reek_of(Reek::SmellDetectors::DuplicateMethodCall)
|
163
|
+
```
|
164
|
+
|
165
|
+
The only supported way now is either as symbol or string:
|
166
|
+
|
167
|
+
```Ruby
|
168
|
+
reek_of(:DuplicateMethodCall)
|
169
|
+
reek_of('DuplicateMethodCall')
|
170
|
+
```
|
171
|
+
|
172
|
+
## Smaller changes
|
173
|
+
|
174
|
+
* `PrimaDonnaMethod` has been given the better name `MissingSafeMethod`
|
175
|
+
* `wiki-links` flag has been renamed to `documentation` flag
|
176
|
+
* Reek assumes the default configuration file to be named ".reek.yml" and will ignore all other files. You can
|
177
|
+
still use any name you want though by passing in a name via the `-c` flag
|
178
|
+
* We have dropped the legacy code comment separator ":" at the end of a detector name. If you wanted to configure
|
179
|
+
a smell detector via comment before this release you had to use g like this:
|
180
|
+
|
181
|
+
```
|
182
|
+
# :reek:UnusedPrivateMethod: { exclude: [ bravo ] }
|
183
|
+
```
|
184
|
+
|
185
|
+
Mind the ":" at the end of "UnusedPrivateMethod". This syntax is disallowed with Reek 5 - you have to drop the ":"
|
186
|
+
at the end now like this:
|
187
|
+
|
188
|
+
```
|
189
|
+
# :reek:UnusedPrivateMethod { exclude: [ bravo ] }
|
190
|
+
```
|
191
|
+
|
192
|
+
* We have dropped support for Ruby 2.1 and 2.2 since they are officially not supported by the Ruby core team anymore
|
193
|
+
|