reek 2.2.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.travis.yml +9 -4
- data/CHANGELOG +8 -0
- data/Gemfile +6 -4
- data/README.md +6 -0
- data/docs/API.md +51 -22
- data/docs/Configuration-Files.md +12 -1
- data/docs/Feature-Envy.md +30 -10
- data/docs/How-reek-works-internally.md +109 -39
- data/docs/RSpec-matchers.md +26 -22
- data/docs/Reek-Driven-Development.md +0 -8
- data/docs/Utility-Function.md +8 -10
- data/features/{ruby_api/api.feature → command_line_interface/basic_usage.feature} +2 -2
- data/features/programmatic_access.feature +21 -2
- data/features/samples.feature +3 -1
- data/lib/reek.rb +2 -2
- data/lib/reek/{core → ast}/ast_node_class_map.rb +8 -8
- data/lib/reek/{sexp/sexp_node.rb → ast/node.rb} +47 -6
- data/lib/reek/{core → ast}/object_refs.rb +2 -1
- data/lib/reek/{core → ast}/reference_collector.rb +2 -1
- data/lib/reek/{sexp → ast}/sexp_extensions.rb +10 -5
- data/lib/reek/{sexp → ast}/sexp_formatter.rb +7 -5
- data/lib/reek/cli/application.rb +1 -0
- data/lib/reek/cli/command.rb +1 -0
- data/lib/reek/cli/input.rb +4 -1
- data/lib/reek/cli/option_interpreter.rb +6 -4
- data/lib/reek/cli/options.rb +2 -1
- data/lib/reek/cli/reek_command.rb +3 -2
- data/lib/reek/cli/silencer.rb +1 -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 +17 -2
- data/lib/reek/configuration/configuration_file_finder.rb +1 -0
- data/lib/reek/{core → context}/code_context.rb +7 -5
- data/lib/reek/{core → context}/method_context.rb +5 -3
- data/lib/reek/{core → context}/module_context.rb +8 -3
- data/lib/reek/{core/stop_context.rb → context/root_context.rb} +4 -2
- data/lib/reek/{core → context}/singleton_method_context.rb +2 -1
- data/lib/reek/examiner.rb +82 -0
- 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.rb +24 -13
- data/lib/reek/smells/attribute.rb +6 -4
- data/lib/reek/smells/boolean_parameter.rb +3 -1
- data/lib/reek/smells/class_variable.rb +3 -1
- data/lib/reek/smells/control_parameter.rb +3 -1
- data/lib/reek/smells/data_clump.rb +3 -1
- data/lib/reek/smells/duplicate_method_call.rb +3 -1
- data/lib/reek/smells/feature_envy.rb +3 -1
- data/lib/reek/smells/irresponsible_module.rb +12 -7
- data/lib/reek/smells/long_parameter_list.rb +5 -3
- data/lib/reek/smells/long_yield_list.rb +3 -1
- data/lib/reek/smells/module_initialize.rb +3 -1
- data/lib/reek/smells/nested_iterators.rb +3 -1
- data/lib/reek/smells/nil_check.rb +3 -1
- data/lib/reek/smells/prima_donna_method.rb +3 -1
- data/lib/reek/smells/repeated_conditional.rb +5 -3
- data/lib/reek/{core → smells}/smell_configuration.rb +3 -1
- data/lib/reek/smells/smell_detector.rb +9 -7
- data/lib/reek/{core → smells}/smell_repository.rb +3 -2
- data/lib/reek/smells/smell_warning.rb +6 -4
- data/lib/reek/smells/too_many_instance_variables.rb +3 -1
- data/lib/reek/smells/too_many_methods.rb +3 -1
- data/lib/reek/smells/too_many_statements.rb +3 -1
- data/lib/reek/smells/uncommunicative_method_name.rb +3 -1
- data/lib/reek/smells/uncommunicative_module_name.rb +3 -1
- data/lib/reek/smells/uncommunicative_parameter_name.rb +3 -1
- data/lib/reek/smells/uncommunicative_variable_name.rb +3 -1
- data/lib/reek/smells/unused_parameters.rb +3 -1
- data/lib/reek/smells/utility_function.rb +5 -2
- data/lib/reek/source/source_code.rb +40 -9
- data/lib/reek/source/source_locator.rb +30 -12
- data/lib/reek/spec/should_reek.rb +5 -4
- data/lib/reek/spec/should_reek_of.rb +3 -2
- data/lib/reek/spec/should_reek_only_of.rb +5 -4
- data/lib/reek/tree_dresser.rb +32 -0
- data/lib/reek/tree_walker.rb +182 -0
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +3 -3
- data/spec/factories/factories.rb +2 -0
- data/spec/reek/{sexp/sexp_node_spec.rb → ast/node_spec.rb} +2 -2
- data/spec/reek/{core → ast}/object_refs_spec.rb +3 -3
- data/spec/reek/{core → ast}/reference_collector_spec.rb +2 -2
- data/spec/reek/{sexp → ast}/sexp_extensions_spec.rb +6 -16
- data/spec/reek/{sexp → ast}/sexp_formatter_spec.rb +2 -2
- data/spec/reek/cli/option_interpreter_spec.rb +2 -1
- data/spec/reek/{core → cli}/warning_collector_spec.rb +3 -3
- data/spec/reek/{core/code_comment_spec.rb → code_comment_spec.rb} +3 -3
- data/spec/reek/configuration/app_configuration_spec.rb +31 -18
- data/spec/reek/{core → context}/code_context_spec.rb +14 -15
- data/spec/reek/{core → context}/method_context_spec.rb +8 -8
- data/spec/reek/{core → context}/module_context_spec.rb +4 -4
- data/spec/reek/context/root_context_spec.rb +14 -0
- data/spec/reek/{core → context}/singleton_method_context_spec.rb +4 -4
- data/spec/reek/{core/examiner_spec.rb → examiner_spec.rb} +3 -42
- data/spec/reek/{cli → report}/html_report_spec.rb +5 -5
- data/spec/reek/report/json_report_spec.rb +20 -0
- data/spec/reek/{cli → report}/text_report_spec.rb +14 -14
- data/spec/reek/{cli → report}/xml_report_spec.rb +7 -7
- data/spec/reek/report/yaml_report_spec.rb +20 -0
- data/spec/reek/smells/attribute_spec.rb +2 -1
- data/spec/reek/smells/boolean_parameter_spec.rb +1 -1
- data/spec/reek/smells/class_variable_spec.rb +5 -5
- data/spec/reek/smells/control_parameter_spec.rb +1 -1
- data/spec/reek/smells/data_clump_spec.rb +1 -1
- data/spec/reek/smells/duplicate_method_call_spec.rb +3 -3
- data/spec/reek/smells/feature_envy_spec.rb +1 -1
- data/spec/reek/smells/irresponsible_module_spec.rb +24 -28
- data/spec/reek/smells/long_parameter_list_spec.rb +2 -2
- data/spec/reek/smells/long_yield_list_spec.rb +2 -2
- data/spec/reek/smells/nested_iterators_spec.rb +1 -1
- data/spec/reek/smells/nil_check_spec.rb +2 -2
- data/spec/reek/smells/prima_donna_method_spec.rb +3 -3
- data/spec/reek/smells/repeated_conditional_spec.rb +6 -6
- data/spec/reek/{core → smells}/smell_configuration_spec.rb +4 -4
- data/spec/reek/smells/smell_detector_shared.rb +2 -2
- data/spec/reek/{core → smells}/smell_repository_spec.rb +5 -4
- data/spec/reek/smells/too_many_instance_variables_spec.rb +1 -1
- data/spec/reek/smells/too_many_methods_spec.rb +4 -4
- data/spec/reek/smells/too_many_statements_spec.rb +2 -2
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +1 -1
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +4 -4
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +2 -2
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +3 -3
- data/spec/reek/smells/utility_function_spec.rb +23 -1
- data/spec/reek/source/source_code_spec.rb +1 -1
- data/spec/reek/source/source_locator_spec.rb +30 -0
- data/spec/reek/spec/should_reek_of_spec.rb +0 -17
- data/spec/reek/spec/should_reek_spec.rb +0 -25
- data/spec/reek/tree_dresser_spec.rb +16 -0
- data/spec/reek/{core/tree_walker_spec.rb → tree_walker_spec.rb} +5 -5
- data/spec/samples/{simple_configuration.reek → configuration/simple_configuration.reek} +0 -0
- data/spec/samples/configuration/with_excluded_paths.reek +4 -0
- 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/spec_helper.rb +6 -7
- data/tasks/develop.rake +2 -2
- metadata +71 -69
- 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 -191
- data/lib/reek/core/ast_node.rb +0 -38
- data/lib/reek/core/code_comment.rb +0 -37
- data/lib/reek/core/examiner.rb +0 -85
- data/lib/reek/core/tree_dresser.rb +0 -24
- data/lib/reek/core/tree_walker.rb +0 -180
- data/lib/reek/source/source_repository.rb +0 -43
- data/spec/reek/cli/json_report_spec.rb +0 -20
- data/spec/reek/cli/yaml_report_spec.rb +0 -20
- data/spec/reek/core/object_source_spec.rb +0 -18
- data/spec/reek/core/stop_context_spec.rb +0 -14
- data/spec/reek/core/tree_dresser_spec.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da371c20978d5a436025bc2ecddc2df4582a9c7e
|
4
|
+
data.tar.gz: 8aa3729d6814cba34e69ff9e1696ce93450221c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d15340c5aa637820c280d28008579ecc97f9de7a56bf74e47f6f217a9f593d3a1416dfa6757b4beb3900032c505eed91aa8fa21de94374ac1e2d1537706cbabb
|
7
|
+
data.tar.gz: c49a1ae86f1265e493f6e5eff700e2d02c2849358a49db20d87d9c52498138da0ca38fd7bd83cb90d0c16cb7b19789aa43422b052910b145ac611d9421bc6bf8
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
@@ -2,19 +2,24 @@ sudo: false
|
|
2
2
|
cache: bundler
|
3
3
|
language: ruby
|
4
4
|
bundler_args: --without local_development
|
5
|
-
script:
|
5
|
+
script:
|
6
|
+
- bundle exec rake
|
7
|
+
- bundle exec ataru check
|
6
8
|
rvm:
|
7
|
-
- 1.9.3
|
8
9
|
- 2.0.0
|
9
10
|
- 2.1
|
10
11
|
- 2.2
|
11
|
-
- jruby-19mode
|
12
12
|
- rbx-2
|
13
13
|
- ruby-head
|
14
|
-
- jruby-head
|
15
14
|
matrix:
|
15
|
+
include:
|
16
|
+
- rvm: jruby-19mode
|
17
|
+
env: JRUBY_OPTS='--server -Xcompile.invokedynamic=false'
|
18
|
+
- rvm: jruby-head
|
19
|
+
env: JRUBY_OPTS='--server -Xcompile.invokedynamic=false'
|
16
20
|
allow_failures:
|
17
21
|
- rvm: jruby-head
|
22
|
+
env: JRUBY_OPTS='--server -Xcompile.invokedynamic=false'
|
18
23
|
- rvm: ruby-head
|
19
24
|
fast_finish: true
|
20
25
|
notifications:
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 3.0.0
|
2
|
+
|
3
|
+
* (troessner) Make directories excludable via configuration.
|
4
|
+
* (mvz) Define and document public API
|
5
|
+
* (troessner) Recognize methods defined with class << self syntax as singleton methods.
|
6
|
+
* (troessner) Use ruby22 instead of ruby21 for parsing.
|
7
|
+
* (nTraum) Drop support for Ruby 1.9
|
8
|
+
|
1
9
|
== 2.2.1
|
2
10
|
|
3
11
|
* (mvz) Support methods using array decomposition arguments
|
data/Gemfile
CHANGED
@@ -5,10 +5,12 @@ gemspec
|
|
5
5
|
|
6
6
|
group :local_development do
|
7
7
|
gem 'pry'
|
8
|
+
gem 'yard', '~> 0.8.7'
|
9
|
+
|
8
10
|
platforms :mri do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
gem 'pry-byebug'
|
12
|
+
gem 'pry-stack_explorer'
|
13
|
+
|
14
|
+
gem 'redcarpet', '~> 3.3.1'
|
13
15
|
end
|
14
16
|
end
|
data/README.md
CHANGED
@@ -173,8 +173,14 @@ NestedIterators:
|
|
173
173
|
DataClump:
|
174
174
|
max_copies: 3
|
175
175
|
min_clump_size: 3
|
176
|
+
|
177
|
+
exclude_paths:
|
178
|
+
- app/views
|
179
|
+
- app/controllers
|
176
180
|
```
|
177
181
|
|
182
|
+
Additionally to the smell configuration you can exclude whole directories from scans using `exclude_paths` as you can see at the end of the configuration above.
|
183
|
+
|
178
184
|
### Source code comments
|
179
185
|
|
180
186
|
`reek` is not the police. In case you need to suppress a smell
|
data/docs/API.md
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
## Using `reek` inside your Ruby application
|
1
|
+
# Using `reek` inside your Ruby application
|
4
2
|
|
5
3
|
`reek` can be used inside another Ruby project.
|
6
4
|
|
@@ -8,37 +6,41 @@
|
|
8
6
|
gem install reek
|
9
7
|
```
|
10
8
|
|
9
|
+
## Using a reporter
|
10
|
+
|
11
11
|
You can use reek inside your Ruby file `check_dirty.rb`
|
12
12
|
|
13
13
|
```ruby
|
14
14
|
require 'reek'
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
puts @screen.contents
|
26
|
-
fail
|
15
|
+
|
16
|
+
source = <<-END
|
17
|
+
class Dirty
|
18
|
+
# This method smells of :reek:NestedIterators but ignores them
|
19
|
+
def awful(x, y, offset = 0, log = false)
|
20
|
+
puts @screen.title
|
21
|
+
@screen = widgets.map { |w| w.each { |key| key += 3 * x } }
|
22
|
+
puts @screen.contents
|
23
|
+
fail
|
24
|
+
end
|
27
25
|
end
|
28
|
-
end
|
29
26
|
END
|
30
27
|
|
31
|
-
|
32
|
-
|
33
|
-
reporter.add_examiner
|
34
|
-
|
28
|
+
reporter = Reek::Report::TextReport.new
|
29
|
+
examiner = Reek::Examiner.new(source)
|
30
|
+
reporter.add_examiner examiner
|
31
|
+
reporter.show
|
35
32
|
```
|
36
33
|
|
37
34
|
This will show the list of errors in variable `source`.
|
38
35
|
|
39
|
-
`
|
36
|
+
`Reek::Examiner.new` can take `source` as `String`, `File` or `IO`.
|
37
|
+
|
38
|
+
```
|
39
|
+
# Examine a file object
|
40
|
+
reporter.add_examiner Reek::Examiner.new(File.new('dirty.rb'))
|
41
|
+
```
|
40
42
|
|
41
|
-
Also, besides normal text output, `reek` can
|
43
|
+
Also, besides normal text output, `reek` can generate output in YAML,
|
42
44
|
JSON, HTML and XML by using the following Report types:
|
43
45
|
|
44
46
|
```
|
@@ -48,3 +50,30 @@ JSONReport
|
|
48
50
|
HTMLReport
|
49
51
|
XMLReport
|
50
52
|
```
|
53
|
+
|
54
|
+
## Accessing the smell warnings directly
|
55
|
+
|
56
|
+
You can also access the smells detected by an examiner directly:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
require 'reek'
|
60
|
+
|
61
|
+
source = <<-END
|
62
|
+
class Dirty
|
63
|
+
# This method smells of :reek:NestedIterators but ignores them
|
64
|
+
def awful(x, y, offset = 0, log = false)
|
65
|
+
puts @screen.title
|
66
|
+
@screen = widgets.map { |w| w.each { |key| key += 3 * x } }
|
67
|
+
puts @screen.contents
|
68
|
+
fail
|
69
|
+
end
|
70
|
+
end
|
71
|
+
END
|
72
|
+
|
73
|
+
examiner = Reek::Examiner.new(source)
|
74
|
+
examiner.smells.each do |smell|
|
75
|
+
puts smell.message
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
`Examiner#smells` returns a list of `SmellWarning` objects.
|
data/docs/Configuration-Files.md
CHANGED
@@ -14,7 +14,7 @@ The order in which `reek` tries to find such a configuration file is exactly lik
|
|
14
14
|
|
15
15
|
As soon as `reek` detects a configuration file it stops searching immediately, meaning that from `reek`'s point of view there exists one configuration file and one configuration only regardless of how many ".reek" files you might have on your filesystem.
|
16
16
|
|
17
|
-
## Configuration options
|
17
|
+
## Configuration options for smells
|
18
18
|
|
19
19
|
The first thing you probably want to check out are the [Basic Smell Options](Basic-Smell-Options.md) which are supported by every smell type.
|
20
20
|
Certain smell types offer a configuration that goes beyond that of the basic smell options - for instance [Data Clump](Data-Clump.md).
|
@@ -36,3 +36,14 @@ DataClump:
|
|
36
36
|
max_copies: 3
|
37
37
|
min_clump_size: 3
|
38
38
|
```
|
39
|
+
|
40
|
+
## Excluding directories from scans
|
41
|
+
|
42
|
+
You can exclude whole directories from scans using `exclude_paths` in your configuration file:
|
43
|
+
|
44
|
+
```yaml
|
45
|
+
---
|
46
|
+
exclude_paths:
|
47
|
+
- app/views
|
48
|
+
- app/controllers
|
49
|
+
```
|
data/docs/Feature-Envy.md
CHANGED
@@ -2,28 +2,48 @@
|
|
2
2
|
|
3
3
|
## Introduction
|
4
4
|
|
5
|
-
|
5
|
+
_Feature Envy_ occurs when a code fragment references another object more often than it references itself, or when several clients do the same series of manipulations on a particular type of object.
|
6
6
|
|
7
|
-
|
7
|
+
_Feature Envy_ reduces the code's ability to communicate intent: code that "belongs" on one class but which is located in another can be hard to find, and may upset the "System of Names" in the host class.
|
8
|
+
|
9
|
+
_Feature Envy_ also affects the design's flexibility: A code fragment that is in the wrong class creates couplings that may not be natural within the application's domain, and creates a loss of cohesion in the unwilling host class.
|
10
|
+
|
11
|
+
_Feature Envy_ often arises because it must manipulate other objects (usually its arguments) to get them into a useful form, and one force preventing them (the arguments) doing this themselves is that the common knowledge lives outside the arguments, or the arguments are of too basic a type to justify extending that type. Therefore there must be something which 'knows' about the contents or purposes of the arguments. That thing would have to be more than just a basic type, because the basic types are either containers which don't know about their contents, or they are single objects which can't capture their relationship with their fellows of the same type. So, this thing with the extra knowledge should be reified into a class, and the utility method will most likely belong there.
|
12
|
+
|
13
|
+
## Example
|
14
|
+
|
15
|
+
Running reek on:
|
8
16
|
|
9
17
|
```Ruby
|
10
|
-
class
|
11
|
-
def
|
12
|
-
|
18
|
+
class Warehouse
|
19
|
+
def sale_price(item)
|
20
|
+
(item.price - item.rebate) * @vat
|
13
21
|
end
|
14
22
|
end
|
15
23
|
```
|
16
24
|
|
17
|
-
|
25
|
+
would report:
|
18
26
|
|
19
|
-
|
27
|
+
```Bash
|
28
|
+
Warehouse#total_price refers to item more than self (FeatureEnvy)
|
29
|
+
```
|
20
30
|
|
21
|
-
|
31
|
+
since this:
|
32
|
+
|
33
|
+
```Ruby
|
34
|
+
(item.price - item.rebate)
|
35
|
+
```
|
36
|
+
|
37
|
+
belongs to the Item class, not the Warehouse.
|
22
38
|
|
23
39
|
## Current Support in reek
|
24
40
|
|
25
|
-
|
41
|
+
_Feature Envy_ reports any method that refers to self less often than it refers to (ie. send messages to) some other object.
|
42
|
+
|
43
|
+
## Differences to _Utility Function_
|
44
|
+
|
45
|
+
_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.
|
26
46
|
|
27
47
|
## Configuration
|
28
48
|
|
29
|
-
|
49
|
+
_Feature Envy_ supports the [Basic Smell Options](Basic-Smell-Options.md).
|
@@ -1,44 +1,114 @@
|
|
1
1
|
# How reek works internally
|
2
2
|
|
3
|
-
|
3
|
+
|
4
|
+
## The big picture
|
4
5
|
|
5
6
|
```
|
6
|
-
[
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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 []):
|
44
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
|
data/docs/RSpec-matchers.md
CHANGED
@@ -37,7 +37,7 @@ end
|
|
37
37
|
Running this via
|
38
38
|
|
39
39
|
```
|
40
|
-
rspec reek-integration-spec.rb
|
40
|
+
rspec reek-integration-spec.rb
|
41
41
|
```
|
42
42
|
|
43
43
|
would give you:
|
@@ -65,7 +65,8 @@ rspec ./reek-integration-spec.rb:6 # Reek Integration works with reek
|
|
65
65
|
|
66
66
|
### `reek`
|
67
67
|
|
68
|
-
A very generic matcher that basically just tells you if something reeks, but
|
68
|
+
A very generic matcher that basically just tells you if something reeks, but
|
69
|
+
not after what exactly.
|
69
70
|
See the "Quickstart" example from above.
|
70
71
|
|
71
72
|
### `reek_of`
|
@@ -78,27 +79,29 @@ Remember that this includes our "smell types" as well. So it could be the
|
|
78
79
|
in reek but it could also be "Duplication" which is a "smell categgory".
|
79
80
|
|
80
81
|
In theory you could pass many different types of input here:
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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.
|
97
100
|
|
98
101
|
So in a nutshell `reek_of` takes the following two arguments:
|
99
102
|
|
100
|
-
- smell_category - The "smell category" or "smell_type" we check for.
|
101
|
-
- smells_details - A hash containing "smell warning" parameters
|
103
|
+
- `smell_category` - The "smell category" or "smell_type" we check for.
|
104
|
+
- `smells_details` - A hash containing "smell warning" parameters
|
102
105
|
|
103
106
|
**Examples**
|
104
107
|
|
@@ -128,6 +131,7 @@ See the documentaton for `reek_of`.
|
|
128
131
|
|
129
132
|
**Notable differences to reek_of:**
|
130
133
|
|
131
|
-
1.
|
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.
|
132
136
|
|
133
|
-
2.
|
137
|
+
2. `reek_only_of` doesn't support the additional smell_details hash.
|