reek 2.0.4 → 3.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/.gitignore +13 -0
- data/.rubocop.yml +47 -0
- data/.travis.yml +31 -0
- data/.yardopts +3 -6
- data/CHANGELOG +24 -0
- data/CONTRIBUTING.md +111 -0
- data/Gemfile +16 -0
- data/README.md +112 -59
- data/bin/reek +2 -2
- data/config/cucumber.yml +3 -0
- data/config/defaults.reek +0 -1
- data/docs/API.md +79 -0
- data/docs/Attribute.md +43 -0
- data/docs/Basic-Smell-Options.md +44 -0
- data/docs/Boolean-Parameter.md +52 -0
- data/docs/Class-Variable.md +40 -0
- data/docs/Code-Smells.md +34 -0
- data/docs/Command-Line-Options.md +84 -0
- data/docs/Configuration-Files.md +49 -0
- data/docs/Control-Couple.md +22 -0
- data/docs/Control-Parameter.md +29 -0
- data/docs/Data-Clump.md +44 -0
- data/docs/Duplicate-Method-Call.md +49 -0
- data/docs/Feature-Envy.md +49 -0
- data/docs/How-reek-works-internally.md +114 -0
- data/docs/Irresponsible-Module.md +39 -0
- data/docs/Large-Class.md +20 -0
- data/docs/Long-Parameter-List.md +38 -0
- data/docs/Long-Yield-List.md +36 -0
- data/docs/Module-Initialize.md +62 -0
- data/docs/Nested-Iterators.md +38 -0
- data/docs/Nil-Check.md +39 -0
- data/docs/Prima-Donna-Method.md +53 -0
- data/docs/RSpec-matchers.md +137 -0
- data/docs/Rake-Task.md +58 -0
- data/docs/Reek-Driven-Development.md +37 -0
- data/docs/Repeated-Conditional.md +44 -0
- data/docs/Simulated-Polymorphism.md +16 -0
- data/docs/Smell-Suppression.md +32 -0
- data/docs/Too-Many-Instance-Variables.md +43 -0
- data/docs/Too-Many-Methods.md +55 -0
- data/docs/Too-Many-Statements.md +50 -0
- data/docs/Uncommunicative-Method-Name.md +24 -0
- data/docs/Uncommunicative-Module-Name.md +23 -0
- data/docs/Uncommunicative-Name.md +16 -0
- data/docs/Uncommunicative-Parameter-Name.md +24 -0
- data/docs/Uncommunicative-Variable-Name.md +24 -0
- data/docs/Unused-Parameters.md +27 -0
- data/docs/Utility-Function.md +44 -0
- data/docs/Versioning-Policy.md +7 -0
- data/docs/YAML-Reports.md +111 -0
- data/docs/yard_plugin.rb +14 -0
- data/features/{ruby_api/api.feature → command_line_interface/basic_usage.feature} +6 -5
- data/features/command_line_interface/options.feature +1 -0
- data/features/command_line_interface/smell_selection.feature +4 -8
- data/features/command_line_interface/smells_count.feature +25 -32
- data/features/command_line_interface/stdin.feature +2 -2
- data/features/configuration_files/masking_smells.feature +30 -41
- data/features/configuration_files/overrides_defaults.feature +5 -3
- data/features/configuration_loading.feature +26 -23
- data/features/programmatic_access.feature +43 -0
- data/features/rake_task/rake_task.feature +25 -22
- data/features/reports/json.feature +24 -26
- data/features/reports/reports.feature +77 -103
- data/features/reports/yaml.feature +26 -20
- data/features/samples.feature +26 -31
- data/features/step_definitions/.rubocop.yml +5 -0
- data/features/step_definitions/reek_steps.rb +16 -28
- data/features/step_definitions/sample_file_steps.rb +158 -0
- data/features/support/env.rb +16 -27
- data/lib/reek/{source → ast}/ast_node_class_map.rb +11 -12
- data/lib/reek/ast/node.rb +132 -0
- data/lib/reek/{core → ast}/object_refs.rb +2 -1
- data/lib/reek/ast/reference_collector.rb +32 -0
- data/lib/reek/{source → ast}/sexp_extensions.rb +43 -7
- data/lib/reek/ast/sexp_formatter.rb +31 -0
- data/lib/reek/cli/application.rb +5 -4
- data/lib/reek/cli/command.rb +2 -1
- data/lib/reek/cli/input.rb +6 -5
- data/lib/reek/cli/option_interpreter.rb +13 -9
- data/lib/reek/cli/options.rb +16 -8
- data/lib/reek/cli/reek_command.rb +4 -3
- data/lib/reek/cli/silencer.rb +14 -0
- data/lib/reek/{core → cli}/warning_collector.rb +2 -1
- data/lib/reek/code_comment.rb +36 -0
- data/lib/reek/configuration/app_configuration.rb +18 -3
- data/lib/reek/configuration/configuration_file_finder.rb +18 -32
- data/lib/reek/{core → context}/code_context.rb +8 -6
- data/lib/reek/{core → context}/method_context.rb +11 -5
- data/lib/reek/{core → context}/module_context.rb +9 -4
- data/lib/reek/{core/stop_context.rb → context/root_context.rb} +4 -2
- data/lib/reek/{core → context}/singleton_method_context.rb +3 -6
- data/lib/reek/examiner.rb +32 -29
- data/lib/reek/report/formatter.rb +70 -0
- data/lib/reek/report/heading_formatter.rb +45 -0
- data/lib/reek/report/location_formatter.rb +35 -0
- data/lib/reek/report/report.rb +198 -0
- data/lib/reek/smells/attribute.rb +41 -11
- data/lib/reek/smells/boolean_parameter.rb +4 -2
- data/lib/reek/smells/class_variable.rb +4 -2
- data/lib/reek/smells/control_parameter.rb +4 -2
- data/lib/reek/smells/data_clump.rb +4 -3
- data/lib/reek/smells/duplicate_method_call.rb +15 -5
- data/lib/reek/smells/feature_envy.rb +8 -2
- data/lib/reek/smells/irresponsible_module.rb +13 -8
- data/lib/reek/smells/long_parameter_list.rb +6 -4
- data/lib/reek/smells/long_yield_list.rb +4 -2
- data/lib/reek/smells/module_initialize.rb +4 -2
- data/lib/reek/smells/nested_iterators.rb +4 -2
- data/lib/reek/smells/nil_check.rb +6 -3
- data/lib/reek/smells/prima_donna_method.rb +21 -12
- data/lib/reek/smells/repeated_conditional.rb +7 -4
- data/lib/reek/{core → smells}/smell_configuration.rb +3 -1
- data/lib/reek/smells/smell_detector.rb +11 -5
- data/lib/reek/{core → smells}/smell_repository.rb +9 -5
- data/lib/reek/smells/smell_warning.rb +101 -0
- data/lib/reek/smells/too_many_instance_variables.rb +4 -2
- data/lib/reek/smells/too_many_methods.rb +4 -2
- data/lib/reek/smells/too_many_statements.rb +4 -2
- data/lib/reek/smells/uncommunicative_method_name.rb +4 -2
- data/lib/reek/smells/uncommunicative_module_name.rb +4 -2
- data/lib/reek/smells/uncommunicative_parameter_name.rb +4 -2
- data/lib/reek/smells/uncommunicative_variable_name.rb +4 -2
- data/lib/reek/smells/unused_parameters.rb +4 -2
- data/lib/reek/smells/utility_function.rb +11 -22
- data/lib/reek/smells.rb +24 -11
- data/lib/reek/source/source_code.rb +69 -12
- data/lib/reek/source/source_locator.rb +34 -19
- data/lib/reek/spec/should_reek.rb +4 -3
- data/lib/reek/spec/should_reek_of.rb +2 -1
- data/lib/reek/spec/should_reek_only_of.rb +4 -3
- data/lib/reek/spec.rb +3 -3
- data/lib/reek/tree_dresser.rb +32 -0
- data/lib/reek/tree_walker.rb +182 -0
- data/lib/reek/version.rb +1 -1
- data/lib/reek.rb +3 -3
- data/reek.gemspec +18 -25
- data/spec/factories/factories.rb +4 -2
- data/spec/gem/updates_spec.rb +1 -1
- data/spec/gem/yard_spec.rb +2 -2
- data/spec/quality/reek_source_spec.rb +3 -3
- data/spec/reek/{source/sexp_node_spec.rb → ast/node_spec.rb} +4 -6
- data/spec/reek/{core → ast}/object_refs_spec.rb +4 -6
- data/spec/reek/{source → ast}/reference_collector_spec.rb +27 -19
- data/spec/reek/{source → ast}/sexp_extensions_spec.rb +7 -19
- data/spec/reek/{source → ast}/sexp_formatter_spec.rb +13 -8
- data/spec/reek/cli/option_interpreter_spec.rb +15 -0
- data/spec/reek/cli/options_spec.rb +19 -0
- data/spec/reek/cli/warning_collector_spec.rb +28 -0
- data/spec/reek/{source/code_comment_spec.rb → code_comment_spec.rb} +19 -17
- data/spec/reek/configuration/app_configuration_spec.rb +37 -26
- data/spec/reek/configuration/configuration_file_finder_spec.rb +67 -21
- data/spec/reek/{core → context}/code_context_spec.rb +18 -21
- data/spec/reek/{core → context}/method_context_spec.rb +33 -27
- data/spec/reek/{core → context}/module_context_spec.rb +5 -7
- data/spec/reek/context/root_context_spec.rb +14 -0
- data/spec/reek/context/singleton_method_context_spec.rb +17 -0
- data/spec/reek/examiner_spec.rb +9 -50
- data/spec/reek/{cli → report}/html_report_spec.rb +6 -9
- data/spec/reek/report/json_report_spec.rb +20 -0
- data/spec/reek/{cli → report}/text_report_spec.rb +16 -19
- data/spec/reek/report/xml_report_spec.rb +34 -0
- data/spec/reek/report/yaml_report_spec.rb +20 -0
- data/spec/reek/smells/attribute_spec.rb +93 -88
- data/spec/reek/smells/behaves_like_variable_detector.rb +1 -1
- data/spec/reek/smells/boolean_parameter_spec.rb +31 -5
- data/spec/reek/smells/class_variable_spec.rb +10 -10
- data/spec/reek/smells/control_parameter_spec.rb +5 -5
- data/spec/reek/smells/data_clump_spec.rb +6 -6
- data/spec/reek/smells/duplicate_method_call_spec.rb +7 -7
- data/spec/reek/smells/feature_envy_spec.rb +12 -13
- data/spec/reek/smells/irresponsible_module_spec.rb +28 -32
- data/spec/reek/smells/long_parameter_list_spec.rb +7 -7
- data/spec/reek/smells/long_yield_list_spec.rb +6 -6
- data/spec/reek/smells/module_initialize_spec.rb +4 -4
- data/spec/reek/smells/nested_iterators_spec.rb +6 -6
- data/spec/reek/smells/nil_check_spec.rb +6 -6
- data/spec/reek/smells/prima_donna_method_spec.rb +8 -5
- data/spec/reek/smells/repeated_conditional_spec.rb +18 -17
- data/spec/reek/{core → smells}/smell_configuration_spec.rb +5 -7
- data/spec/reek/smells/smell_detector_shared.rb +6 -7
- data/spec/reek/smells/smell_repository_spec.rb +29 -0
- data/spec/reek/{smell_warning_spec.rb → smells/smell_warning_spec.rb} +7 -9
- data/spec/reek/smells/too_many_instance_variables_spec.rb +5 -5
- data/spec/reek/smells/too_many_methods_spec.rb +12 -8
- data/spec/reek/smells/too_many_statements_spec.rb +10 -9
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +5 -5
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +8 -8
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +18 -6
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +10 -7
- data/spec/reek/smells/unused_parameters_spec.rb +4 -4
- data/spec/reek/smells/utility_function_spec.rb +65 -39
- data/spec/reek/source/source_code_spec.rb +10 -10
- data/spec/reek/source/source_locator_spec.rb +30 -0
- data/spec/reek/spec/should_reek_of_spec.rb +9 -25
- data/spec/reek/spec/should_reek_only_of_spec.rb +4 -7
- data/spec/reek/spec/should_reek_spec.rb +4 -32
- data/spec/reek/tree_dresser_spec.rb +16 -0
- data/spec/reek/{core/tree_walker_spec.rb → tree_walker_spec.rb} +5 -7
- data/spec/samples/checkstyle.xml +2 -0
- data/spec/samples/configuration/with_excluded_paths.reek +4 -0
- data/spec/samples/{overrides/masked/lower.reek → masked_by_dotfile/.reek} +3 -1
- data/spec/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +5 -0
- data/spec/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +2 -0
- data/spec/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +6 -0
- data/spec/samples/{ruby20_syntax.rb → unusual_syntax.rb} +8 -0
- data/spec/spec_helper.rb +21 -10
- data/tasks/develop.rake +2 -2
- data/tasks/reek.rake +1 -1
- metadata +158 -141
- data/features/support/hooks.rb +0 -15
- data/lib/reek/cli/report/formatter.rb +0 -69
- data/lib/reek/cli/report/heading_formatter.rb +0 -45
- data/lib/reek/cli/report/location_formatter.rb +0 -34
- data/lib/reek/cli/report/report.rb +0 -131
- data/lib/reek/core/tree_walker.rb +0 -180
- data/lib/reek/smell_warning.rb +0 -87
- data/lib/reek/source/ast_node.rb +0 -38
- data/lib/reek/source/code_comment.rb +0 -37
- data/lib/reek/source/core_extras.rb +0 -46
- data/lib/reek/source/reference_collector.rb +0 -27
- data/lib/reek/source/sexp_formatter.rb +0 -22
- data/lib/reek/source/sexp_node.rb +0 -79
- data/lib/reek/source/source_file.rb +0 -16
- data/lib/reek/source/source_repository.rb +0 -45
- data/lib/reek/source/tree_dresser.rb +0 -24
- data/lib/reek/source.rb +0 -16
- data/spec/reek/cli/json_report_spec.rb +0 -20
- data/spec/reek/cli/option_interperter_spec.rb +0 -14
- data/spec/reek/cli/yaml_report_spec.rb +0 -23
- data/spec/reek/core/singleton_method_context_spec.rb +0 -9
- data/spec/reek/core/smell_repository_spec.rb +0 -17
- data/spec/reek/core/stop_context_spec.rb +0 -17
- data/spec/reek/core/warning_collector_spec.rb +0 -30
- data/spec/reek/source/object_source_spec.rb +0 -20
- data/spec/reek/source/tree_dresser_spec.rb +0 -18
- data/spec/samples/config/allow_duplication.reek +0 -3
- data/spec/samples/config/deeper_nested_iterators.reek +0 -3
- data/spec/samples/configuration_loading/minimal_dirty.rb +0 -4
- data/spec/samples/configuration_loading/reek-test-run-disable_smells.reek +0 -7
- data/spec/samples/configuration_loading/reek-test-run-enable_smells.reek +0 -7
- data/spec/samples/corrupt_config_file/corrupt.reek +0 -1
- data/spec/samples/corrupt_config_file/dirty.rb +0 -8
- data/spec/samples/demo/demo.rb +0 -8
- data/spec/samples/empty_config_file/dirty.rb +0 -8
- data/spec/samples/empty_config_file/empty.reek +0 -0
- data/spec/samples/inline_config/dirty.rb +0 -16
- data/spec/samples/inline_config/masked.reek +0 -7
- data/spec/samples/mask_some/dirty.rb +0 -8
- data/spec/samples/mask_some/some.reek +0 -8
- data/spec/samples/masked/dirty.rb +0 -8
- data/spec/samples/masked/masked.reek +0 -5
- data/spec/samples/minimal_smelly_and_masked/config.reek +0 -7
- data/spec/samples/minimal_smelly_and_masked/minimal_dirty.rb +0 -4
- data/spec/samples/mixed_results/clean_one.rb +0 -7
- data/spec/samples/mixed_results/clean_three.rb +0 -7
- data/spec/samples/mixed_results/clean_two.rb +0 -7
- data/spec/samples/mixed_results/dirty_one.rb +0 -8
- data/spec/samples/mixed_results/dirty_two.rb +0 -8
- data/spec/samples/not_quite_masked/dirty.rb +0 -8
- data/spec/samples/not_quite_masked/masked.reek +0 -5
- data/spec/samples/not_quite_masked/smelly.rb +0 -3
- data/spec/samples/one_smelly_file/dirty.rb +0 -3
- data/spec/samples/overrides/masked/dirty.rb +0 -8
- data/spec/samples/overrides/upper.reek +0 -5
- data/spec/samples/overrides_defaults/camel_case.rb +0 -14
- data/spec/samples/overrides_defaults/config.reek +0 -6
- data/spec/samples/ruby21_syntax.rb +0 -5
- data/spec/samples/standard_smelly/dirty.rb +0 -8
- data/spec/samples/standard_smelly/minimal_dirty.rb +0 -4
- data/spec/samples/three_smelly_files/dirty_one.rb +0 -3
- data/spec/samples/three_smelly_files/dirty_three.rb +0 -5
- data/spec/samples/three_smelly_files/dirty_two.rb +0 -4
- /data/spec/samples/{simple_configuration.reek → configuration/simple_configuration.reek} +0 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# How reek works internally
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## The big picture
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
["class C; end" | reek] [reek lib/*.rb] [expect(files).not_to reek_of(:LargeClass)]
|
|
8
|
+
\ | |
|
|
9
|
+
\ | |
|
|
10
|
+
\ | |
|
|
11
|
+
\ creates a | |
|
|
12
|
+
\ | |
|
|
13
|
+
\ | |
|
|
14
|
+
\ | |
|
|
15
|
+
\ | |
|
|
16
|
+
\---------- Application (cli/application.rb) + |
|
|
17
|
+
Options (cli/options) |
|
|
18
|
+
| |
|
|
19
|
+
| |
|
|
20
|
+
| |
|
|
21
|
+
| |
|
|
22
|
+
creates a | |
|
|
23
|
+
| |
|
|
24
|
+
| |
|
|
25
|
+
| |
|
|
26
|
+
| |
|
|
27
|
+
ReekCommand (cli/reek_command) |
|
|
28
|
+
* uses a reporter (report/report) |
|
|
29
|
+
* uses a SourceLocator (source/source_locator) |
|
|
30
|
+
/ | \ |
|
|
31
|
+
/ | \ |
|
|
32
|
+
/ | \ |
|
|
33
|
+
Source Source Source (source/source_code) |
|
|
34
|
+
| | | |
|
|
35
|
+
| | | |
|
|
36
|
+
| | | |
|
|
37
|
+
Examiner | Examiner |
|
|
38
|
+
| |
|
|
39
|
+
| |
|
|
40
|
+
Examiner (core/examiner) --------------------------------------
|
|
41
|
+
* generates the AST out of the given source
|
|
42
|
+
* adorns the generated AST via a TreeDresser (core/tree_dresser)
|
|
43
|
+
* initializes a SmellRepository with all relevant smells (smells/smell_repository)
|
|
44
|
+
* initializes a WarningCollector (cli/warning_collector)
|
|
45
|
+
* runs all corresponding smell detectors via a Treewalker (core/tree_walker) for the SmellRepository above
|
|
46
|
+
/ | \
|
|
47
|
+
/ | \
|
|
48
|
+
/ | \
|
|
49
|
+
UtilityFunction FeatureEnvy TooManyMethods
|
|
50
|
+
\ | /
|
|
51
|
+
\ | /
|
|
52
|
+
\ | /
|
|
53
|
+
WarningCollector
|
|
54
|
+
|
|
|
55
|
+
|
|
|
56
|
+
|
|
|
57
|
+
Application output
|
|
58
|
+
|
|
59
|
+
## A closer look at how an Examiner works
|
|
60
|
+
|
|
61
|
+
The core foundation of reek and its API is the Examiner.
|
|
62
|
+
As you can see above, the Examiner is run for every source it gets passed and then runs the configured SmellDetectors.
|
|
63
|
+
The overall workflow is like this:
|
|
64
|
+
|
|
65
|
+
Examiner
|
|
66
|
+
|
|
|
67
|
+
|
|
|
68
|
+
|
|
|
69
|
+
Initialize SmellRepository only with eligible smells
|
|
70
|
+
|
|
|
71
|
+
|
|
|
72
|
+
|
|
|
73
|
+
Generate the AST out of the given source using SourceCode#syntax_tree, which works like this:
|
|
74
|
+
|
|
75
|
+
- We generate a "rough" AST using the "parser" gem
|
|
76
|
+
- We then obtain the comments from the source code separately
|
|
77
|
+
- We pass this unprocessed AST and the comment_map to TreeDresser#dress which
|
|
78
|
+
returns an instance of Reek::AST::SexpNode with type-dependent SexpExtensions mixed in.
|
|
79
|
+
|
|
80
|
+
An example should make this more palpable.
|
|
81
|
+
Given:
|
|
82
|
+
|
|
83
|
+
class C
|
|
84
|
+
def m
|
|
85
|
+
puts 'nada'
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
The AST generated by the parser gem (consisting of Parser::AST::Node) looks like this:
|
|
90
|
+
|
|
91
|
+
(class
|
|
92
|
+
(const nil :C)
|
|
93
|
+
nil
|
|
94
|
+
(def :m
|
|
95
|
+
(args)
|
|
96
|
+
(send nil :puts
|
|
97
|
+
(str "nada"))))
|
|
98
|
+
|
|
99
|
+
TreeDresser#dress would transform this into a very similar tree, but this time not consisting
|
|
100
|
+
of Parser::AST::Node but of Reek::AST::SexpNode and with node-dependent SexpExtensions
|
|
101
|
+
mixed in (noted in []):
|
|
102
|
+
|
|
103
|
+
(class [AST::SexpExtensions::ClassNode, AST::SexpExtensions::ModuleNode]
|
|
104
|
+
(const nil :C) [AST::SexpExtensions::ConstNode]
|
|
105
|
+
nil
|
|
106
|
+
(def :m [AST::SexpExtensions::DefNode, AST::SexpExtensions::MethodNodeBase]
|
|
107
|
+
(args) [AST::SexpExtensions::ArgsNode]
|
|
108
|
+
(send nil :puts [AST::SexpExtensions::SendNode]
|
|
109
|
+
(str "nada"))))
|
|
110
|
+
|
|
|
111
|
+
|
|
|
112
|
+
|
|
|
113
|
+
A TreeWalker then traverses this now adorned tree again and
|
|
114
|
+
runs all SmellDetectors from the SmellRepository above
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Irresponsible Module
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
Classes and modules are the units of reuse and release. It is therefore considered good practice to annotate every class and module with a brief comment outlining its responsibilities.
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
Given
|
|
10
|
+
|
|
11
|
+
```Ruby
|
|
12
|
+
class Dummy
|
|
13
|
+
# Do things...
|
|
14
|
+
end
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`reek` would emit the following warning:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
test.rb -- 1 warning:
|
|
21
|
+
[1]:Dummy has no descriptive comment (IrresponsibleModule)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Fixing this is simple - just an explaining comment:
|
|
25
|
+
|
|
26
|
+
```Ruby
|
|
27
|
+
# The Dummy class is responsible for ...
|
|
28
|
+
class Dummy
|
|
29
|
+
# Do things...
|
|
30
|
+
end
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Current Support in reek
|
|
34
|
+
|
|
35
|
+
`Irresponsible Module` currently checks classes, but not modules.
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
`Irresponsible Module` supports only the [Basic Smell Options](Basic-Smell-Options.md).
|
data/docs/Large-Class.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Large Class
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A `Large Class` is a class or module that has a large number of instance variables, methods or lines of code in any one piece of its specification. (That is, this smell relates to pieces of the class's specification, not to the size of the corresponding instance of `Class`.)
|
|
6
|
+
|
|
7
|
+
## Current Support in Reek
|
|
8
|
+
|
|
9
|
+
`Large Class` reports classes having more than a configurable number of methods or instance variables. The method count includes public, protected and private methods, and excludes methods inherited from superclasses or included modules.
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
`reek`'s Large Class detector supports the [Basic Smell Options](Basic-Smell-Options.md), plus:
|
|
14
|
+
|
|
15
|
+
| Option | Value | Effect |
|
|
16
|
+
| ---------------|-------------|---------|
|
|
17
|
+
| max_methods | integer | The maximum number of methods allowed in a class before a warning is issued. Defaults to 25. |
|
|
18
|
+
| max_instance_variables | integer | The maximum number of instance variables allowed in a class before a warning is issued. Defaults to 9. |
|
|
19
|
+
|
|
20
|
+
The `Large Class` detector is enabled whenever `reek` is asked to check an instance of `Class` or `Module`.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Long Parameter List
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A `Long Parameter List` occurs when a method has a lot of parameters.
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
Given
|
|
10
|
+
|
|
11
|
+
```Ruby
|
|
12
|
+
class Dummy
|
|
13
|
+
def long_list(foo,bar,baz,fling,flung)
|
|
14
|
+
puts foo,bar,baz,fling,flung
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`reek` would report the following warning:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
test.rb -- 1 warning:
|
|
23
|
+
[2]:Dummy#long_list has 5 parameters (LongParameterList)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
A common solution to this problem would be the introduction of parameter objects.
|
|
27
|
+
|
|
28
|
+
## Current Support in Reek
|
|
29
|
+
|
|
30
|
+
`Long Parameter List` reports any method or block with more than 3 parameters.
|
|
31
|
+
|
|
32
|
+
## Configuration
|
|
33
|
+
|
|
34
|
+
Reek's Long Parameter List detector supports the [Basic Smell Options](Basic-Smell-Options.md), plus:
|
|
35
|
+
|
|
36
|
+
| Option | Value | Effect |
|
|
37
|
+
| ---------------|-------------|---------|
|
|
38
|
+
| max_params | integer | The maximum number of parameters allowed in a method or block before a warning is issued. Defaults to 3. |
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Long Yield List
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A _Long Yield List_ occurs when a method yields a lot of arguments to the block it gets passed.
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
```Ruby
|
|
10
|
+
class Dummy
|
|
11
|
+
def yields_a_lot(foo,bar,baz,fling,flung)
|
|
12
|
+
yield foo,bar,baz,fling,flung
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`reek` would report the following warning:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
test.rb -- 1 warning:
|
|
21
|
+
[4]:Dummy#yields_a_lot yields 5 parameters (LongYieldList)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
A common solution to this problem would be the introduction of parameter objects.
|
|
25
|
+
|
|
26
|
+
## Current Support in Reek
|
|
27
|
+
|
|
28
|
+
Currently Long Parameter List reports any method or block with more than 3 parameters.
|
|
29
|
+
|
|
30
|
+
## Configuration
|
|
31
|
+
|
|
32
|
+
Reek's Long Parameter List detector supports the [Basic Smell Options](Basic-Smell-Options.md), plus:
|
|
33
|
+
|
|
34
|
+
| Option | Value | Effect |
|
|
35
|
+
| ---------------|-------------|---------|
|
|
36
|
+
| max_params | integer | The maximum number of parameters allowed in a method or block before a warning is issued. Defaults to 3. |
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Module Initialize
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A module is usually a mixin, so when an `#initialize` method is present it is
|
|
6
|
+
hard to tell initialization order and parameters so having `#initialize`
|
|
7
|
+
in a module is usually a bad idea.
|
|
8
|
+
|
|
9
|
+
## Example
|
|
10
|
+
|
|
11
|
+
The `Foo` module below contains a method `initialize`. Although class `B` inherits from `A`, the inclusion of `Foo` stops `A#initialize` from being called.
|
|
12
|
+
|
|
13
|
+
```Ruby
|
|
14
|
+
class A
|
|
15
|
+
def initialize(a)
|
|
16
|
+
@a = a
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module Foo
|
|
21
|
+
def initialize(foo)
|
|
22
|
+
@foo = foo
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class B < A
|
|
27
|
+
include Foo
|
|
28
|
+
|
|
29
|
+
def initialize(b)
|
|
30
|
+
super('bar')
|
|
31
|
+
@b = b
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
A simple solution is to rename `Foo#initialize` and call that method by name:
|
|
37
|
+
|
|
38
|
+
```Ruby
|
|
39
|
+
module Foo
|
|
40
|
+
def setup_foo_module(foo)
|
|
41
|
+
@foo = foo
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class B < A
|
|
46
|
+
include Foo
|
|
47
|
+
|
|
48
|
+
def initialize(b)
|
|
49
|
+
super 'bar'
|
|
50
|
+
setup_foo_module('foo')
|
|
51
|
+
@b = b
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Current Support in reek
|
|
57
|
+
|
|
58
|
+
`reek` warns about module initialize when an instance method named `initialize` is present in a module.
|
|
59
|
+
|
|
60
|
+
## Configuration
|
|
61
|
+
|
|
62
|
+
Module Initialize supports the [Basic Smell Options](Basic-Smell-Options.md).
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Nested Iterators
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A `Nested Iterator` occurs when a block contains another block.
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
Given
|
|
10
|
+
|
|
11
|
+
```Ruby
|
|
12
|
+
class Duck
|
|
13
|
+
class << self
|
|
14
|
+
def duck_names
|
|
15
|
+
%i!tick trick track!.each do |surname|
|
|
16
|
+
%i!duck!.each do |last_name|
|
|
17
|
+
puts "full name is #{surname} #{last_name}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`reek` would report the following warning:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
test.rb -- 1 warning:
|
|
29
|
+
[5]:Duck#duck_names contains iterators nested 2 deep (NestedIterators)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Current Support in Reek
|
|
33
|
+
|
|
34
|
+
Nested Iterators reports failing methods only once.
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
`Nested Iterators` offers the [Basic Smell Options](Basic-Smell-Options.md).
|
data/docs/Nil-Check.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Nil Check
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A `NilCheck` is a type check. Failures of `NilCheck` violate the ["tell, don't ask"](http://robots.thoughtbot.com/tell-dont-ask) principle.
|
|
6
|
+
Additionally to that, type checks often mask bigger problems in your source code like not using OOP and / or polymorphism when you should.
|
|
7
|
+
|
|
8
|
+
## Example
|
|
9
|
+
|
|
10
|
+
Given
|
|
11
|
+
|
|
12
|
+
```Ruby
|
|
13
|
+
class Klass
|
|
14
|
+
def nil_checker(argument)
|
|
15
|
+
if argument.nil?
|
|
16
|
+
puts "argument isn't nil!"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`reek` would emit the following warning:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
test.rb -- 1 warning:
|
|
26
|
+
[3]:Klass#nil_checker performs a nil-check. (NilCheck)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Current Support in Reek
|
|
30
|
+
|
|
31
|
+
`NilCheck` reports use of
|
|
32
|
+
|
|
33
|
+
* <code>.nil?</code> method
|
|
34
|
+
* <code>==</code> and <code>===</code> operators when checking vs. <code>nil</code>
|
|
35
|
+
* case statements that use syntax like <code>when nil</code>
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
`Nil Check` offers the [Basic Smell Options](Basic-Smell-Options.md).
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Prima Donna Method
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A candidate method for the `Prima Donna Method` smell are methods whose names end with an exclamation mark.
|
|
6
|
+
|
|
7
|
+
An exclamation mark in method names means (the explanation below is taken from [here](http://dablog.rubypal.com/2007/8/15/bang-methods-or-danger-will-rubyist) ):
|
|
8
|
+
|
|
9
|
+
>>
|
|
10
|
+
The ! in method names that end with ! means, “This method is dangerous”—or, more precisely, this method is the “dangerous” version of an otherwise equivalent method, with the same name minus the !. “Danger” is relative; the ! doesn’t mean anything at all unless the method name it’s in corresponds to a similar but bang-less method name.
|
|
11
|
+
So, for example, gsub! is the dangerous version of gsub. exit! is the dangerous version of exit. flatten! is the dangerous version of flatten. And so forth.
|
|
12
|
+
|
|
13
|
+
Such a method is called `Prima Donna Method` if and only if her non-bang version does not exist and this method is reported as a smell.
|
|
14
|
+
|
|
15
|
+
## Example
|
|
16
|
+
|
|
17
|
+
Given
|
|
18
|
+
|
|
19
|
+
```Ruby
|
|
20
|
+
class C
|
|
21
|
+
def foo; end
|
|
22
|
+
def foo!; end
|
|
23
|
+
def bar!; end
|
|
24
|
+
end
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`reek` would report `bar!` as `prima donna method` smell but not `foo!`.
|
|
28
|
+
|
|
29
|
+
`reek` reports this smell only in a class context, not in a module context in order to allow perfectly legit code like this:
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
```Ruby
|
|
33
|
+
class Parent
|
|
34
|
+
def foo; end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module Dangerous
|
|
38
|
+
def foo!; end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class Son < Parent
|
|
42
|
+
include Dangerous
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Daughter < Parent
|
|
46
|
+
end
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
In this example, `reek` would not report the `prima donna method` smell for the method `foo` of the `Dangerous` module.
|
|
50
|
+
|
|
51
|
+
## Configuration
|
|
52
|
+
|
|
53
|
+
`Prima Donna Method` offers the [Basic Smell Options](Basic-Smell-Options.md).
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# RSpec matchers
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
`reek` offers matchers for RSpec you can easily include into your project.
|
|
6
|
+
|
|
7
|
+
There are 3 matchers available:
|
|
8
|
+
|
|
9
|
+
- `reek`
|
|
10
|
+
- `reek_of`
|
|
11
|
+
- `reek_only_of`
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
Let's install the dependencies:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
gem install reek
|
|
19
|
+
gem install rspec
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
And then use it like that in your spec file:
|
|
23
|
+
|
|
24
|
+
```Ruby
|
|
25
|
+
require 'reek'
|
|
26
|
+
require 'reek/spec'
|
|
27
|
+
require 'rspec'
|
|
28
|
+
|
|
29
|
+
RSpec.describe 'Reek Integration' do
|
|
30
|
+
it 'works with reek' do
|
|
31
|
+
smelly_class = 'class C; def m; end; end'
|
|
32
|
+
expect(smelly_class).not_to reek
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Running this via
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
rspec reek-integration-spec.rb
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
would give you:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
Failures:
|
|
47
|
+
|
|
48
|
+
1) Reek Integration works with reek
|
|
49
|
+
Failure/Error: expect(smelly_class).not_to reek
|
|
50
|
+
Expected no smells, but got:
|
|
51
|
+
C has no descriptive comment (IrresponsibleModule)
|
|
52
|
+
C has the name 'C' (UncommunicativeModuleName)
|
|
53
|
+
C#m has the name 'm' (UncommunicativeMethodName)
|
|
54
|
+
# ./reek-integration-spec.rb:8:in `block (2 levels) in <top (required)>'
|
|
55
|
+
|
|
56
|
+
Finished in 0.00284 seconds (files took 0.28815 seconds to load)
|
|
57
|
+
1 example, 1 failure
|
|
58
|
+
|
|
59
|
+
Failed examples:
|
|
60
|
+
|
|
61
|
+
rspec ./reek-integration-spec.rb:6 # Reek Integration works with reek
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## The matchers explained
|
|
65
|
+
|
|
66
|
+
### `reek`
|
|
67
|
+
|
|
68
|
+
A very generic matcher that basically just tells you if something reeks, but
|
|
69
|
+
not after what exactly.
|
|
70
|
+
See the "Quickstart" example from above.
|
|
71
|
+
|
|
72
|
+
### `reek_of`
|
|
73
|
+
|
|
74
|
+
Checks the target source code for instances of "smell category"
|
|
75
|
+
and returns true only if it can find one of them that matches.
|
|
76
|
+
|
|
77
|
+
Remember that this includes our "smell types" as well. So it could be the
|
|
78
|
+
"smell type" UtilityFunction, which is represented as a concrete class
|
|
79
|
+
in reek but it could also be "Duplication" which is a "smell categgory".
|
|
80
|
+
|
|
81
|
+
In theory you could pass many different types of input here:
|
|
82
|
+
- `:UtilityFunction`
|
|
83
|
+
- `"UtilityFunction"`
|
|
84
|
+
- `UtilityFunction` (this works in our specs because we tend to do "include
|
|
85
|
+
Reek:Smells")
|
|
86
|
+
- `Reek::Smells::UtilityFunction` (the right way if you really want to pass a
|
|
87
|
+
class)
|
|
88
|
+
- `"Duplication"` or `:Duplication` which is an abstract "smell category"
|
|
89
|
+
|
|
90
|
+
It is recommended to pass this as a symbol like `:UtilityFunction`. However we
|
|
91
|
+
don't enforce this.
|
|
92
|
+
|
|
93
|
+
Additionally you can be more specific and pass in "smell_details" you want to
|
|
94
|
+
check for as well e.g. "name" or "count" (see the examples below). The
|
|
95
|
+
parameters you can check for are depending on the smell you are checking for.
|
|
96
|
+
For instance "count" doesn't make sense everywhere whereas "name" does in most
|
|
97
|
+
cases. If you pass in a parameter that doesn't exist (e.g. you make a typo like
|
|
98
|
+
"namme") reek will raise an ArgumentError to give you a hint that you passed
|
|
99
|
+
something that doesn't make much sense.
|
|
100
|
+
|
|
101
|
+
So in a nutshell `reek_of` takes the following two arguments:
|
|
102
|
+
|
|
103
|
+
- `smell_category` - The "smell category" or "smell_type" we check for.
|
|
104
|
+
- `smells_details` - A hash containing "smell warning" parameters
|
|
105
|
+
|
|
106
|
+
**Examples**
|
|
107
|
+
|
|
108
|
+
Without smell_details:
|
|
109
|
+
|
|
110
|
+
```Ruby
|
|
111
|
+
reek_of(:FeatureEnvy)
|
|
112
|
+
reek_of(Reek::Smells::UtilityFunction)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
With smell_details:
|
|
116
|
+
|
|
117
|
+
```Ruby
|
|
118
|
+
reek_of(UncommunicativeParameterName, name: 'x2')
|
|
119
|
+
reek_of(DataClump, count: 3)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Examples from a real spec**
|
|
123
|
+
|
|
124
|
+
```Ruby
|
|
125
|
+
expect(src).to reek_of(Reek::Smells::DuplicateMethodCall, name: '@other.thing')
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### reek_only_of
|
|
129
|
+
|
|
130
|
+
See the documentaton for `reek_of`.
|
|
131
|
+
|
|
132
|
+
**Notable differences to reek_of:**
|
|
133
|
+
|
|
134
|
+
1. `reek_of` doesn't mind if there are other smells of a different category.
|
|
135
|
+
"reek_only_of" will fail in that case.
|
|
136
|
+
|
|
137
|
+
2. `reek_only_of` doesn't support the additional smell_details hash.
|
data/docs/Rake-Task.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Rake Task
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
`reek` provides a Rake task that runs `reek` on a set of source files. In its most simple form you just include something like that in your Rakefile:
|
|
6
|
+
|
|
7
|
+
```Ruby
|
|
8
|
+
require 'reek/rake/task'
|
|
9
|
+
|
|
10
|
+
Reek::Rake::Task.new do |t|
|
|
11
|
+
t.fail_on_error = false
|
|
12
|
+
end
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
In its most simple form, that's it.
|
|
16
|
+
|
|
17
|
+
When you now run:
|
|
18
|
+
|
|
19
|
+
```Bash
|
|
20
|
+
rake -T
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
you should see
|
|
24
|
+
|
|
25
|
+
```Bash
|
|
26
|
+
rake reek # Check for code smells
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Configuration via task
|
|
30
|
+
|
|
31
|
+
An more sophisticated rake task that would make use of all available configuration options could look like this:
|
|
32
|
+
|
|
33
|
+
```Ruby
|
|
34
|
+
Reek::Rake::Task.new do |t|
|
|
35
|
+
t.name = 'custom_rake' # Whatever name you want. Defaults to "reek".
|
|
36
|
+
t.config_file = 'config/config.reek' # Defaults to nothing.
|
|
37
|
+
t.source_files = 'vendor/**/*.rb' # Glob pattern to match source files. Defaults to lib/**/*.rb
|
|
38
|
+
t.reek_opts = '-U' # Defaults to ''. You can pass all the options here in that are shown by "reek -h"
|
|
39
|
+
t.fail_on_error = false # Defaults to true
|
|
40
|
+
t.verbose = true # Defaults to false
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Configuration via environment variables
|
|
45
|
+
|
|
46
|
+
You can overwrite the following attributes by environment variables:
|
|
47
|
+
|
|
48
|
+
- "reek_opts" by using REEK_OPTS
|
|
49
|
+
- "config_file" by using REEK_CFG
|
|
50
|
+
- "source_files" by using REEK_SRC
|
|
51
|
+
|
|
52
|
+
An example rake call using environment variables could look like this:
|
|
53
|
+
|
|
54
|
+
```Bash
|
|
55
|
+
REEK_CFG="config/custom.reek" REEK_OPTS="-s" rake reek
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
See also: [Reek-Driven-Development](Reek-Driven-Development.md)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Reek Driven Development
|
|
2
|
+
|
|
3
|
+
## rake
|
|
4
|
+
|
|
5
|
+
One way to drive quality into your code from the very beginning of a project is to run `reek` as a part of your testing process. For example, you could do that by adding a [Rake Task](Rake-Task.md) to your rakefile, which will make it easy to run `reek` on all your source files whenever you need to.
|
|
6
|
+
|
|
7
|
+
```Ruby
|
|
8
|
+
require 'reek/rake/task'
|
|
9
|
+
|
|
10
|
+
Reek::Rake::Task.new do |t|
|
|
11
|
+
t.fail_on_error = true
|
|
12
|
+
t.verbose = false
|
|
13
|
+
t.source_files = 'lib/**/*.rb'
|
|
14
|
+
end
|
|
15
|
+
```
|
|
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) in this wiki.
|
|
18
|
+
|
|
19
|
+
## reek/spec
|
|
20
|
+
|
|
21
|
+
But there's another way; a much more effective "Reek-driven" approach: add `reek` expectations directly into your Rspec specs. Here's an example taken directly from `reek`'s own source code:
|
|
22
|
+
|
|
23
|
+
```Ruby
|
|
24
|
+
it 'contains no code smells' do
|
|
25
|
+
Dir['lib/**/*.rb'].should_not reek
|
|
26
|
+
end
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
By requiring "reek/spec":http://reek.rubyforge.org/rdoc/classes/Reek/Spec.html you gain access to the `reek` matcher, which returns true if and only if `reek` finds smells in your code. And if the test fails, the matcher produces an error message that includes details of all the smells it found.
|
|
30
|
+
|
|
31
|
+
## assert
|
|
32
|
+
|
|
33
|
+
If you're not yet into BDD with Rspec, you can still gain the benefits of Reek-driven development using assertions:
|
|
34
|
+
|
|
35
|
+
```Ruby
|
|
36
|
+
assert !Dir['lib/**/*.rb'].to_source.smelly?
|
|
37
|
+
```
|