reek 3.6.0 → 3.6.1
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/CHANGELOG.md +6 -1
- data/README.md +6 -1
- data/docs/API.md +27 -0
- data/lib/reek/ast/node.rb +1 -1
- data/lib/reek/ast/reference_collector.rb +1 -1
- data/lib/reek/context/code_context.rb +1 -0
- data/lib/reek/smells/attribute.rb +1 -1
- data/lib/reek/smells/boolean_parameter.rb +1 -1
- data/lib/reek/smells/class_variable.rb +1 -1
- data/lib/reek/smells/control_parameter.rb +1 -1
- data/lib/reek/smells/data_clump.rb +1 -1
- data/lib/reek/smells/duplicate_method_call.rb +1 -1
- data/lib/reek/smells/feature_envy.rb +1 -1
- data/lib/reek/smells/irresponsible_module.rb +1 -1
- data/lib/reek/smells/long_parameter_list.rb +1 -1
- data/lib/reek/smells/long_yield_list.rb +1 -1
- data/lib/reek/smells/module_initialize.rb +1 -1
- data/lib/reek/smells/nested_iterators.rb +1 -1
- data/lib/reek/smells/nil_check.rb +1 -1
- data/lib/reek/smells/prima_donna_method.rb +1 -1
- data/lib/reek/smells/repeated_conditional.rb +1 -1
- data/lib/reek/smells/smell_detector.rb +45 -61
- data/lib/reek/smells/smell_repository.rb +16 -18
- data/lib/reek/smells/too_many_instance_variables.rb +1 -1
- data/lib/reek/smells/too_many_methods.rb +2 -2
- data/lib/reek/smells/too_many_statements.rb +1 -1
- data/lib/reek/smells/uncommunicative_method_name.rb +1 -1
- data/lib/reek/smells/uncommunicative_module_name.rb +1 -1
- data/lib/reek/smells/uncommunicative_parameter_name.rb +1 -1
- data/lib/reek/smells/uncommunicative_variable_name.rb +1 -1
- data/lib/reek/smells/unused_parameters.rb +1 -1
- data/lib/reek/smells/utility_function.rb +1 -1
- data/lib/reek/tree_walker.rb +21 -3
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +1 -1
- data/spec/reek/ast/reference_collector_spec.rb +4 -0
- data/spec/reek/smells/boolean_parameter_spec.rb +1 -1
- data/spec/reek/smells/class_variable_spec.rb +4 -4
- 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 +1 -1
- data/spec/reek/smells/long_parameter_list_spec.rb +1 -1
- data/spec/reek/smells/long_yield_list_spec.rb +1 -1
- data/spec/reek/smells/nested_iterators_spec.rb +5 -5
- data/spec/reek/smells/nil_check_spec.rb +1 -1
- data/spec/reek/smells/prima_donna_method_spec.rb +1 -1
- data/spec/reek/smells/smell_detector_shared.rb +2 -0
- 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 +1 -1
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +1 -1
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +2 -2
- 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 +4 -0
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6656a7be5a8741a3d09652e3d4fffa05f06d8e8e
|
|
4
|
+
data.tar.gz: fe908f1791d3ca5ff1dddee324569dbc52293f6c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b90ac67fe60415c01a8b9330acdabbfa61ba82627e2a22f5e899b8bb2e7683d055b05ddfbf0643a3dffa551a1e39823d76df08a5496b70ddbb15a9928475236f
|
|
7
|
+
data.tar.gz: 8adff3362ad6e24ac4a2f91b8e8325fb4432f890a66a10fc3ced5fd997ab9029642283eec0f2550d3c84c8777ae53d00eefa83be3cc95dae1e15e1d10ca8434a
|
data/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
-
## 3.6 (2015-
|
|
5
|
+
## 3.6.1 (2015-11-13)
|
|
6
|
+
|
|
7
|
+
* (mvz) Make UtilityFunction not report methods that call `super` with
|
|
8
|
+
arguments.
|
|
9
|
+
|
|
10
|
+
## 3.6.0 (2015-10-30)
|
|
6
11
|
|
|
7
12
|
* (mvz) Make Attribute respect suppressing comments
|
|
8
13
|
* (chastell) Adjust parser dependency to allow versions 2.2.3+ (and even 2.3+)
|
data/README.md
CHANGED
|
@@ -14,7 +14,12 @@
|
|
|
14
14
|
|
|
15
15
|
Reek is a tool that examines Ruby classes, modules and methods and reports any
|
|
16
16
|
[Code Smells](docs/Code-Smells.md) it finds.
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
For an excellent introduction to
|
|
19
|
+
[Code Smells](docs/Code-Smells.md) and `Reek` check out [this blog post](https://blog.codeship.com/how-to-find-ruby-code-smells-with-reek/)
|
|
20
|
+
or [this talk](https://www.youtube.com/watch?v=ZzqOuHI5MkA).
|
|
21
|
+
|
|
22
|
+
Install it via rubygems:
|
|
18
23
|
|
|
19
24
|
```Bash
|
|
20
25
|
gem install reek
|
data/docs/API.md
CHANGED
|
@@ -50,6 +50,33 @@ string -- 5 warnings:
|
|
|
50
50
|
|
|
51
51
|
Note that `Reek::Examiner.new` can take `source` as `String`, `Pathname`, `File` or `IO`.
|
|
52
52
|
|
|
53
|
+
## API stability
|
|
54
|
+
|
|
55
|
+
Everything that is mentioned in this document can be considered stable in the
|
|
56
|
+
sense that it will only change across major versions.
|
|
57
|
+
|
|
58
|
+
`Reek 3` was the first major version with a stable API. As soon as `Reek 4`
|
|
59
|
+
is released we will mark the differences between `3` and `4`.
|
|
60
|
+
|
|
61
|
+
There is one thing in this API documentation you can't and shouldn't rely on:
|
|
62
|
+
The `SmellWarning` messages itself.
|
|
63
|
+
|
|
64
|
+
Something like this
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
Dirty#m has the parameter name 'a' (UncommunicativeParameterName)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
might change even across minor versions.
|
|
71
|
+
|
|
72
|
+
You should not need to be specific about those messages anyways.
|
|
73
|
+
In case you'd like to be specific about `SmellWarnings` please have a look at
|
|
74
|
+
[accessing the smell warnings directly](#accessing-the-smell-warnings-directly).
|
|
75
|
+
|
|
76
|
+
Additionally you can use one of our structured [outputs formats](#choosing-your-output-format)
|
|
77
|
+
like JSON or YAML if you need a more fine-grained access to our
|
|
78
|
+
`SmellWarnings`.
|
|
79
|
+
|
|
53
80
|
## Choosing your output format
|
|
54
81
|
|
|
55
82
|
Besides normal text output, Reek can generate output in YAML,
|
data/lib/reek/ast/node.rb
CHANGED
|
@@ -43,7 +43,7 @@ module Reek
|
|
|
43
43
|
#
|
|
44
44
|
# target_type - the type to look for, e.g. :send, :block
|
|
45
45
|
# ignoring - types to ignore, e.g. [:casgn, :class, :module]
|
|
46
|
-
# blk - block to execute for every hit
|
|
46
|
+
# blk - block to execute for every hit. Gets passed in the matching element itself.
|
|
47
47
|
#
|
|
48
48
|
# Examples:
|
|
49
49
|
# context.each_node(:send, [:mlhs]) do |call_node| .... end
|
|
@@ -53,7 +53,7 @@ module Reek
|
|
|
53
53
|
# @return [Array<SmellWarning>]
|
|
54
54
|
#
|
|
55
55
|
# :reek:FeatureEnvy
|
|
56
|
-
def
|
|
56
|
+
def inspect(ctx)
|
|
57
57
|
ControlParameterCollector.new(ctx).control_parameters.map do |control_parameter|
|
|
58
58
|
name = control_parameter.name.to_s
|
|
59
59
|
smell_warning(
|
|
@@ -51,7 +51,7 @@ module Reek
|
|
|
51
51
|
# @return [Array<SmellWarning>]
|
|
52
52
|
#
|
|
53
53
|
# :reek:FeatureEnvy
|
|
54
|
-
def
|
|
54
|
+
def inspect(ctx)
|
|
55
55
|
max_copies = value(MAX_COPIES_KEY, ctx, DEFAULT_MAX_COPIES)
|
|
56
56
|
min_clump_size = value(MIN_CLUMP_SIZE_KEY, ctx, DEFAULT_MIN_CLUMP_SIZE)
|
|
57
57
|
MethodGroup.new(ctx, min_clump_size, max_copies).clumps.map do |clump, methods|
|
|
@@ -47,7 +47,7 @@ module Reek
|
|
|
47
47
|
#
|
|
48
48
|
# :reek:FeatureEnvy
|
|
49
49
|
# :reek:DuplicateMethodCall: { max_calls: 2 }
|
|
50
|
-
def
|
|
50
|
+
def inspect(ctx)
|
|
51
51
|
max_allowed_calls = value(MAX_ALLOWED_CALLS_KEY, ctx, DEFAULT_MAX_CALLS)
|
|
52
52
|
allow_calls = value(ALLOW_CALLS_KEY, ctx, DEFAULT_ALLOW_CALLS)
|
|
53
53
|
|
|
@@ -44,7 +44,7 @@ module Reek
|
|
|
44
44
|
# @return [Array<SmellWarning>]
|
|
45
45
|
#
|
|
46
46
|
# :reek:TooManyStatements: { max_statements: 6 }
|
|
47
|
-
def
|
|
47
|
+
def inspect(ctx)
|
|
48
48
|
configure_ignore_iterators(ctx)
|
|
49
49
|
deepest_iterator = find_deepest_iterator ctx
|
|
50
50
|
return [] unless deepest_iterator
|
|
@@ -12,7 +12,7 @@ module Reek
|
|
|
12
12
|
'SimulatedPolymorphism'
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def
|
|
15
|
+
def inspect(ctx)
|
|
16
16
|
call_node_finder = NodeFinder.new(ctx, :send, NilCallNodeDetector)
|
|
17
17
|
case_node_finder = NodeFinder.new(ctx, :when, NilWhenNodeDetector)
|
|
18
18
|
smelly_nodes = call_node_finder.smelly_nodes + case_node_finder.smelly_nodes
|
|
@@ -51,7 +51,7 @@ module Reek
|
|
|
51
51
|
#
|
|
52
52
|
# :reek:TooManyStatements: { max_statements: 6 }
|
|
53
53
|
# :reek:DuplicateMethodCall: { max_calls: 2 }
|
|
54
|
-
def
|
|
54
|
+
def inspect(ctx)
|
|
55
55
|
max_identical_ifs = value(MAX_IDENTICAL_IFS_KEY, ctx, DEFAULT_MAX_IFS)
|
|
56
56
|
conditional_counts(ctx).select do |_key, lines|
|
|
57
57
|
lines.length > max_identical_ifs
|
|
@@ -15,6 +15,8 @@ module Reek
|
|
|
15
15
|
# :reek:TooManyMethods: { max_methods: 19 }
|
|
16
16
|
# :reek:TooManyInstanceVariables: { max_instance_variables: 5 }
|
|
17
17
|
class SmellDetector
|
|
18
|
+
attr_reader :config
|
|
19
|
+
private_attr_accessor :smells_found
|
|
18
20
|
# The name of the config field that lists the names of code contexts
|
|
19
21
|
# that should not be checked. Add this field to the config for each
|
|
20
22
|
# smell that should ignore this code element.
|
|
@@ -24,32 +26,9 @@ module Reek
|
|
|
24
26
|
# in any configuration file.
|
|
25
27
|
DEFAULT_EXCLUDE_SET = []
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# :reek:UtilityFunction
|
|
33
|
-
def default_config
|
|
34
|
-
{
|
|
35
|
-
SmellConfiguration::ENABLED_KEY => true,
|
|
36
|
-
EXCLUDE_KEY => DEFAULT_EXCLUDE_SET.dup
|
|
37
|
-
}
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def inherited(subclass)
|
|
41
|
-
subclasses << subclass
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def descendants
|
|
45
|
-
subclasses
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
private
|
|
49
|
-
|
|
50
|
-
def subclasses
|
|
51
|
-
@subclasses ||= []
|
|
52
|
-
end
|
|
29
|
+
def initialize(config = {})
|
|
30
|
+
@config = SmellConfiguration.new self.class.default_config.merge(config)
|
|
31
|
+
@smells_found = []
|
|
53
32
|
end
|
|
54
33
|
|
|
55
34
|
def smell_category
|
|
@@ -60,52 +39,25 @@ module Reek
|
|
|
60
39
|
self.class.smell_type
|
|
61
40
|
end
|
|
62
41
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
@smell_category ||= default_smell_category
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def smell_type
|
|
69
|
-
@smell_type ||= default_smell_category
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def default_smell_category
|
|
73
|
-
name.split(/::/)[-1]
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def initialize(config = {})
|
|
78
|
-
config = self.class.default_config.merge(config)
|
|
79
|
-
@config = SmellConfiguration.new(config)
|
|
80
|
-
@smells_found = []
|
|
42
|
+
def contexts
|
|
43
|
+
self.class.contexts
|
|
81
44
|
end
|
|
82
45
|
|
|
83
|
-
def
|
|
84
|
-
return unless
|
|
85
|
-
self.class.contexts.each { |ctx| hooks[ctx] << self }
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def examine(context)
|
|
89
|
-
return unless enabled_for? context
|
|
46
|
+
def run_for(context)
|
|
47
|
+
return unless enabled_for?(context)
|
|
90
48
|
return if exception?(context)
|
|
91
49
|
|
|
92
|
-
|
|
93
|
-
self.smells_found += sm
|
|
50
|
+
self.smells_found = smells_found + inspect(context)
|
|
94
51
|
end
|
|
95
52
|
|
|
96
|
-
def report_on(
|
|
97
|
-
smells_found.each { |smell| smell.report_on(
|
|
53
|
+
def report_on(collector)
|
|
54
|
+
smells_found.each { |smell| smell.report_on(collector) }
|
|
98
55
|
end
|
|
99
56
|
|
|
100
57
|
def exception?(context)
|
|
101
58
|
context.matches?(value(EXCLUDE_KEY, context, DEFAULT_EXCLUDE_SET))
|
|
102
59
|
end
|
|
103
60
|
|
|
104
|
-
protected
|
|
105
|
-
|
|
106
|
-
# NOTE: Needs to be protected so += works for Ruby < 2.2
|
|
107
|
-
attr_accessor :smells_found
|
|
108
|
-
|
|
109
61
|
private
|
|
110
62
|
|
|
111
63
|
def enabled_for?(context)
|
|
@@ -133,7 +85,39 @@ module Reek
|
|
|
133
85
|
parameters: options.fetch(:parameters, {}))
|
|
134
86
|
end
|
|
135
87
|
|
|
136
|
-
|
|
88
|
+
class << self
|
|
89
|
+
def smell_category
|
|
90
|
+
@smell_category ||= default_smell_category
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def smell_type
|
|
94
|
+
@smell_type ||= default_smell_category
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def default_smell_category
|
|
98
|
+
name.split(/::/)[-1]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def contexts
|
|
102
|
+
[:def, :defs]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# :reek:UtilityFunction
|
|
106
|
+
def default_config
|
|
107
|
+
{
|
|
108
|
+
SmellConfiguration::ENABLED_KEY => true,
|
|
109
|
+
EXCLUDE_KEY => DEFAULT_EXCLUDE_SET.dup
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def inherited(subclass)
|
|
114
|
+
descendants << subclass
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def descendants
|
|
118
|
+
@descendants ||= []
|
|
119
|
+
end
|
|
120
|
+
end
|
|
137
121
|
end
|
|
138
122
|
end
|
|
139
123
|
end
|
|
@@ -8,6 +8,8 @@ module Reek
|
|
|
8
8
|
# Contains all the existing smells and exposes operations on them.
|
|
9
9
|
#
|
|
10
10
|
class SmellRepository
|
|
11
|
+
private_attr_reader :configuration, :smell_types, :detectors
|
|
12
|
+
|
|
11
13
|
def self.smell_types
|
|
12
14
|
Reek::Smells::SmellDetector.descendants.sort_by(&:name)
|
|
13
15
|
end
|
|
@@ -23,38 +25,34 @@ module Reek
|
|
|
23
25
|
configuration: {})
|
|
24
26
|
@configuration = configuration
|
|
25
27
|
@smell_types = smell_types
|
|
28
|
+
@detectors = smell_types.map { |klass| klass.new configuration_for(klass) }
|
|
26
29
|
end
|
|
27
30
|
|
|
28
|
-
def report_on(
|
|
29
|
-
detectors.
|
|
31
|
+
def report_on(collector)
|
|
32
|
+
detectors.each { |detector| detector.report_on(collector) }
|
|
30
33
|
end
|
|
31
34
|
|
|
32
35
|
def examine(context)
|
|
33
|
-
|
|
34
|
-
detector.
|
|
36
|
+
smell_detectors_for(context.type).each do |detector|
|
|
37
|
+
detector.run_for(context)
|
|
35
38
|
end
|
|
36
39
|
end
|
|
37
40
|
|
|
38
|
-
def detectors
|
|
39
|
-
@initialized_detectors ||= smell_types.map do |klass|
|
|
40
|
-
{ klass => klass.new(source_configuration_for(klass)) }
|
|
41
|
-
end.reduce({}, :merge)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
41
|
private
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def source_configuration_for(klass)
|
|
49
|
-
configuration[klass] || {}
|
|
43
|
+
def configuration_for(klass)
|
|
44
|
+
configuration.fetch klass, {}
|
|
50
45
|
end
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
detectors.each_value { |detector| detector.register(listeners) }
|
|
47
|
+
def smell_detectors_for(type)
|
|
48
|
+
enabled_detectors.select do |detector|
|
|
49
|
+
detector.contexts.include? type
|
|
56
50
|
end
|
|
57
51
|
end
|
|
52
|
+
|
|
53
|
+
def enabled_detectors
|
|
54
|
+
detectors.select { |detector| detector.config.enabled? }
|
|
55
|
+
end
|
|
58
56
|
end
|
|
59
57
|
end
|
|
60
58
|
end
|
|
@@ -37,7 +37,7 @@ module Reek
|
|
|
37
37
|
#
|
|
38
38
|
# @return [Array<SmellWarning>]
|
|
39
39
|
#
|
|
40
|
-
def
|
|
40
|
+
def inspect(ctx)
|
|
41
41
|
max_allowed_ivars = value(MAX_ALLOWED_IVARS_KEY, ctx, DEFAULT_MAX_IVARS)
|
|
42
42
|
count = ctx.local_nodes(:ivasgn).map { |ivasgn| ivasgn.children.first }.uniq.length
|
|
43
43
|
return [] if count <= max_allowed_ivars
|
|
@@ -23,7 +23,7 @@ module Reek
|
|
|
23
23
|
'LargeClass'
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def self.contexts
|
|
26
|
+
def self.contexts
|
|
27
27
|
[:class]
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -39,7 +39,7 @@ module Reek
|
|
|
39
39
|
#
|
|
40
40
|
# @return [Array<SmellWarning>]
|
|
41
41
|
#
|
|
42
|
-
def
|
|
42
|
+
def inspect(ctx)
|
|
43
43
|
max_allowed_methods = value(MAX_ALLOWED_METHODS_KEY, ctx, DEFAULT_MAX_METHODS)
|
|
44
44
|
# TODO: Only checks instance methods!
|
|
45
45
|
actual = ctx.node_instance_methods.length
|
|
@@ -51,7 +51,7 @@ module Reek
|
|
|
51
51
|
#
|
|
52
52
|
# @return [Array<SmellWarning>]
|
|
53
53
|
#
|
|
54
|
-
def
|
|
54
|
+
def inspect(ctx)
|
|
55
55
|
self.reject_names = value(REJECT_KEY, ctx, DEFAULT_REJECT_SET)
|
|
56
56
|
self.accept_names = value(ACCEPT_KEY, ctx, DEFAULT_ACCEPT_SET)
|
|
57
57
|
variable_names(ctx.exp).select do |name, _lines|
|
data/lib/reek/tree_walker.rb
CHANGED
|
@@ -25,7 +25,7 @@ module Reek
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def walk
|
|
28
|
-
|
|
28
|
+
context_tree.each do |element|
|
|
29
29
|
smell_repository.examine(element)
|
|
30
30
|
end
|
|
31
31
|
end
|
|
@@ -35,8 +35,26 @@ module Reek
|
|
|
35
35
|
private_attr_accessor :element
|
|
36
36
|
private_attr_reader :exp, :smell_repository
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
# Processes the given AST, memoizes it and returns a tree of nested
|
|
39
|
+
# contexts.
|
|
40
|
+
#
|
|
41
|
+
# For example this ruby code:
|
|
42
|
+
# class Car; def drive; end; end
|
|
43
|
+
# would get compiled into this AST:
|
|
44
|
+
# (class
|
|
45
|
+
# (const nil :Car) nil
|
|
46
|
+
# (def :drive
|
|
47
|
+
# (args) nil))
|
|
48
|
+
# Processing this AST would result in a context tree where each node
|
|
49
|
+
# contains the outer context, the AST and the child contexts. The top
|
|
50
|
+
# node is always Reek::Context::RootContext. Using the example above,
|
|
51
|
+
# the tree would look like this:
|
|
52
|
+
#
|
|
53
|
+
# RootContext -> children: 1 ModuleContext -> children: 1 MethodContext
|
|
54
|
+
#
|
|
55
|
+
# @return [Reek::Context::RootContext] tree of nested contexts
|
|
56
|
+
def context_tree
|
|
57
|
+
@context_tree ||= process(exp)
|
|
40
58
|
end
|
|
41
59
|
|
|
42
60
|
def process(exp)
|
data/lib/reek/version.rb
CHANGED
data/reek.gemspec
CHANGED
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
|
28
28
|
s.add_runtime_dependency 'unparser', '~> 0.2.2'
|
|
29
29
|
|
|
30
30
|
s.add_development_dependency 'activesupport', '~> 4.2'
|
|
31
|
-
s.add_development_dependency 'aruba', '~> 0.
|
|
31
|
+
s.add_development_dependency 'aruba', '~> 0.10.0'
|
|
32
32
|
s.add_development_dependency 'ataru', '~> 0.2.0'
|
|
33
33
|
s.add_development_dependency 'bundler', '~> 1.1'
|
|
34
34
|
s.add_development_dependency 'cucumber', '~> 2.0'
|
|
@@ -16,6 +16,10 @@ RSpec.describe Reek::AST::ReferenceCollector do
|
|
|
16
16
|
expect(refs_to_self('def simple() super; end')).to eq(1)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
it 'counts a call to super with arguments' do
|
|
20
|
+
expect(refs_to_self('def simple() super(); end')).to eq(1)
|
|
21
|
+
end
|
|
22
|
+
|
|
19
23
|
it 'counts a local call' do
|
|
20
24
|
expect(refs_to_self('def simple() to_s; end')).to eq(1)
|
|
21
25
|
end
|
|
@@ -74,7 +74,7 @@ RSpec.describe Reek::Smells::BooleanParameter do
|
|
|
74
74
|
let(:warning) do
|
|
75
75
|
src = 'def cc(arga = true) end'
|
|
76
76
|
ctx = Reek::Context::MethodContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
77
|
-
detector.
|
|
77
|
+
detector.inspect(ctx).first
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
it_should_behave_like 'common fields set correctly'
|
|
@@ -12,19 +12,19 @@ RSpec.describe Reek::Smells::ClassVariable do
|
|
|
12
12
|
context 'with no class variables' do
|
|
13
13
|
it 'records nothing in the class' do
|
|
14
14
|
exp = sexp(:class, :Fred)
|
|
15
|
-
expect(detector.
|
|
15
|
+
expect(detector.inspect(Reek::Context::CodeContext.new(nil, exp))).to be_empty
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
it 'records nothing in the module' do
|
|
19
19
|
exp = sexp(:module, :Fred)
|
|
20
|
-
expect(detector.
|
|
20
|
+
expect(detector.inspect(Reek::Context::CodeContext.new(nil, exp))).to be_empty
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
context 'with one class variable' do
|
|
25
25
|
shared_examples_for 'one variable found' do
|
|
26
26
|
let(:ast) { Reek::Source::SourceCode.from(src).syntax_tree }
|
|
27
|
-
let(:smells) { detector.
|
|
27
|
+
let(:smells) { detector.inspect(Reek::Context::CodeContext.new(nil, ast)) }
|
|
28
28
|
|
|
29
29
|
it 'records only that class variable' do
|
|
30
30
|
expect(smells.length).to eq(1)
|
|
@@ -85,7 +85,7 @@ RSpec.describe Reek::Smells::ClassVariable do
|
|
|
85
85
|
end
|
|
86
86
|
EOS
|
|
87
87
|
ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
88
|
-
detector.
|
|
88
|
+
detector.inspect(ctx).first
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
it_should_behave_like 'common fields set correctly'
|
|
@@ -270,7 +270,7 @@ RSpec.describe Reek::Smells::ControlParameter do
|
|
|
270
270
|
end
|
|
271
271
|
EOS
|
|
272
272
|
ctx = Reek::Context::MethodContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
273
|
-
smells = detector.
|
|
273
|
+
smells = detector.run_for(ctx)
|
|
274
274
|
expect(smells.length).to eq(1)
|
|
275
275
|
smells.first
|
|
276
276
|
end
|
|
@@ -26,7 +26,7 @@ RSpec.shared_examples_for 'a data clump detector' do
|
|
|
26
26
|
end
|
|
27
27
|
EOS
|
|
28
28
|
ctx = Reek::Context::ModuleContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
29
|
-
build(:smell_detector, smell_type: :DataClump).
|
|
29
|
+
build(:smell_detector, smell_type: :DataClump).inspect(ctx)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
it 'records only the one smell' do
|
|
@@ -17,7 +17,7 @@ RSpec.describe Reek::Smells::DuplicateMethodCall do
|
|
|
17
17
|
end
|
|
18
18
|
EOS
|
|
19
19
|
ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
20
|
-
smells = detector.
|
|
20
|
+
smells = detector.inspect(ctx)
|
|
21
21
|
expect(smells.length).to eq(1)
|
|
22
22
|
smells.first
|
|
23
23
|
end
|
|
@@ -87,7 +87,7 @@ RSpec.describe Reek::Smells::LongParameterList do
|
|
|
87
87
|
end
|
|
88
88
|
EOS
|
|
89
89
|
ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
90
|
-
detector.
|
|
90
|
+
detector.inspect(ctx).first
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
it_should_behave_like 'common fields set correctly'
|
|
@@ -36,7 +36,7 @@ RSpec.describe Reek::Smells::LongYieldList do
|
|
|
36
36
|
end
|
|
37
37
|
EOS
|
|
38
38
|
ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
39
|
-
detector.
|
|
39
|
+
detector.inspect(ctx).first
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
it_should_behave_like 'common fields set correctly'
|
|
@@ -109,7 +109,7 @@ RSpec.describe Reek::Smells::NestedIterators do
|
|
|
109
109
|
expect(src).to reek_of(:NestedIterators)
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
-
describe '
|
|
112
|
+
describe 'inspect / warnings' do
|
|
113
113
|
let(:detector) { build(:smell_detector, smell_type: :NestedIterators) }
|
|
114
114
|
|
|
115
115
|
it 'reports correctly' do
|
|
@@ -120,7 +120,7 @@ RSpec.describe Reek::Smells::NestedIterators do
|
|
|
120
120
|
end
|
|
121
121
|
end
|
|
122
122
|
EOS
|
|
123
|
-
warnings = detector.
|
|
123
|
+
warnings = detector.inspect(build(:method_context, source: source))
|
|
124
124
|
warning = warnings.first
|
|
125
125
|
|
|
126
126
|
expect(warning.smell_category).to eq(Reek::Smells::NestedIterators.smell_category)
|
|
@@ -137,7 +137,7 @@ RSpec.describe Reek::Smells::NestedIterators do
|
|
|
137
137
|
end
|
|
138
138
|
EOS
|
|
139
139
|
|
|
140
|
-
warnings = detector.
|
|
140
|
+
warnings = detector.inspect(build(:method_context, source: source))
|
|
141
141
|
expect(warnings.size).to eq(1)
|
|
142
142
|
warning = warnings.first
|
|
143
143
|
expect(warning.parameters[:name]).to eq('bad')
|
|
@@ -150,7 +150,7 @@ RSpec.describe Reek::Smells::NestedIterators do
|
|
|
150
150
|
@jim.each {|ting| ting.each {|piece| piece.each {|atom| atom.foo } } }
|
|
151
151
|
end
|
|
152
152
|
EOS
|
|
153
|
-
warnings = detector.
|
|
153
|
+
warnings = detector.inspect(build(:method_context, source: source))
|
|
154
154
|
expect(warnings.size).to eq(1)
|
|
155
155
|
warning = warnings.first
|
|
156
156
|
|
|
@@ -273,7 +273,7 @@ RSpec.describe Reek::Smells::NestedIterators do
|
|
|
273
273
|
end
|
|
274
274
|
EOS
|
|
275
275
|
ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
276
|
-
detector.
|
|
276
|
+
detector.inspect(ctx).first
|
|
277
277
|
end
|
|
278
278
|
|
|
279
279
|
it_should_behave_like 'common fields set correctly'
|
|
@@ -13,7 +13,7 @@ RSpec.describe Reek::Smells::NilCheck do
|
|
|
13
13
|
EOS
|
|
14
14
|
ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
15
15
|
detector = build(:smell_detector, smell_type: :NilCheck)
|
|
16
|
-
smells = detector.
|
|
16
|
+
smells = detector.inspect(ctx)
|
|
17
17
|
expect(smells[0].lines).to eq [2]
|
|
18
18
|
end
|
|
19
19
|
|
|
@@ -22,9 +22,11 @@ RSpec.shared_examples_for 'common fields set correctly' do
|
|
|
22
22
|
it 'reports the source' do
|
|
23
23
|
expect(warning.source).to eq('string')
|
|
24
24
|
end
|
|
25
|
+
|
|
25
26
|
it 'reports the smell class' do
|
|
26
27
|
expect(warning.smell_category).to eq(detector.smell_category)
|
|
27
28
|
end
|
|
29
|
+
|
|
28
30
|
it 'reports the smell sub class' do
|
|
29
31
|
expect(warning.smell_type).to eq(detector.smell_type)
|
|
30
32
|
end
|
|
@@ -85,7 +85,7 @@ RSpec.describe Reek::Smells::TooManyInstanceVariables do
|
|
|
85
85
|
end
|
|
86
86
|
EOS
|
|
87
87
|
ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
88
|
-
detector.
|
|
88
|
+
detector.inspect(ctx).first
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
it_should_behave_like 'common fields set correctly'
|
|
@@ -18,7 +18,7 @@ RSpec.describe Reek::Smells::TooManyMethods do
|
|
|
18
18
|
EOS
|
|
19
19
|
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
|
20
20
|
ctx = Reek::Context::ModuleContext.new(nil, syntax_tree)
|
|
21
|
-
expect(detector.
|
|
21
|
+
expect(detector.inspect(ctx)).to be_empty
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
it 'should report if we exceed max_methods' do
|
|
@@ -31,7 +31,7 @@ RSpec.describe Reek::Smells::TooManyMethods do
|
|
|
31
31
|
EOS
|
|
32
32
|
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
|
33
33
|
ctx = Reek::Context::ModuleContext.new(nil, syntax_tree)
|
|
34
|
-
smells = detector.
|
|
34
|
+
smells = detector.inspect(ctx)
|
|
35
35
|
expect(smells.length).to eq(1)
|
|
36
36
|
expect(smells[0].smell_type).to eq(described_class.smell_type)
|
|
37
37
|
expect(smells[0].parameters[:count]).to eq(3)
|
|
@@ -54,7 +54,7 @@ RSpec.describe Reek::Smells::TooManyMethods do
|
|
|
54
54
|
EOS
|
|
55
55
|
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
|
56
56
|
ctx = Reek::Context::ModuleContext.new(nil, syntax_tree)
|
|
57
|
-
expect(detector.
|
|
57
|
+
expect(detector.inspect(ctx)).to be_empty
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
@@ -69,7 +69,7 @@ RSpec.describe Reek::Smells::TooManyMethods do
|
|
|
69
69
|
|
|
70
70
|
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
|
71
71
|
ctx = Reek::Context::ModuleContext.new(nil, syntax_tree)
|
|
72
|
-
warning = detector.
|
|
72
|
+
warning = detector.inspect(ctx)[0]
|
|
73
73
|
expect(warning.source).to eq(source_name)
|
|
74
74
|
expect(warning.smell_category).to eq(described_class.smell_category)
|
|
75
75
|
expect(warning.smell_type).to eq(described_class.smell_type)
|
|
@@ -51,7 +51,7 @@ RSpec.describe Reek::Smells::TooManyStatements do
|
|
|
51
51
|
ctx = double('method_context').as_null_object
|
|
52
52
|
expect(ctx).to receive(:num_statements).and_return(num_statements)
|
|
53
53
|
expect(ctx).to receive(:config_for).with(described_class).and_return({})
|
|
54
|
-
detector.
|
|
54
|
+
detector.inspect(ctx)
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
it 'reports only 1 smell' do
|
|
@@ -19,7 +19,7 @@ RSpec.describe Reek::Smells::UncommunicativeMethodName do
|
|
|
19
19
|
let(:warning) do
|
|
20
20
|
src = "def #{method_name}; end"
|
|
21
21
|
ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
22
|
-
detector.
|
|
22
|
+
detector.inspect(ctx).first
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
it_should_behave_like 'common fields set correctly'
|
|
@@ -28,7 +28,7 @@ RSpec.describe Reek::Smells::UncommunicativeModuleName do
|
|
|
28
28
|
it 'reports a bad scoped name' do
|
|
29
29
|
src = "#{type} Foo::X; end"
|
|
30
30
|
ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
31
|
-
smells = detector.
|
|
31
|
+
smells = detector.inspect(ctx)
|
|
32
32
|
expect(smells.length).to eq(1)
|
|
33
33
|
expect(smells[0].smell_category).to eq(Reek::Smells::UncommunicativeModuleName.smell_category)
|
|
34
34
|
expect(smells[0].smell_type).to eq(Reek::Smells::UncommunicativeModuleName.smell_type)
|
|
@@ -66,7 +66,7 @@ RSpec.describe Reek::Smells::UncommunicativeModuleName do
|
|
|
66
66
|
let(:warning) do
|
|
67
67
|
src = 'module Printer2; end'
|
|
68
68
|
ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
69
|
-
detector.
|
|
69
|
+
detector.inspect(ctx).first
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
it_should_behave_like 'common fields set correctly'
|
|
@@ -8,7 +8,7 @@ RSpec.describe Reek::Smells::UncommunicativeParameterName do
|
|
|
8
8
|
|
|
9
9
|
it_should_behave_like 'SmellDetector'
|
|
10
10
|
|
|
11
|
-
{ 'obj.' => 'with a
|
|
11
|
+
{ 'obj.' => 'with a receiver',
|
|
12
12
|
'' => 'without a receiver' }.each do |host, description|
|
|
13
13
|
context "in a method definition #{description}" do
|
|
14
14
|
it 'does not recognise *' do
|
|
@@ -77,7 +77,7 @@ RSpec.describe Reek::Smells::UncommunicativeParameterName do
|
|
|
77
77
|
let(:warning) do
|
|
78
78
|
src = 'def bad(good, bad2, good_again); basics(good, bad2, good_again); end'
|
|
79
79
|
ctx = Reek::Context::MethodContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
|
80
|
-
detector.
|
|
80
|
+
detector.inspect(ctx).first
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
it_should_behave_like 'common fields set correctly'
|
|
@@ -51,7 +51,7 @@ RSpec.describe Reek::Smells::UncommunicativeVariableName do
|
|
|
51
51
|
src = 'def simple(fred) x = jim(45); x = y end'
|
|
52
52
|
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
|
53
53
|
ctx = Reek::Context::CodeContext.new(nil, syntax_tree)
|
|
54
|
-
smells = detector.
|
|
54
|
+
smells = detector.inspect(ctx)
|
|
55
55
|
expect(smells.length).to eq(1)
|
|
56
56
|
expect(smells[0].smell_type).to eq(described_class.smell_type)
|
|
57
57
|
expect(smells[0].parameters[:name]).to eq('x')
|
|
@@ -164,7 +164,7 @@ RSpec.describe Reek::Smells::UncommunicativeVariableName do
|
|
|
164
164
|
EOS
|
|
165
165
|
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
|
166
166
|
ctx = Reek::Context::CodeContext.new(nil, syntax_tree)
|
|
167
|
-
detector.
|
|
167
|
+
detector.inspect(ctx).first
|
|
168
168
|
end
|
|
169
169
|
|
|
170
170
|
it_should_behave_like 'common fields set correctly'
|
|
@@ -180,7 +180,7 @@ RSpec.describe Reek::Smells::UncommunicativeVariableName do
|
|
|
180
180
|
src = 'def self.bad() x2 = 4; end'
|
|
181
181
|
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
|
182
182
|
ctx = Reek::Context::CodeContext.new(nil, syntax_tree)
|
|
183
|
-
detector.
|
|
183
|
+
detector.inspect(ctx).first
|
|
184
184
|
end
|
|
185
185
|
|
|
186
186
|
it_should_behave_like 'common fields set correctly'
|
|
@@ -197,6 +197,10 @@ RSpec.describe Reek::Smells::UtilityFunction do
|
|
|
197
197
|
expect('def child(arg) super; arg.to_s; end').not_to reek_of(:UtilityFunction)
|
|
198
198
|
end
|
|
199
199
|
|
|
200
|
+
it 'does not report a method that calls super with arguments' do
|
|
201
|
+
expect('def child(arg) super(arg * 2); arg.to_s; end').not_to reek_of(:UtilityFunction)
|
|
202
|
+
end
|
|
203
|
+
|
|
200
204
|
it 'should recognise a deep call' do
|
|
201
205
|
src = <<-EOS
|
|
202
206
|
class Red
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: reek
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.6.
|
|
4
|
+
version: 3.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kevin Rutherford
|
|
@@ -11,7 +11,7 @@ authors:
|
|
|
11
11
|
autorequire:
|
|
12
12
|
bindir: bin
|
|
13
13
|
cert_chain: []
|
|
14
|
-
date: 2015-
|
|
14
|
+
date: 2015-11-13 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
17
17
|
name: parser
|
|
@@ -95,14 +95,14 @@ dependencies:
|
|
|
95
95
|
requirements:
|
|
96
96
|
- - "~>"
|
|
97
97
|
- !ruby/object:Gem::Version
|
|
98
|
-
version: 0.
|
|
98
|
+
version: 0.10.0
|
|
99
99
|
type: :development
|
|
100
100
|
prerelease: false
|
|
101
101
|
version_requirements: !ruby/object:Gem::Requirement
|
|
102
102
|
requirements:
|
|
103
103
|
- - "~>"
|
|
104
104
|
- !ruby/object:Gem::Version
|
|
105
|
-
version: 0.
|
|
105
|
+
version: 0.10.0
|
|
106
106
|
- !ruby/object:Gem::Dependency
|
|
107
107
|
name: ataru
|
|
108
108
|
requirement: !ruby/object:Gem::Requirement
|