reek 4.7.3 → 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 +18 -3
- data/.simplecov +1 -0
- data/.travis.yml +3 -4
- data/.yardopts +1 -1
- data/CHANGELOG.md +45 -0
- data/Gemfile +4 -4
- 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 +2 -3
- 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 +2 -2
- 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 +78 -73
- 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 +2 -2
- data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
- data/features/locales.feature +2 -2
- data/features/rake_task/rake_task.feature +15 -15
- 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 +9 -1
- data/features/samples.feature +287 -287
- 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 +26 -23
- data/lib/reek/ast/node.rb +40 -55
- 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/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 +29 -14
- 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 +8 -11
- data/lib/reek/context/method_context.rb +7 -12
- data/lib/reek/context/module_context.rb +4 -4
- data/lib/reek/context_builder.rb +11 -11
- data/lib/reek/detector_repository.rb +6 -0
- data/lib/reek/documentation_link.rb +28 -0
- data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +13 -12
- data/lib/reek/errors/bad_detector_in_comment_error.rb +11 -10
- 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 +16 -11
- data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +11 -10
- data/lib/reek/errors/incomprehensible_source_error.rb +20 -22
- data/lib/reek/errors/syntax_error.rb +41 -0
- data/lib/reek/examiner.rb +19 -25
- data/lib/reek/logging_error_handler.rb +7 -5
- data/lib/reek/rake/task.rb +3 -3
- 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 +0 -1
- data/lib/reek/smell_detectors/base_detector.rb +9 -12
- data/lib/reek/smell_detectors/boolean_parameter.rb +0 -1
- data/lib/reek/smell_detectors/class_variable.rb +3 -11
- 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 +6 -7
- data/lib/reek/smell_detectors/feature_envy.rb +1 -1
- data/lib/reek/smell_detectors/instance_variable_assumption.rb +1 -10
- 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 +3 -3
- data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +6 -7
- data/lib/reek/smell_detectors/module_initialize.rb +1 -2
- data/lib/reek/smell_detectors/nested_iterators.rb +6 -6
- 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 +2 -3
- 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 +6 -7
- 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 +2 -3
- data/lib/reek/smell_detectors.rb +1 -2
- data/lib/reek/smell_warning.rb +15 -8
- data/lib/reek/source/source_code.rb +50 -72
- data/lib/reek/source/source_locator.rb +7 -7
- 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 +5 -5
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +5 -5
- 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 +2 -2
- data/spec/reek/cli/application_spec.rb +50 -38
- 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 -49
- 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 +60 -96
- data/spec/reek/context/ghost_context_spec.rb +1 -1
- data/spec/reek/context/root_context_spec.rb +1 -1
- 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 +100 -30
- 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/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/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +9 -9
- 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 +6 -4
- 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 +10 -10
- data/spec/reek/smell_detectors/utility_function_spec.rb +5 -5
- data/spec/reek/smell_warning_spec.rb +12 -8
- data/spec/reek/source/source_code_spec.rb +17 -43
- data/spec/reek/source/source_locator_spec.rb +17 -17
- data/spec/reek/spec/should_reek_of_spec.rb +7 -11
- data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
- data/spec/reek/spec/should_reek_spec.rb +3 -3
- data/spec/reek/spec/smell_matcher_spec.rb +3 -3
- data/spec/reek/tree_dresser_spec.rb +12 -17
- data/spec/spec_helper.rb +6 -17
- data/tasks/configuration.rake +8 -5
- metadata +71 -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
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: map
|
|
3
|
+
mapping:
|
|
4
|
+
"detectors":
|
|
5
|
+
type: map
|
|
6
|
+
mapping: &all_detectors
|
|
7
|
+
Attribute:
|
|
8
|
+
type: map
|
|
9
|
+
mapping: &detector_base
|
|
10
|
+
"enabled":
|
|
11
|
+
type: bool
|
|
12
|
+
"exclude":
|
|
13
|
+
type: seq
|
|
14
|
+
sequence:
|
|
15
|
+
- type: str
|
|
16
|
+
BooleanParameter:
|
|
17
|
+
type: map
|
|
18
|
+
mapping:
|
|
19
|
+
<<: *detector_base
|
|
20
|
+
ClassVariable:
|
|
21
|
+
type: map
|
|
22
|
+
mapping:
|
|
23
|
+
<<: *detector_base
|
|
24
|
+
ControlParameter:
|
|
25
|
+
type: map
|
|
26
|
+
mapping:
|
|
27
|
+
<<: *detector_base
|
|
28
|
+
DataClump:
|
|
29
|
+
type: map
|
|
30
|
+
mapping:
|
|
31
|
+
<<: *detector_base
|
|
32
|
+
max_copies:
|
|
33
|
+
type: number
|
|
34
|
+
min_clump_size:
|
|
35
|
+
type: number
|
|
36
|
+
DuplicateMethodCall:
|
|
37
|
+
type: map
|
|
38
|
+
mapping:
|
|
39
|
+
<<: *detector_base
|
|
40
|
+
max_calls:
|
|
41
|
+
type: number
|
|
42
|
+
allow_calls:
|
|
43
|
+
type: seq
|
|
44
|
+
sequence:
|
|
45
|
+
- type: str
|
|
46
|
+
FeatureEnvy:
|
|
47
|
+
type: map
|
|
48
|
+
mapping:
|
|
49
|
+
<<: *detector_base
|
|
50
|
+
InstanceVariableAssumption:
|
|
51
|
+
type: map
|
|
52
|
+
mapping:
|
|
53
|
+
<<: *detector_base
|
|
54
|
+
IrresponsibleModule:
|
|
55
|
+
type: map
|
|
56
|
+
mapping:
|
|
57
|
+
<<: *detector_base
|
|
58
|
+
LongParameterList:
|
|
59
|
+
type: map
|
|
60
|
+
mapping:
|
|
61
|
+
<<: *detector_base
|
|
62
|
+
max_params:
|
|
63
|
+
type: number
|
|
64
|
+
overrides:
|
|
65
|
+
type: map
|
|
66
|
+
mapping:
|
|
67
|
+
initialize:
|
|
68
|
+
type: map
|
|
69
|
+
mapping:
|
|
70
|
+
max_params:
|
|
71
|
+
type: number
|
|
72
|
+
LongYieldList:
|
|
73
|
+
type: map
|
|
74
|
+
mapping:
|
|
75
|
+
<<: *detector_base
|
|
76
|
+
max_params:
|
|
77
|
+
type: number
|
|
78
|
+
ManualDispatch:
|
|
79
|
+
type: map
|
|
80
|
+
mapping:
|
|
81
|
+
<<: *detector_base
|
|
82
|
+
MissingSafeMethod:
|
|
83
|
+
type: map
|
|
84
|
+
mapping:
|
|
85
|
+
<<: *detector_base
|
|
86
|
+
ModuleInitialize:
|
|
87
|
+
type: map
|
|
88
|
+
mapping:
|
|
89
|
+
<<: *detector_base
|
|
90
|
+
NestedIterators:
|
|
91
|
+
type: map
|
|
92
|
+
mapping:
|
|
93
|
+
<<: *detector_base
|
|
94
|
+
max_allowed_nesting:
|
|
95
|
+
type: number
|
|
96
|
+
ignore_iterators:
|
|
97
|
+
type: seq
|
|
98
|
+
sequence:
|
|
99
|
+
- type: str
|
|
100
|
+
NilCheck:
|
|
101
|
+
type: map
|
|
102
|
+
mapping:
|
|
103
|
+
<<: *detector_base
|
|
104
|
+
RepeatedConditional:
|
|
105
|
+
type: map
|
|
106
|
+
mapping:
|
|
107
|
+
<<: *detector_base
|
|
108
|
+
max_ifs:
|
|
109
|
+
type: number
|
|
110
|
+
SubclassedFromCoreClass:
|
|
111
|
+
type: map
|
|
112
|
+
mapping:
|
|
113
|
+
<<: *detector_base
|
|
114
|
+
Syntax:
|
|
115
|
+
type: map
|
|
116
|
+
mapping:
|
|
117
|
+
<<: *detector_base
|
|
118
|
+
TooManyConstants:
|
|
119
|
+
type: map
|
|
120
|
+
mapping:
|
|
121
|
+
<<: *detector_base
|
|
122
|
+
max_constants:
|
|
123
|
+
type: number
|
|
124
|
+
TooManyInstanceVariables:
|
|
125
|
+
type: map
|
|
126
|
+
mapping:
|
|
127
|
+
<<: *detector_base
|
|
128
|
+
max_instance_variables:
|
|
129
|
+
type: number
|
|
130
|
+
TooManyMethods:
|
|
131
|
+
type: map
|
|
132
|
+
mapping:
|
|
133
|
+
<<: *detector_base
|
|
134
|
+
max_methods:
|
|
135
|
+
type: number
|
|
136
|
+
TooManyStatements:
|
|
137
|
+
type: map
|
|
138
|
+
mapping:
|
|
139
|
+
<<: *detector_base
|
|
140
|
+
max_statements:
|
|
141
|
+
type: number
|
|
142
|
+
UncommunicativeMethodName:
|
|
143
|
+
type: map
|
|
144
|
+
mapping:
|
|
145
|
+
<<: *detector_base
|
|
146
|
+
reject: &reject_settings
|
|
147
|
+
type: seq
|
|
148
|
+
sequence:
|
|
149
|
+
- type: str
|
|
150
|
+
accept: &accept_settings
|
|
151
|
+
type: seq
|
|
152
|
+
sequence:
|
|
153
|
+
- type: str
|
|
154
|
+
UncommunicativeModuleName:
|
|
155
|
+
type: map
|
|
156
|
+
mapping:
|
|
157
|
+
<<: *detector_base
|
|
158
|
+
reject: *reject_settings
|
|
159
|
+
accept: *accept_settings
|
|
160
|
+
UncommunicativeParameterName:
|
|
161
|
+
type: map
|
|
162
|
+
mapping:
|
|
163
|
+
<<: *detector_base
|
|
164
|
+
reject: *reject_settings
|
|
165
|
+
accept: *accept_settings
|
|
166
|
+
UncommunicativeVariableName:
|
|
167
|
+
type: map
|
|
168
|
+
mapping:
|
|
169
|
+
<<: *detector_base
|
|
170
|
+
reject: *reject_settings
|
|
171
|
+
accept: *accept_settings
|
|
172
|
+
UnusedParameters:
|
|
173
|
+
type: map
|
|
174
|
+
mapping:
|
|
175
|
+
<<: *detector_base
|
|
176
|
+
UnusedPrivateMethod:
|
|
177
|
+
type: map
|
|
178
|
+
mapping:
|
|
179
|
+
<<: *detector_base
|
|
180
|
+
UtilityFunction:
|
|
181
|
+
type: map
|
|
182
|
+
mapping:
|
|
183
|
+
<<: *detector_base
|
|
184
|
+
public_methods_only:
|
|
185
|
+
type: bool
|
|
186
|
+
|
|
187
|
+
"directories":
|
|
188
|
+
type: map
|
|
189
|
+
mapping:
|
|
190
|
+
# For any given key that is not matched somewhere else we'll apply the schema below.
|
|
191
|
+
# So this will just slurp in every directory we throw at it and then validate everything under
|
|
192
|
+
# it against all detectors - for instance:
|
|
193
|
+
#
|
|
194
|
+
# directories:
|
|
195
|
+
# "web_app/app/controllers":
|
|
196
|
+
# NestedIterators:
|
|
197
|
+
# enabled: false
|
|
198
|
+
# "web_app/app/helpers":
|
|
199
|
+
# UtilityFunction:
|
|
200
|
+
# enabled: false
|
|
201
|
+
#
|
|
202
|
+
# For details check out: http://www.kuwata-lab.com/kwalify/ruby/users-guide.02.html#tips-default
|
|
203
|
+
=:
|
|
204
|
+
type: map
|
|
205
|
+
mapping: *all_detectors
|
|
206
|
+
|
|
207
|
+
"exclude_paths":
|
|
208
|
+
type: seq
|
|
209
|
+
sequence:
|
|
210
|
+
- type: str
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
require_relative '../cli/silencer'
|
|
5
|
+
Reek::CLI::Silencer.without_warnings { require 'kwalify' }
|
|
6
|
+
require_relative '../errors/config_file_error'
|
|
7
|
+
|
|
8
|
+
module Reek
|
|
9
|
+
module Configuration
|
|
10
|
+
#
|
|
11
|
+
# Schema validator module.
|
|
12
|
+
#
|
|
13
|
+
class SchemaValidator
|
|
14
|
+
SCHEMA_FILE_PATH = File.expand_path('./schema.yml', __dir__)
|
|
15
|
+
|
|
16
|
+
def initialize(configuration)
|
|
17
|
+
@configuration = configuration
|
|
18
|
+
@validator = CLI::Silencer.without_warnings do
|
|
19
|
+
schema_file = Kwalify::Yaml.load_file(SCHEMA_FILE_PATH)
|
|
20
|
+
Kwalify::Validator.new(schema_file)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def validate
|
|
25
|
+
errors = CLI::Silencer.without_warnings { @validator.validate @configuration }
|
|
26
|
+
return if !errors || errors.empty?
|
|
27
|
+
raise Errors::ConfigFileError, error_message(errors)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# :reek:UtilityFunction
|
|
33
|
+
def error_message(errors)
|
|
34
|
+
"We found some problems with your configuration file: #{CLI::Silencer.silently { errors.join(', ') }}"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -14,12 +14,11 @@ module Reek
|
|
|
14
14
|
# code element. CodeContexts form a tree in the same way the code does,
|
|
15
15
|
# with each context holding a reference to a unique outer context.
|
|
16
16
|
#
|
|
17
|
-
# :reek:TooManyMethods
|
|
18
|
-
# :reek:TooManyInstanceVariables
|
|
17
|
+
# @quality :reek:TooManyMethods { max_methods: 19 }
|
|
18
|
+
# @quality :reek:TooManyInstanceVariables { max_instance_variables: 8 }
|
|
19
19
|
class CodeContext
|
|
20
20
|
include Enumerable
|
|
21
21
|
extend Forwardable
|
|
22
|
-
delegate each_node: :exp
|
|
23
22
|
delegate [:name, :type] => :exp
|
|
24
23
|
|
|
25
24
|
attr_reader :children, :parent, :exp, :statement_counter
|
|
@@ -40,12 +39,12 @@ module Reek
|
|
|
40
39
|
# @yield block that is executed for every node.
|
|
41
40
|
#
|
|
42
41
|
def local_nodes(type, ignored = [], &blk)
|
|
43
|
-
ignored
|
|
44
|
-
each_node(type, ignored, &blk)
|
|
42
|
+
ignored |= [:class, :module]
|
|
43
|
+
exp.each_node(type, ignored, &blk)
|
|
45
44
|
end
|
|
46
45
|
|
|
47
46
|
# Iterate over `self` and child contexts.
|
|
48
|
-
# The main difference (among others) to `
|
|
47
|
+
# The main difference (among others) to `local_nodes` is that we are traversing
|
|
49
48
|
# `CodeContexts` here, not AST nodes (see `Reek::AST::Node`).
|
|
50
49
|
#
|
|
51
50
|
# @yield block that is executed for every node.
|
|
@@ -111,17 +110,15 @@ module Reek
|
|
|
111
110
|
self
|
|
112
111
|
end
|
|
113
112
|
|
|
114
|
-
# :reek:TooManyStatements
|
|
115
|
-
# :reek:FeatureEnvy
|
|
113
|
+
# @quality :reek:TooManyStatements { max_statements: 6 }
|
|
114
|
+
# @quality :reek:FeatureEnvy
|
|
116
115
|
def record_call_to(exp)
|
|
117
116
|
receiver = exp.receiver
|
|
118
117
|
type = receiver ? receiver.type : :self
|
|
119
118
|
line = exp.line
|
|
120
119
|
case type
|
|
121
120
|
when :lvar, :lvasgn
|
|
122
|
-
unless exp.object_creation_call?
|
|
123
|
-
refs.record_reference(name: receiver.name, line: line)
|
|
124
|
-
end
|
|
121
|
+
refs.record_reference(name: receiver.name, line: line) unless exp.object_creation_call?
|
|
125
122
|
when :self
|
|
126
123
|
refs.record_reference(name: :self, line: line)
|
|
127
124
|
end
|
|
@@ -7,7 +7,7 @@ module Reek
|
|
|
7
7
|
#
|
|
8
8
|
# A context wrapper for any method definition found in a syntax tree.
|
|
9
9
|
#
|
|
10
|
-
# :reek:Attribute
|
|
10
|
+
# @quality :reek:Attribute
|
|
11
11
|
class MethodContext < CodeContext
|
|
12
12
|
attr_accessor :visibility
|
|
13
13
|
attr_reader :refs
|
|
@@ -23,24 +23,19 @@ module Reek
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def uses_param?(param)
|
|
26
|
-
#
|
|
26
|
+
# :lvasgn catches:
|
|
27
|
+
#
|
|
27
28
|
# def foo(bar); bar += 1; end
|
|
28
|
-
# In this example there is no `lvar` node present.
|
|
29
29
|
#
|
|
30
|
-
#
|
|
30
|
+
# :lvar catches:
|
|
31
|
+
#
|
|
31
32
|
# def foo(bar); other(bar); end
|
|
32
33
|
# def foo(bar); tmp = other(bar); tmp[0]; end
|
|
33
34
|
#
|
|
34
|
-
|
|
35
|
-
# This means that if we would just search for [:lvar, :lvasgn]
|
|
36
|
-
# (e.g. via Reek::AST::Node#find_nodes) this would fail for this example since we would
|
|
37
|
-
# stop at the `lvasgn` and not detect the contained `lvar`.
|
|
38
|
-
# Hence we first get all `lvar` nodes followed by all `lvasgn` nodes.
|
|
39
|
-
#
|
|
40
|
-
(local_nodes(:lvar) + local_nodes(:lvasgn)).find { |node| node.var_name == param.name }
|
|
35
|
+
local_nodes([:lvar, :lvasgn]).find { |node| node.var_name == param.name }
|
|
41
36
|
end
|
|
42
37
|
|
|
43
|
-
# :reek:FeatureEnvy
|
|
38
|
+
# @quality :reek:FeatureEnvy
|
|
44
39
|
def unused_params
|
|
45
40
|
exp.arguments.reject do |param|
|
|
46
41
|
param.anonymous_splat? ||
|
|
@@ -43,9 +43,9 @@ module Reek
|
|
|
43
43
|
AttributeContext
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
def defined_instance_methods(visibility: :
|
|
46
|
+
def defined_instance_methods(visibility: :any)
|
|
47
47
|
instance_method_children.select do |context|
|
|
48
|
-
context.visibility == visibility
|
|
48
|
+
visibility == :any || context.visibility == visibility
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
@@ -59,7 +59,7 @@ module Reek
|
|
|
59
59
|
# @deprecated use `defined_instance_methods` instead
|
|
60
60
|
#
|
|
61
61
|
def node_instance_methods
|
|
62
|
-
local_nodes(:def)
|
|
62
|
+
local_nodes(:def).to_a
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def descriptively_commented?
|
|
@@ -73,7 +73,7 @@ module Reek
|
|
|
73
73
|
#
|
|
74
74
|
# @return true if the module is a namespace module
|
|
75
75
|
#
|
|
76
|
-
# :reek:FeatureEnvy
|
|
76
|
+
# @quality :reek:FeatureEnvy
|
|
77
77
|
def namespace_module?
|
|
78
78
|
return false if exp.type == :casgn
|
|
79
79
|
children = exp.direct_children
|
data/lib/reek/context_builder.rb
CHANGED
|
@@ -20,9 +20,9 @@ module Reek
|
|
|
20
20
|
# counting. Ideally `ContextBuilder` would only build up the context tree and leave the
|
|
21
21
|
# statement and reference counting to the contexts.
|
|
22
22
|
#
|
|
23
|
-
# :reek:TooManyMethods
|
|
24
|
-
# :reek:UnusedPrivateMethod
|
|
25
|
-
# :reek:DataClump
|
|
23
|
+
# @quality :reek:TooManyMethods { max_methods: 31 }
|
|
24
|
+
# @quality :reek:UnusedPrivateMethod { exclude: [ !ruby/regexp /process_/ ] }
|
|
25
|
+
# @quality :reek:DataClump
|
|
26
26
|
class ContextBuilder
|
|
27
27
|
attr_reader :context_tree
|
|
28
28
|
|
|
@@ -206,7 +206,7 @@ module Reek
|
|
|
206
206
|
#
|
|
207
207
|
# def self.foo; end
|
|
208
208
|
#
|
|
209
|
-
def process_self(
|
|
209
|
+
def process_self(_exp, _parent)
|
|
210
210
|
current_context.record_use_of_self
|
|
211
211
|
end
|
|
212
212
|
|
|
@@ -226,7 +226,7 @@ module Reek
|
|
|
226
226
|
#
|
|
227
227
|
# We record one reference to `self`.
|
|
228
228
|
#
|
|
229
|
-
def process_zsuper(
|
|
229
|
+
def process_zsuper(_exp, _parent)
|
|
230
230
|
current_context.record_use_of_self
|
|
231
231
|
end
|
|
232
232
|
|
|
@@ -470,7 +470,7 @@ module Reek
|
|
|
470
470
|
self.class.private_method_defined?(name)
|
|
471
471
|
end
|
|
472
472
|
|
|
473
|
-
# :reek:ControlParameter
|
|
473
|
+
# @quality :reek:ControlParameter
|
|
474
474
|
def increase_statement_count_by(sexp)
|
|
475
475
|
current_context.statement_counter.increase_by sexp
|
|
476
476
|
end
|
|
@@ -482,8 +482,8 @@ module Reek
|
|
|
482
482
|
# Stores a reference to the current context, creates a nested new one,
|
|
483
483
|
# yields to the given block and then restores the previous context.
|
|
484
484
|
#
|
|
485
|
-
# @param klass [Context::*Context]
|
|
486
|
-
# @param args
|
|
485
|
+
# @param klass [Context::*Context] context class
|
|
486
|
+
# @param args arguments for the class initializer
|
|
487
487
|
# @yield block
|
|
488
488
|
#
|
|
489
489
|
def inside_new_context(klass, *args)
|
|
@@ -497,10 +497,10 @@ module Reek
|
|
|
497
497
|
# Appends a new child context to the current context but does not change
|
|
498
498
|
# the current context.
|
|
499
499
|
#
|
|
500
|
-
# @param klass [Context::*Context]
|
|
501
|
-
# @param args
|
|
500
|
+
# @param klass [Context::*Context] context class
|
|
501
|
+
# @param args arguments for the class initializer
|
|
502
502
|
#
|
|
503
|
-
# @return [Context::*Context]
|
|
503
|
+
# @return [Context::*Context] the context that was appended
|
|
504
504
|
#
|
|
505
505
|
def append_new_context(klass, *args)
|
|
506
506
|
klass.new(*args).tap do |new_context|
|
|
@@ -44,6 +44,12 @@ module Reek
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
# @return [Array<String>] The names of all known SmellDetectors
|
|
48
|
+
# e.g. ["BooleanParameter", "ClassVariable"].
|
|
49
|
+
def self.available_detector_names
|
|
50
|
+
smell_types.map(&:smell_type)
|
|
51
|
+
end
|
|
52
|
+
|
|
47
53
|
private
|
|
48
54
|
|
|
49
55
|
attr_reader :configuration, :smell_types
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Reek
|
|
4
|
+
# Generate versioned links to our documentation
|
|
5
|
+
module DocumentationLink
|
|
6
|
+
HELP_LINK_TEMPLATE = 'https://github.com/troessner/reek/blob/v%<version>s/docs/%<item>s.md'
|
|
7
|
+
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
# Build link to the documentation about the given subject for the current
|
|
11
|
+
# version of Reek. The subject can be either a smell type like
|
|
12
|
+
# 'FeatureEnvy' or a general subject like 'Rake Task'.
|
|
13
|
+
#
|
|
14
|
+
# @param subject [String]
|
|
15
|
+
# @return [String] the full URL for the relevant documentation
|
|
16
|
+
def build(subject)
|
|
17
|
+
Kernel.format(HELP_LINK_TEMPLATE, version: Version::STRING, item: name_to_param(subject))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Convert the given subject name to a form that is acceptable in a URL.
|
|
21
|
+
def name_to_param(name)
|
|
22
|
+
# Splits the subject on the start of capitalized words, optionally
|
|
23
|
+
# preceded by a space. The space is discarded, the start of the word is
|
|
24
|
+
# not.
|
|
25
|
+
name.split(/ *(?=[A-Z][a-z])/).join('-')
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'base_error'
|
|
4
|
+
require_relative '../documentation_link'
|
|
4
5
|
|
|
5
6
|
module Reek
|
|
6
7
|
module Errors
|
|
7
8
|
# Gets raised when trying to configure a detector with an option
|
|
8
9
|
# which is unknown to it.
|
|
9
10
|
class BadDetectorConfigurationKeyInCommentError < BaseError
|
|
10
|
-
UNKNOWN_SMELL_DETECTOR_MESSAGE = <<-MESSAGE
|
|
11
|
+
UNKNOWN_SMELL_DETECTOR_MESSAGE = <<-MESSAGE
|
|
11
12
|
|
|
12
|
-
Error: You are trying to configure the smell detector '
|
|
13
|
-
in one of your source code comments with the unknown option
|
|
14
|
-
The source is '
|
|
13
|
+
Error: You are trying to configure the smell detector '%<detector>s'
|
|
14
|
+
in one of your source code comments with the unknown option %<option>s.
|
|
15
|
+
The source is '%<source>s' and the comment belongs to the expression starting in line %<line>d.
|
|
15
16
|
Here's the original comment:
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
%<comment>s
|
|
18
19
|
|
|
19
20
|
Please see the Reek docs for:
|
|
20
|
-
* how to configure Reek via source code comments:
|
|
21
|
-
* what basic options are available:
|
|
21
|
+
* how to configure Reek via source code comments: #{DocumentationLink.build('Smell Suppression')}
|
|
22
|
+
* what basic options are available: #{DocumentationLink.build('Basic Smell Options')}
|
|
22
23
|
* what custom options are available by checking the detector specific documentation in /docs
|
|
23
24
|
Update the offensive comment (or remove it if no longer applicable) and re-run Reek.
|
|
24
25
|
|
|
@@ -26,11 +27,11 @@ module Reek
|
|
|
26
27
|
|
|
27
28
|
def initialize(detector_name:, offensive_keys:, source:, line:, original_comment:)
|
|
28
29
|
message = format(UNKNOWN_SMELL_DETECTOR_MESSAGE,
|
|
29
|
-
detector_name,
|
|
30
|
-
offensive_keys,
|
|
31
|
-
source,
|
|
32
|
-
line,
|
|
33
|
-
original_comment)
|
|
30
|
+
detector: detector_name,
|
|
31
|
+
option: offensive_keys,
|
|
32
|
+
source: source,
|
|
33
|
+
line: line,
|
|
34
|
+
comment: original_comment)
|
|
34
35
|
super message
|
|
35
36
|
end
|
|
36
37
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'base_error'
|
|
4
|
+
require_relative '../documentation_link'
|
|
4
5
|
|
|
5
6
|
module Reek
|
|
6
7
|
module Errors
|
|
@@ -8,28 +9,28 @@ module Reek
|
|
|
8
9
|
# This might happen for multiple reasons. The users might have a typo in
|
|
9
10
|
# his comment or he might use a detector that does not exist anymore.
|
|
10
11
|
class BadDetectorInCommentError < BaseError
|
|
11
|
-
UNKNOWN_SMELL_DETECTOR_MESSAGE = <<-MESSAGE
|
|
12
|
+
UNKNOWN_SMELL_DETECTOR_MESSAGE = <<-MESSAGE
|
|
12
13
|
|
|
13
|
-
Error: You are trying to configure an unknown smell detector '
|
|
14
|
+
Error: You are trying to configure an unknown smell detector '%<detector>s' in one
|
|
14
15
|
of your source code comments.
|
|
15
|
-
The source is '
|
|
16
|
+
The source is '%<source>s' and the comment belongs to the expression starting in line %<line>d.
|
|
16
17
|
Here's the original comment:
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
%<comment>s
|
|
19
20
|
|
|
20
21
|
Please see the Reek docs for:
|
|
21
|
-
* how to configure Reek via source code comments:
|
|
22
|
-
* what smell detectors are available:
|
|
22
|
+
* how to configure Reek via source code comments: #{DocumentationLink.build('Smell Suppression')}
|
|
23
|
+
* what smell detectors are available: #{DocumentationLink.build('Code Smells')}
|
|
23
24
|
Update the offensive comment (or remove it if no longer applicable) and re-run Reek.
|
|
24
25
|
|
|
25
26
|
MESSAGE
|
|
26
27
|
|
|
27
28
|
def initialize(detector_name:, source:, line:, original_comment:)
|
|
28
29
|
message = format(UNKNOWN_SMELL_DETECTOR_MESSAGE,
|
|
29
|
-
detector_name,
|
|
30
|
-
source,
|
|
31
|
-
line,
|
|
32
|
-
original_comment)
|
|
30
|
+
detector: detector_name,
|
|
31
|
+
source: source,
|
|
32
|
+
line: line,
|
|
33
|
+
comment: original_comment)
|
|
33
34
|
super message
|
|
34
35
|
end
|
|
35
36
|
end
|
|
@@ -6,9 +6,11 @@ module Reek
|
|
|
6
6
|
module Errors
|
|
7
7
|
# Gets raised when Reek is unable to process the source due to an EncodingError
|
|
8
8
|
class EncodingError < BaseError
|
|
9
|
-
|
|
9
|
+
TEMPLATE = "Source '%<source>s' cannot be processed by Reek due to an encoding error in the source file."
|
|
10
|
+
|
|
11
|
+
LONG_TEMPLATE = <<-MESSAGE
|
|
10
12
|
!!!
|
|
11
|
-
|
|
13
|
+
%<message>s
|
|
12
14
|
|
|
13
15
|
This is a problem that is outside of Reek's scope and should be fixed by you, the
|
|
14
16
|
user, in order for Reek being able to continue.
|
|
@@ -17,21 +19,24 @@ module Reek
|
|
|
17
19
|
|
|
18
20
|
Exception message:
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
%<exception>s
|
|
21
23
|
|
|
22
|
-
Original
|
|
24
|
+
Original backtrace:
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
%<original>s
|
|
25
27
|
|
|
26
28
|
!!!
|
|
27
29
|
MESSAGE
|
|
28
30
|
|
|
29
|
-
def initialize(origin
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
def initialize(origin:)
|
|
32
|
+
super format(TEMPLATE, source: origin)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def long_message
|
|
36
|
+
format(LONG_TEMPLATE,
|
|
37
|
+
message: message,
|
|
38
|
+
exception: cause.inspect,
|
|
39
|
+
original: cause.backtrace.join("\n\t"))
|
|
35
40
|
end
|
|
36
41
|
end
|
|
37
42
|
end
|