reek 4.7.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.codeclimate.yml +17 -12
- data/.rubocop.yml +36 -7
- data/.simplecov +1 -0
- data/.travis.yml +3 -9
- data/.yardopts +1 -1
- data/CHANGELOG.md +59 -0
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +5 -5
- data/README.md +134 -104
- 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 +7 -7
- data/docs/Instance-Variable-Assumption.md +1 -1
- data/docs/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
- data/docs/Rake-Task.md +1 -1
- data/docs/Reek-4-to-Reek-5-migration.md +193 -0
- data/docs/Reek-Driven-Development.md +1 -1
- data/docs/Uncommunicative-Method-Name.md +45 -6
- data/docs/Uncommunicative-Module-Name.md +49 -7
- data/docs/Uncommunicative-Parameter-Name.md +43 -5
- data/docs/Uncommunicative-Variable-Name.md +73 -2
- data/docs/Unused-Private-Method.md +3 -3
- data/docs/defaults.reek.yml +129 -0
- data/docs/yard_plugin.rb +1 -0
- data/features/command_line_interface/basic_usage.feature +2 -2
- data/features/command_line_interface/options.feature +46 -4
- data/features/command_line_interface/show_progress.feature +4 -4
- data/features/command_line_interface/smell_selection.feature +1 -1
- data/features/command_line_interface/smells_count.feature +6 -6
- data/features/command_line_interface/stdin.feature +30 -8
- data/features/configuration_files/accept_setting.feature +45 -28
- data/features/configuration_files/directory_specific_directives.feature +80 -75
- data/features/configuration_files/exclude_directives.feature +11 -10
- data/features/configuration_files/exclude_paths_directives.feature +4 -4
- data/features/configuration_files/masking_smells.feature +38 -9
- data/features/configuration_files/mix_accept_reject_setting.feature +31 -28
- data/features/configuration_files/reject_setting.feature +52 -41
- data/features/configuration_files/schema_validation.feature +59 -0
- data/features/configuration_files/unused_private_method.feature +18 -16
- data/features/configuration_loading.feature +53 -10
- data/features/configuration_via_source_comments/erroneous_source_comments.feature +3 -3
- data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
- data/features/locales.feature +32 -0
- data/features/rake_task/rake_task.feature +58 -18
- data/features/reports/json.feature +3 -3
- data/features/reports/reports.feature +34 -34
- data/features/reports/yaml.feature +3 -3
- data/features/rspec_matcher.feature +40 -0
- data/features/samples.feature +287 -287
- data/features/step_definitions/reek_steps.rb +2 -2
- data/features/step_definitions/sample_file_steps.rb +9 -4
- data/features/support/env.rb +2 -11
- data/features/todo_list.feature +26 -23
- data/lib/reek/ast/builder.rb +1 -1
- data/lib/reek/ast/node.rb +40 -58
- data/lib/reek/ast/object_refs.rb +1 -1
- data/lib/reek/ast/reference_collector.rb +2 -4
- data/lib/reek/ast/sexp_extensions/case.rb +1 -1
- data/lib/reek/ast/sexp_extensions/if.rb +8 -1
- data/lib/reek/ast/sexp_extensions/logical_operators.rb +1 -1
- data/lib/reek/ast/sexp_extensions/methods.rb +4 -6
- data/lib/reek/ast/sexp_extensions/send.rb +0 -4
- 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 +8 -8
- data/lib/reek/cli/options.rb +31 -16
- data/lib/reek/cli/silencer.rb +14 -3
- data/lib/reek/code_comment.rb +14 -16
- data/lib/reek/configuration/app_configuration.rb +32 -27
- data/lib/reek/configuration/configuration_converter.rb +110 -0
- data/lib/reek/configuration/configuration_file_finder.rb +16 -41
- 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 +3 -3
- data/lib/reek/context/code_context.rb +47 -43
- data/lib/reek/context/ghost_context.rb +0 -2
- data/lib/reek/context/method_context.rb +22 -15
- data/lib/reek/context/module_context.rb +5 -9
- data/lib/reek/context/root_context.rb +0 -4
- data/lib/reek/context/send_context.rb +2 -2
- data/lib/reek/context_builder.rb +43 -44
- data/lib/reek/detector_repository.rb +11 -11
- data/lib/reek/documentation_link.rb +28 -0
- data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +14 -13
- data/lib/reek/errors/bad_detector_in_comment_error.rb +12 -11
- data/lib/reek/errors/base_error.rb +3 -0
- data/lib/reek/errors/config_file_error.rb +11 -0
- data/lib/reek/errors/encoding_error.rb +43 -0
- data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +13 -12
- data/lib/reek/errors/incomprehensible_source_error.rb +22 -24
- data/lib/reek/errors/syntax_error.rb +41 -0
- data/lib/reek/examiner.rb +24 -26
- data/lib/reek/logging_error_handler.rb +7 -5
- data/lib/reek/rake/task.rb +8 -4
- data/lib/reek/report/base_report.rb +8 -12
- data/lib/reek/report/code_climate/code_climate_configuration.rb +1 -1
- data/lib/reek/report/code_climate/code_climate_configuration.yml +6 -10
- 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/report.rb +15 -10
- data/lib/reek/smell_configuration.rb +2 -2
- data/lib/reek/smell_detectors/attribute.rb +5 -11
- data/lib/reek/smell_detectors/base_detector.rb +30 -26
- data/lib/reek/smell_detectors/boolean_parameter.rb +3 -5
- data/lib/reek/smell_detectors/class_variable.rb +5 -14
- data/lib/reek/smell_detectors/control_parameter.rb +18 -33
- data/lib/reek/smell_detectors/data_clump.rb +15 -9
- data/lib/reek/smell_detectors/duplicate_method_call.rb +23 -17
- data/lib/reek/smell_detectors/feature_envy.rb +9 -7
- data/lib/reek/smell_detectors/instance_variable_assumption.rb +14 -23
- data/lib/reek/smell_detectors/irresponsible_module.rb +5 -12
- data/lib/reek/smell_detectors/long_parameter_list.rb +10 -7
- data/lib/reek/smell_detectors/long_yield_list.rb +10 -7
- data/lib/reek/smell_detectors/manual_dispatch.rb +4 -5
- data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +20 -20
- data/lib/reek/smell_detectors/module_initialize.rb +3 -5
- data/lib/reek/smell_detectors/nested_iterators.rb +16 -24
- data/lib/reek/smell_detectors/nil_check.rb +8 -15
- data/lib/reek/smell_detectors/repeated_conditional.rb +13 -11
- data/lib/reek/smell_detectors/subclassed_from_core_class.rb +7 -8
- data/lib/reek/smell_detectors/too_many_constants.rb +10 -9
- data/lib/reek/smell_detectors/too_many_instance_variables.rb +10 -6
- data/lib/reek/smell_detectors/too_many_methods.rb +11 -7
- data/lib/reek/smell_detectors/too_many_statements.rb +10 -6
- data/lib/reek/smell_detectors/uncommunicative_method_name.rb +10 -11
- data/lib/reek/smell_detectors/uncommunicative_module_name.rb +14 -18
- data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +17 -22
- data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +26 -27
- data/lib/reek/smell_detectors/unused_parameters.rb +4 -6
- data/lib/reek/smell_detectors/unused_private_method.rb +11 -18
- data/lib/reek/smell_detectors/utility_function.rb +12 -16
- data/lib/reek/smell_detectors.rb +1 -2
- data/lib/reek/smell_warning.rb +15 -8
- data/lib/reek/source/source_code.rb +57 -58
- data/lib/reek/source/source_locator.rb +8 -8
- 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/spec.rb +6 -6
- data/lib/reek/tree_dresser.rb +8 -8
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +5 -7
- data/samples/checkstyle.xml +1 -1
- data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
- data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
- data/samples/configuration/full_configuration.reek +8 -4
- data/samples/configuration/full_mask.reek +5 -4
- data/samples/configuration/partial_mask.reek +3 -2
- data/samples/configuration/regular_configuration/.reek.yml +4 -0
- data/samples/paths.rb +5 -4
- data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
- data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
- data/spec/factories/factories.rb +2 -13
- data/spec/reek/ast/node_spec.rb +103 -10
- data/spec/reek/ast/reference_collector_spec.rb +1 -1
- data/spec/reek/ast/sexp_extensions_spec.rb +14 -34
- data/spec/reek/cli/application_spec.rb +52 -42
- data/spec/reek/cli/command/todo_list_command_spec.rb +6 -4
- data/spec/reek/cli/silencer_spec.rb +28 -0
- data/spec/reek/code_comment_spec.rb +31 -38
- data/spec/reek/configuration/app_configuration_spec.rb +46 -33
- data/spec/reek/configuration/configuration_file_finder_spec.rb +133 -51
- data/spec/reek/configuration/default_directive_spec.rb +1 -1
- data/spec/reek/configuration/directory_directives_spec.rb +6 -7
- data/spec/reek/configuration/excluded_paths_spec.rb +6 -6
- data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
- data/spec/reek/configuration/schema_validator_spec.rb +165 -0
- data/spec/reek/context/code_context_spec.rb +70 -106
- data/spec/reek/context/ghost_context_spec.rb +9 -9
- data/spec/reek/context/method_context_spec.rb +2 -2
- data/spec/reek/context/module_context_spec.rb +3 -3
- data/spec/reek/context/root_context_spec.rb +1 -1
- data/spec/reek/context_builder_spec.rb +20 -0
- data/spec/reek/documentation_link_spec.rb +20 -0
- data/spec/reek/errors/base_error_spec.rb +13 -0
- data/spec/reek/examiner_spec.rb +136 -29
- data/spec/reek/rake/task_spec.rb +25 -2
- data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +82 -80
- data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
- data/spec/reek/report/json_report_spec.rb +13 -46
- data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
- data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
- data/spec/reek/report/text_report_spec.rb +4 -4
- data/spec/reek/report/xml_report_spec.rb +3 -3
- data/spec/reek/report/yaml_report_spec.rb +9 -38
- data/spec/reek/report_spec.rb +3 -3
- data/spec/reek/smell_detectors/base_detector_spec.rb +4 -5
- data/spec/reek/smell_detectors/boolean_parameter_spec.rb +2 -2
- data/spec/reek/smell_detectors/class_variable_spec.rb +26 -32
- data/spec/reek/smell_detectors/control_parameter_spec.rb +34 -4
- data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +3 -3
- data/spec/reek/smell_detectors/feature_envy_spec.rb +47 -2
- data/spec/reek/smell_detectors/irresponsible_module_spec.rb +0 -11
- data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +10 -10
- data/spec/reek/smell_detectors/module_initialize_spec.rb +14 -0
- data/spec/reek/smell_detectors/nested_iterators_spec.rb +1 -1
- data/spec/reek/smell_detectors/too_many_constants_spec.rb +3 -3
- data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +1 -1
- data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +6 -6
- data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +6 -4
- data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +36 -15
- data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +9 -9
- data/spec/reek/smell_detectors/unused_parameters_spec.rb +3 -3
- data/spec/reek/smell_detectors/unused_private_method_spec.rb +21 -10
- data/spec/reek/smell_detectors/utility_function_spec.rb +57 -5
- data/spec/reek/smell_warning_spec.rb +12 -8
- data/spec/reek/source/source_code_spec.rb +22 -21
- data/spec/reek/source/source_locator_spec.rb +17 -17
- data/spec/reek/spec/should_reek_of_spec.rb +25 -29
- data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
- data/spec/reek/spec/should_reek_spec.rb +8 -8
- data/spec/reek/spec/smell_matcher_spec.rb +23 -23
- data/spec/reek/tree_dresser_spec.rb +12 -17
- data/spec/spec_helper.rb +6 -17
- data/tasks/configuration.rake +8 -5
- metadata +74 -41
- data/defaults.reek +0 -131
- data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
- 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 -36
- data/lib/reek/report/formatter.rb +0 -33
- 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/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
- /data/samples/{clean.rb → clean_source/clean.rb} +0 -0
- /data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
- /data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
- /data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
- /data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
- /data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
- /data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
- /data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
- /data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
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.
|
|
@@ -27,20 +27,20 @@ module Reek
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
#
|
|
30
|
-
# Here you should document what you expect
|
|
30
|
+
# Here you should document what you expect the detector's context to look
|
|
31
|
+
# like.
|
|
31
32
|
#
|
|
32
33
|
# @return [Array<SmellWarning>]
|
|
33
34
|
#
|
|
34
|
-
def sniff
|
|
35
|
+
def sniff
|
|
35
36
|
# "found_smells" below is just an abstraction for
|
|
36
|
-
# "find the smells in question" and
|
|
37
|
+
# "find the smells in question" and iterate over them.
|
|
37
38
|
# This can just be a method but it can also be a more sophisticated set up.
|
|
38
39
|
# Check out other smell detectors to get a feeling for what to do here.
|
|
39
|
-
found_smells
|
|
40
|
+
found_smells.map do |smell|
|
|
40
41
|
# "smell_warning" is defined in BaseDetector and should be used by you
|
|
41
42
|
# to construct smell warnings
|
|
42
43
|
smell_warning(
|
|
43
|
-
context: ctx,
|
|
44
44
|
lines: [], # lines on which the smell was detected
|
|
45
45
|
message: "...", # the message that is printed on STDOUT
|
|
46
46
|
# whatever you interpolate into the "message" should go into
|
|
@@ -61,7 +61,7 @@ end
|
|
|
61
61
|
|
|
62
62
|
For your detector to be properly loaded you need to require it in `lib/reek/smell_detectors.rb` as well.
|
|
63
63
|
|
|
64
|
-
### defaults.reek
|
|
64
|
+
### defaults.reek.yml
|
|
65
65
|
|
|
66
66
|
After you ran
|
|
67
67
|
|
|
@@ -69,7 +69,7 @@ After you ran
|
|
|
69
69
|
bundle exec rake
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
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`
|
|
73
73
|
file should have been updated automatically. Make sure you don't forget to check
|
|
74
74
|
in those changes as well.
|
|
75
75
|
|
|
@@ -61,7 +61,7 @@ end
|
|
|
61
61
|
would report:
|
|
62
62
|
|
|
63
63
|
```Bash
|
|
64
|
-
[1]:InstanceVariableAssumption: Dummy assumes too much for instance variable @ivar
|
|
64
|
+
[1]:InstanceVariableAssumption: Dummy assumes too much for instance variable @ivar
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
Note that this example would trigger this smell warning as well:
|
|
@@ -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
|
+
|
|
@@ -14,7 +14,7 @@ Reek::Rake::Task.new do |t|
|
|
|
14
14
|
end
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Now the command `reek` will run Reek on your source code (and in this case, it fails if it finds any smells). For more detailed information about Reek's integration with Rake, see [Rake Task](Rake-Task.md)
|
|
17
|
+
Now the command `reek` will run Reek on your source code (and in this case, it fails if it finds any smells). For more detailed information about Reek's integration with Rake, see [Rake Task](Rake-Task.md).
|
|
18
18
|
|
|
19
19
|
## reek/spec
|
|
20
20
|
|