reek 4.0.3 → 4.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile +3 -3
- data/Rakefile +3 -3
- data/docs/Class-Variable.md +1 -1
- data/docs/Control-Parameter.md +1 -1
- data/docs/Duplicate-Method-Call.md +8 -4
- data/features/samples.feature +3 -2
- data/lib/reek/smells/data_clump.rb +2 -2
- data/lib/reek/smells/duplicate_method_call.rb +2 -2
- data/lib/reek/smells/long_parameter_list.rb +1 -1
- data/lib/reek/smells/long_yield_list.rb +1 -3
- data/lib/reek/smells/nested_iterators.rb +54 -39
- data/lib/reek/smells/repeated_conditional.rb +1 -1
- data/lib/reek/smells/smell_configuration.rb +5 -4
- data/lib/reek/smells/smell_detector.rb +3 -3
- data/lib/reek/smells/too_many_instance_variables.rb +1 -1
- data/lib/reek/smells/too_many_methods.rb +1 -1
- data/lib/reek/smells/too_many_statements.rb +1 -3
- data/lib/reek/smells/uncommunicative_method_name.rb +2 -2
- data/lib/reek/smells/uncommunicative_module_name.rb +2 -2
- data/lib/reek/smells/uncommunicative_parameter_name.rb +2 -2
- data/lib/reek/smells/uncommunicative_variable_name.rb +2 -2
- data/lib/reek/smells/unused_private_method.rb +1 -1
- data/lib/reek/smells/utility_function.rb +5 -1
- data/lib/reek/source/source_code.rb +3 -0
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +1 -1
- data/spec/reek/smells/nested_iterators_spec.rb +20 -20
- data/spec/reek/smells/smell_configuration_spec.rb +0 -5
- data/spec/reek/smells/utility_function_spec.rb +22 -0
- data/spec/spec_helper.rb +5 -0
- data/tasks/ataru.rake +4 -0
- data/tasks/mutant.rake +5 -0
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c09dc83cbd7c49a57a5e0568479ccf87a8c284d
|
4
|
+
data.tar.gz: 7a9643ce33812488821abaabaf157eee3ba1f886
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e85233445ea0535f360876d6f45398ff364aa895883b0175a60097839fbb5182b399496010c675253a9b79efdd15b1ca759db9253ea7febfc916efe2a3e3013f
|
7
|
+
data.tar.gz: cdc14223fc488191e56d3642c1bff7affeb9f4e97fc9f6030d1bd7988f7c75f133ad824724da58785c44556ab0a2483f7893f35c219eb666f22dfcb21f8b6082
|
data/.travis.yml
CHANGED
@@ -2,10 +2,7 @@ sudo: false
|
|
2
2
|
cache: bundler
|
3
3
|
language: ruby
|
4
4
|
bundler_args: --without debugging
|
5
|
-
script:
|
6
|
-
- bundle exec rake
|
7
|
-
- bundle exec ataru check
|
8
|
-
- bundle exec mutant --include lib --require reek --use rspec --since master --jobs 4 "Reek*"
|
5
|
+
script: bundle exec rake ci
|
9
6
|
rvm:
|
10
7
|
- 2.1
|
11
8
|
- 2.2
|
@@ -30,3 +27,6 @@ notifications:
|
|
30
27
|
- matijs@matijs.net
|
31
28
|
- chastell@chastell.net
|
32
29
|
irc: irc.freenode.org#reek
|
30
|
+
branches:
|
31
|
+
only:
|
32
|
+
- master
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -7,12 +7,12 @@ group :development do
|
|
7
7
|
gem 'ataru', '~> 0.2.0'
|
8
8
|
gem 'cucumber', '~> 2.0'
|
9
9
|
gem 'factory_girl', '~> 4.0'
|
10
|
+
gem 'mutant-rspec', '~> 0.8.8'
|
10
11
|
gem 'rake', '~> 11.1'
|
11
12
|
gem 'rspec', '~> 3.0'
|
12
13
|
gem 'rubocop', '~> 0.39.0'
|
13
|
-
gem 'yard', '~> 0.8.7'
|
14
14
|
gem 'simplecov', '~> 0.11.1'
|
15
|
-
gem '
|
15
|
+
gem 'yard', '~> 0.8.7'
|
16
16
|
|
17
17
|
platforms :mri do
|
18
18
|
gem 'redcarpet', '~> 3.3.1'
|
@@ -21,8 +21,8 @@ end
|
|
21
21
|
|
22
22
|
group :debugging do
|
23
23
|
# Fixing https://github.com/guard/guard/wiki/Add-Readline-support-to-Ruby-on-Mac-OS-X#option-4-using-a-pure-ruby-readline-implementation
|
24
|
-
gem 'rb-readline', '~> 0.5.3'
|
25
24
|
gem 'pry'
|
25
|
+
gem 'rb-readline', '~> 0.5.3'
|
26
26
|
platforms :mri do
|
27
27
|
gem 'pry-byebug'
|
28
28
|
gem 'pry-stack_explorer'
|
data/Rakefile
CHANGED
@@ -3,6 +3,6 @@ require 'rake/clean'
|
|
3
3
|
|
4
4
|
Dir['tasks/**/*.rake'].each { |t| load t }
|
5
5
|
|
6
|
-
task
|
7
|
-
task
|
8
|
-
task default:
|
6
|
+
task local_test_run: [:test, :rubocop, 'test:quality']
|
7
|
+
task ci: [:test, :rubocop, 'test:quality', :ataru, :mutant]
|
8
|
+
task default: :local_test_run
|
data/docs/Class-Variable.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
Class variables form part of the global runtime state, and as such make it easy for one part of the system to accidentally or inadvertently depend on another part of the system. So the system becomes more prone to problems where changing something over here breaks something over there. In particular, class variables can make it hard to set up tests (because the context of the test includes all global state).
|
6
6
|
|
7
|
-
For a detailed explanation, check out [this article](http://4thmouse.com/index.php/2011/03/20/why-class-variables-in-ruby-are-a-bad-idea/)
|
7
|
+
For a detailed explanation, check out [this article](http://4thmouse.com/index.php/2011/03/20/why-class-variables-in-ruby-are-a-bad-idea/).
|
8
8
|
|
9
9
|
## Example
|
10
10
|
|
data/docs/Control-Parameter.md
CHANGED
@@ -10,7 +10,7 @@ Reek implements a check for _Duplicate Method Call_.
|
|
10
10
|
Here's a very much simplified and contrived example. The following method will report a warning:
|
11
11
|
|
12
12
|
```Ruby
|
13
|
-
def double_thing
|
13
|
+
def double_thing
|
14
14
|
@other.thing + @other.thing
|
15
15
|
end
|
16
16
|
```
|
@@ -18,19 +18,23 @@ end
|
|
18
18
|
One quick approach to silence Reek would be to refactor the code thus:
|
19
19
|
|
20
20
|
```Ruby
|
21
|
-
def double_thing
|
21
|
+
def double_thing
|
22
22
|
thing = @other.thing
|
23
23
|
thing + thing
|
24
24
|
end
|
25
25
|
```
|
26
26
|
|
27
|
-
A slightly different approach would be to replace all calls
|
27
|
+
A slightly different approach would be to replace all calls in `double_thing` by calls to `thing`:
|
28
28
|
|
29
29
|
```Ruby
|
30
30
|
class Other
|
31
|
-
def double_thing
|
31
|
+
def double_thing
|
32
32
|
thing + thing
|
33
33
|
end
|
34
|
+
|
35
|
+
def thing
|
36
|
+
@other.thing
|
37
|
+
end
|
34
38
|
end
|
35
39
|
```
|
36
40
|
|
data/features/samples.feature
CHANGED
@@ -177,7 +177,7 @@ Feature: Basic smell detection
|
|
177
177
|
UnusedParameters: OptionParser::Completion#convert has unused parameter 'opt' [https://github.com/troessner/reek/blob/master/docs/Unused-Parameters.md]
|
178
178
|
UnusedParameters: OptionParser::Switch::NoArgument#parse has unused parameter 'argv' [https://github.com/troessner/reek/blob/master/docs/Unused-Parameters.md]
|
179
179
|
UnusedParameters: OptionParser::Switch::OptionalArgument#parse has unused parameter 'argv' [https://github.com/troessner/reek/blob/master/docs/Unused-Parameters.md]
|
180
|
-
redcloth.rb --
|
180
|
+
redcloth.rb -- 102 warnings:
|
181
181
|
Attribute: RedCloth#filter_html is a writable attribute [https://github.com/troessner/reek/blob/master/docs/Attribute.md]
|
182
182
|
Attribute: RedCloth#filter_styles is a writable attribute [https://github.com/troessner/reek/blob/master/docs/Attribute.md]
|
183
183
|
Attribute: RedCloth#hard_breaks is a writable attribute [https://github.com/troessner/reek/blob/master/docs/Attribute.md]
|
@@ -216,6 +216,7 @@ Feature: Basic smell detection
|
|
216
216
|
LongParameterList: RedCloth#textile_fn_ has 5 parameters [https://github.com/troessner/reek/blob/master/docs/Long-Parameter-List.md]
|
217
217
|
LongParameterList: RedCloth#textile_p has 4 parameters [https://github.com/troessner/reek/blob/master/docs/Long-Parameter-List.md]
|
218
218
|
NestedIterators: RedCloth#block_textile_lists contains iterators nested 3 deep [https://github.com/troessner/reek/blob/master/docs/Nested-Iterators.md]
|
219
|
+
NestedIterators: RedCloth#block_textile_table contains iterators nested 2 deep [https://github.com/troessner/reek/blob/master/docs/Nested-Iterators.md]
|
219
220
|
NestedIterators: RedCloth#block_textile_table contains iterators nested 3 deep [https://github.com/troessner/reek/blob/master/docs/Nested-Iterators.md]
|
220
221
|
NestedIterators: RedCloth#blocks contains iterators nested 2 deep [https://github.com/troessner/reek/blob/master/docs/Nested-Iterators.md]
|
221
222
|
NestedIterators: RedCloth#clean_html contains iterators nested 2 deep [https://github.com/troessner/reek/blob/master/docs/Nested-Iterators.md]
|
@@ -279,5 +280,5 @@ Feature: Basic smell detection
|
|
279
280
|
UtilityFunction: RedCloth#lT doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Utility-Function.md]
|
280
281
|
UtilityFunction: RedCloth#no_textile doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Utility-Function.md]
|
281
282
|
UtilityFunction: RedCloth#v_align doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/master/docs/Utility-Function.md]
|
282
|
-
|
283
|
+
266 total warnings
|
283
284
|
"""
|
@@ -53,8 +53,8 @@ module Reek
|
|
53
53
|
#
|
54
54
|
# :reek:FeatureEnvy
|
55
55
|
def inspect(ctx)
|
56
|
-
max_copies = value(MAX_COPIES_KEY, ctx
|
57
|
-
min_clump_size = value(MIN_CLUMP_SIZE_KEY, ctx
|
56
|
+
max_copies = value(MAX_COPIES_KEY, ctx)
|
57
|
+
min_clump_size = value(MIN_CLUMP_SIZE_KEY, ctx)
|
58
58
|
MethodGroup.new(ctx, min_clump_size, max_copies).clumps.map do |clump, methods|
|
59
59
|
methods_length = methods.length
|
60
60
|
smell_warning(
|
@@ -45,8 +45,8 @@ module Reek
|
|
45
45
|
# :reek:FeatureEnvy
|
46
46
|
# :reek:DuplicateMethodCall: { max_calls: 2 }
|
47
47
|
def inspect(ctx)
|
48
|
-
max_allowed_calls = value(MAX_ALLOWED_CALLS_KEY, ctx
|
49
|
-
allow_calls = value(ALLOW_CALLS_KEY, ctx
|
48
|
+
max_allowed_calls = value(MAX_ALLOWED_CALLS_KEY, ctx)
|
49
|
+
allow_calls = value(ALLOW_CALLS_KEY, ctx)
|
50
50
|
|
51
51
|
collector = CallCollector.new(ctx, max_allowed_calls, allow_calls)
|
52
52
|
collector.smelly_calls.map do |found_call|
|
@@ -35,7 +35,7 @@ module Reek
|
|
35
35
|
# @return [Array<SmellWarning>]
|
36
36
|
#
|
37
37
|
def inspect(ctx)
|
38
|
-
max_allowed_params = value(MAX_ALLOWED_PARAMS_KEY, ctx
|
38
|
+
max_allowed_params = value(MAX_ALLOWED_PARAMS_KEY, ctx)
|
39
39
|
exp = ctx.exp
|
40
40
|
count = exp.arg_names.length
|
41
41
|
return [] if count <= max_allowed_params
|
@@ -27,9 +27,7 @@ module Reek
|
|
27
27
|
# :reek:FeatureEnvy
|
28
28
|
# :reek:DuplicateMethodCall: { max_calls: 2 }
|
29
29
|
def inspect(ctx)
|
30
|
-
max_allowed_params = value(MAX_ALLOWED_PARAMS_KEY,
|
31
|
-
ctx,
|
32
|
-
DEFAULT_MAX_ALLOWED_PARAMS)
|
30
|
+
max_allowed_params = value(MAX_ALLOWED_PARAMS_KEY, ctx)
|
33
31
|
ctx.local_nodes(:yield).select do |yield_node|
|
34
32
|
yield_node.args.length > max_allowed_params
|
35
33
|
end.map do |yield_node|
|
@@ -13,9 +13,8 @@ module Reek
|
|
13
13
|
class NestedIterators < SmellDetector
|
14
14
|
# Struct for conveniently associating iterators with their depth (that is, their nesting).
|
15
15
|
Iterator = Struct.new :exp, :depth do
|
16
|
-
|
17
|
-
|
18
|
-
depth <=> other.depth
|
16
|
+
def line
|
17
|
+
exp.line
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
@@ -36,41 +35,55 @@ module Reek
|
|
36
35
|
)
|
37
36
|
end
|
38
37
|
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
38
|
+
# Generates a smell warning for each independent deepest nesting depth
|
39
|
+
# that is greater than our allowed maximum. This means if two iterators
|
40
|
+
# with the same depth were found, we combine them into one warning and
|
41
|
+
# merge the line information.
|
42
42
|
#
|
43
43
|
# @return [Array<SmellWarning>]
|
44
44
|
#
|
45
|
-
# :reek:TooManyStatements: { max_statements: 6 }
|
46
45
|
def inspect(ctx)
|
47
|
-
configure_ignore_iterators
|
48
|
-
|
49
|
-
return [] unless deepest_iterator
|
50
|
-
depth = deepest_iterator.depth
|
51
|
-
return [] unless depth > max_nesting(ctx)
|
46
|
+
configure_ignore_iterators ctx
|
47
|
+
violations = find_violations ctx
|
52
48
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
49
|
+
violations.group_by(&:depth).map do |depth, group|
|
50
|
+
lines = group.map(&:line)
|
51
|
+
smell_warning(
|
52
|
+
context: ctx,
|
53
|
+
lines: lines,
|
54
|
+
message: "contains iterators nested #{depth} deep",
|
55
|
+
parameters: { name: ctx.full_name, count: depth })
|
56
|
+
end
|
58
57
|
end
|
59
58
|
|
60
59
|
private
|
61
60
|
|
62
61
|
attr_accessor :ignore_iterators
|
63
62
|
|
63
|
+
# Finds the set of independent most deeply nested iterators that are
|
64
|
+
# nested more deeply than allowed.
|
65
|
+
#
|
66
|
+
# Here, independent means that if iterator A is contained within iterator
|
67
|
+
# B, we only include A. But if iterators A and B are both contained in
|
68
|
+
# iterator C, but A is not contained in B, nor B in A, both A and B are
|
69
|
+
# included.
|
70
|
+
#
|
71
|
+
# @return [Array<Iterator>]
|
72
|
+
#
|
73
|
+
def find_violations(ctx)
|
74
|
+
candidates = find_candidates ctx
|
75
|
+
max_allowed_nesting = max_nesting(ctx)
|
76
|
+
candidates.select { |it| it.depth > max_allowed_nesting }
|
77
|
+
end
|
78
|
+
|
79
|
+
# Finds the set of independent most deeply nested iterators regardless of
|
80
|
+
# nesting depth.
|
64
81
|
#
|
65
|
-
# @return [Iterator
|
82
|
+
# @return [Array<Iterator>]
|
66
83
|
#
|
67
|
-
def
|
84
|
+
def find_candidates(ctx)
|
68
85
|
exp = ctx.exp
|
69
|
-
|
70
|
-
scout(parent: exp, exp: exp, depth: 0).
|
71
|
-
flatten.
|
72
|
-
sort.
|
73
|
-
last
|
86
|
+
scout(exp: exp, depth: 0)
|
74
87
|
end
|
75
88
|
|
76
89
|
# A little digression into parser's sexp is necessary here:
|
@@ -79,36 +92,38 @@ module Reek
|
|
79
92
|
# foo.each() do ... end
|
80
93
|
# this will end up as:
|
81
94
|
#
|
82
|
-
# "foo.each() do ... end" -> the
|
83
|
-
# "each()" -> the "call"
|
84
|
-
# "do ... end" -> the "block"
|
85
|
-
#
|
86
|
-
# @param parent [AST::Node] The parent iterator
|
95
|
+
# "foo.each() do ... end" -> one of the :block nodes
|
96
|
+
# "each()" -> the node's "call"
|
97
|
+
# "do ... end" -> the node's "block"
|
87
98
|
#
|
88
99
|
# @param exp [AST::Node]
|
89
100
|
# The given expression to analyze.
|
90
|
-
# Will be nil on empty blocks so we'll return just the parent iterator
|
91
101
|
#
|
92
102
|
# @param depth [Integer]
|
93
103
|
#
|
94
104
|
# @return [Array<Iterator>]
|
95
105
|
#
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
106
|
+
# :reek:TooManyStatements: { max_statements: 6 }
|
107
|
+
def scout(exp:, depth:)
|
108
|
+
return [] unless exp
|
109
|
+
exp.find_nodes([:block]).flat_map do |iterator|
|
110
|
+
new_depth = increment_depth(iterator, depth)
|
101
111
|
# 1st case: we recurse down the given block of the iterator. In this case
|
102
112
|
# we need to check if we should increment the depth.
|
103
113
|
# 2nd case: we recurse down the associated call of the iterator. In this case
|
104
114
|
# the depth stays the same.
|
105
|
-
scout(
|
106
|
-
scout(
|
115
|
+
nested_iterators = scout(exp: iterator.block, depth: new_depth) +
|
116
|
+
scout(exp: iterator.call, depth: depth)
|
117
|
+
if nested_iterators.empty?
|
118
|
+
Iterator.new(iterator, new_depth)
|
119
|
+
else
|
120
|
+
nested_iterators
|
121
|
+
end
|
107
122
|
end
|
108
123
|
end
|
109
124
|
|
110
125
|
def configure_ignore_iterators(ctx)
|
111
|
-
self.ignore_iterators = value(IGNORE_ITERATORS_KEY, ctx
|
126
|
+
self.ignore_iterators = value(IGNORE_ITERATORS_KEY, ctx)
|
112
127
|
end
|
113
128
|
|
114
129
|
def increment_depth(iterator, depth)
|
@@ -116,7 +131,7 @@ module Reek
|
|
116
131
|
end
|
117
132
|
|
118
133
|
def max_nesting(ctx)
|
119
|
-
value(MAX_ALLOWED_NESTING_KEY, ctx
|
134
|
+
value(MAX_ALLOWED_NESTING_KEY, ctx)
|
120
135
|
end
|
121
136
|
|
122
137
|
# :reek:FeatureEnvy
|
@@ -49,7 +49,7 @@ module Reek
|
|
49
49
|
# :reek:TooManyStatements: { max_statements: 6 }
|
50
50
|
# :reek:DuplicateMethodCall: { max_calls: 2 }
|
51
51
|
def inspect(ctx)
|
52
|
-
max_identical_ifs = value(MAX_IDENTICAL_IFS_KEY, ctx
|
52
|
+
max_identical_ifs = value(MAX_IDENTICAL_IFS_KEY, ctx)
|
53
53
|
conditional_counts(ctx).select do |_key, lines|
|
54
54
|
lines.length > max_identical_ifs
|
55
55
|
end.map do |key, lines|
|
@@ -29,13 +29,14 @@ module Reek
|
|
29
29
|
Overrides.new(options.fetch(OVERRIDES_KEY, {})).for_context(context)
|
30
30
|
end
|
31
31
|
|
32
|
-
# Retrieves the value, if any, for the given +key+.
|
32
|
+
# Retrieves the value, if any, for the given +key+ in the given +context+.
|
33
33
|
#
|
34
|
-
#
|
34
|
+
# Raises an error if neither the context nor this config have a value for
|
35
|
+
# the key.
|
35
36
|
#
|
36
|
-
def value(key, context
|
37
|
+
def value(key, context)
|
37
38
|
overrides_for(context).each { |conf| return conf[key] if conf.key?(key) }
|
38
|
-
options.fetch(key
|
39
|
+
options.fetch(key)
|
39
40
|
end
|
40
41
|
|
41
42
|
private
|
@@ -52,7 +52,7 @@ module Reek
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def exception?(context)
|
55
|
-
context.matches?(value(EXCLUDE_KEY, context
|
55
|
+
context.matches?(value(EXCLUDE_KEY, context))
|
56
56
|
end
|
57
57
|
|
58
58
|
def self.todo_configuration_for(smells)
|
@@ -69,8 +69,8 @@ module Reek
|
|
69
69
|
config.enabled? && config_for(context)[SmellConfiguration::ENABLED_KEY] != false
|
70
70
|
end
|
71
71
|
|
72
|
-
def value(key, ctx
|
73
|
-
config_for(ctx)[key] || config.value(key, ctx
|
72
|
+
def value(key, ctx)
|
73
|
+
config_for(ctx)[key] || config.value(key, ctx)
|
74
74
|
end
|
75
75
|
|
76
76
|
def config_for(ctx)
|
@@ -35,7 +35,7 @@ module Reek
|
|
35
35
|
# @return [Array<SmellWarning>]
|
36
36
|
#
|
37
37
|
def inspect(ctx)
|
38
|
-
max_allowed_ivars = value(MAX_ALLOWED_IVARS_KEY, ctx
|
38
|
+
max_allowed_ivars = value(MAX_ALLOWED_IVARS_KEY, ctx)
|
39
39
|
count = ctx.local_nodes(:ivasgn).map { |ivasgn| ivasgn.children.first }.uniq.length
|
40
40
|
return [] if count <= max_allowed_ivars
|
41
41
|
[smell_warning(
|
@@ -37,7 +37,7 @@ module Reek
|
|
37
37
|
# @return [Array<SmellWarning>]
|
38
38
|
#
|
39
39
|
def inspect(ctx)
|
40
|
-
max_allowed_methods = value(MAX_ALLOWED_METHODS_KEY, ctx
|
40
|
+
max_allowed_methods = value(MAX_ALLOWED_METHODS_KEY, ctx)
|
41
41
|
# TODO: Only checks instance methods!
|
42
42
|
actual = ctx.node_instance_methods.length
|
43
43
|
return [] if actual <= max_allowed_methods
|
@@ -29,9 +29,7 @@ module Reek
|
|
29
29
|
# @return [Array<SmellWarning>]
|
30
30
|
#
|
31
31
|
def inspect(ctx)
|
32
|
-
max_allowed_statements = value(MAX_ALLOWED_STATEMENTS_KEY,
|
33
|
-
ctx,
|
34
|
-
DEFAULT_MAX_STATEMENTS)
|
32
|
+
max_allowed_statements = value(MAX_ALLOWED_STATEMENTS_KEY, ctx)
|
35
33
|
count = ctx.number_of_statements
|
36
34
|
return [] if count <= max_allowed_statements
|
37
35
|
[smell_warning(
|
@@ -56,11 +56,11 @@ module Reek
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def reject_patterns(context)
|
59
|
-
Array value(REJECT_KEY, context
|
59
|
+
Array value(REJECT_KEY, context)
|
60
60
|
end
|
61
61
|
|
62
62
|
def accept_patterns(context)
|
63
|
-
Array value(ACCEPT_KEY, context
|
63
|
+
Array value(ACCEPT_KEY, context)
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
@@ -71,11 +71,11 @@ module Reek
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def reject_patterns(context)
|
74
|
-
Array value(REJECT_KEY, context
|
74
|
+
Array value(REJECT_KEY, context)
|
75
75
|
end
|
76
76
|
|
77
77
|
def accept_patterns(context)
|
78
|
-
Array value(ACCEPT_KEY, context
|
78
|
+
Array value(ACCEPT_KEY, context)
|
79
79
|
end
|
80
80
|
end
|
81
81
|
end
|
@@ -65,11 +65,11 @@ module Reek
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def reject_patterns(context)
|
68
|
-
Array value(REJECT_KEY, context
|
68
|
+
Array value(REJECT_KEY, context)
|
69
69
|
end
|
70
70
|
|
71
71
|
def accept_patterns(context)
|
72
|
-
Array value(ACCEPT_KEY, context
|
72
|
+
Array value(ACCEPT_KEY, context)
|
73
73
|
end
|
74
74
|
|
75
75
|
# :reek:UtilityFunction
|
@@ -49,8 +49,8 @@ module Reek
|
|
49
49
|
# @return [Array<SmellWarning>]
|
50
50
|
#
|
51
51
|
def inspect(ctx)
|
52
|
-
self.reject_names = value(REJECT_KEY, ctx
|
53
|
-
self.accept_names = value(ACCEPT_KEY, ctx
|
52
|
+
self.reject_names = value(REJECT_KEY, ctx)
|
53
|
+
self.accept_names = value(ACCEPT_KEY, ctx)
|
54
54
|
variable_names(ctx.exp).select do |name, _lines|
|
55
55
|
bad_name?(name, ctx)
|
56
56
|
end.map do |name, lines|
|
@@ -81,7 +81,7 @@ module Reek
|
|
81
81
|
# :reek:FeatureEnvy
|
82
82
|
def ignore_method?(ctx, method)
|
83
83
|
# ignore_contexts will be e.g. ["Foo::Smelly#my_method", "..."]
|
84
|
-
ignore_contexts = value(EXCLUDE_KEY, ctx
|
84
|
+
ignore_contexts = value(EXCLUDE_KEY, ctx)
|
85
85
|
ignore_contexts.any? do |ignore_context|
|
86
86
|
full_name = "#{method.parent.full_name}##{method.name}"
|
87
87
|
full_name[ignore_context]
|
@@ -41,6 +41,10 @@ module Reek
|
|
41
41
|
PUBLIC_METHODS_ONLY_KEY = 'public_methods_only'.freeze
|
42
42
|
PUBLIC_METHODS_ONLY_DEFAULT = false
|
43
43
|
|
44
|
+
def self.default_config
|
45
|
+
super.merge(PUBLIC_METHODS_ONLY_KEY => PUBLIC_METHODS_ONLY_DEFAULT)
|
46
|
+
end
|
47
|
+
|
44
48
|
class << self
|
45
49
|
def contexts # :nodoc:
|
46
50
|
[:def]
|
@@ -76,7 +80,7 @@ module Reek
|
|
76
80
|
|
77
81
|
def ignore_method?(method_ctx)
|
78
82
|
method_ctx.non_public_visibility? &&
|
79
|
-
value(PUBLIC_METHODS_ONLY_KEY, method_ctx
|
83
|
+
value(PUBLIC_METHODS_ONLY_KEY, method_ctx)
|
80
84
|
end
|
81
85
|
end
|
82
86
|
end
|
data/lib/reek/version.rb
CHANGED
data/reek.gemspec
CHANGED
@@ -22,6 +22,6 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.summary = 'Code smell detector for Ruby'
|
23
23
|
|
24
24
|
s.add_runtime_dependency 'codeclimate-engine-rb', '~> 0.3.1'
|
25
|
-
s.add_runtime_dependency 'parser', '~> 2.3', '>= 2.3.
|
25
|
+
s.add_runtime_dependency 'parser', '~> 2.3.1', '>= 2.3.1.2'
|
26
26
|
s.add_runtime_dependency 'rainbow', '~> 2.0'
|
27
27
|
end
|
@@ -82,6 +82,7 @@ RSpec.describe Reek::Smells::NestedIterators do
|
|
82
82
|
}
|
83
83
|
end
|
84
84
|
EOS
|
85
|
+
expect(src).not_to reek_of(:NestedIterators, count: 2)
|
85
86
|
expect(src).to reek_of(:NestedIterators, count: 3)
|
86
87
|
end
|
87
88
|
|
@@ -112,7 +113,7 @@ RSpec.describe Reek::Smells::NestedIterators do
|
|
112
113
|
describe 'inspect / warnings' do
|
113
114
|
let(:detector) { build(:smell_detector, smell_type: :NestedIterators) }
|
114
115
|
|
115
|
-
it 'reports
|
116
|
+
it 'reports a sensible warning message' do
|
116
117
|
source = <<-EOS
|
117
118
|
def foo
|
118
119
|
bar do |bar|
|
@@ -120,41 +121,40 @@ RSpec.describe Reek::Smells::NestedIterators do
|
|
120
121
|
end
|
121
122
|
end
|
122
123
|
EOS
|
123
|
-
|
124
|
-
|
124
|
+
expect(source).to reek_of(:NestedIterators, message: 'contains iterators nested 2 deep')
|
125
|
+
end
|
125
126
|
|
126
|
-
|
127
|
-
|
128
|
-
|
127
|
+
it 'reports the name of the method and line of the deepest iterator' do
|
128
|
+
source = <<-EOS
|
129
|
+
def foo
|
130
|
+
bar do |bar|
|
131
|
+
baz {|baz| }
|
132
|
+
end
|
133
|
+
end
|
134
|
+
EOS
|
135
|
+
expect(source).to reek_of(:NestedIterators, name: 'foo', lines: [3])
|
129
136
|
end
|
130
137
|
|
131
|
-
it '
|
138
|
+
it 'reports all lines on which nested iterators occur' do
|
132
139
|
source = <<-EOS
|
133
|
-
def bad
|
140
|
+
def bad
|
134
141
|
@fred.each {|item| item.each {|part| @joe.send} }
|
135
142
|
@jim.each {|ting| ting.each {|piece| @hal.send} }
|
136
143
|
end
|
137
144
|
EOS
|
138
145
|
|
139
|
-
|
140
|
-
expect(warnings.size).to eq(1)
|
141
|
-
warning = warnings.first
|
142
|
-
expect(warning.parameters[:name]).to eq('bad')
|
146
|
+
expect(source).to reek_of(:NestedIterators, name: 'bad', lines: [2, 3])
|
143
147
|
end
|
144
148
|
|
145
|
-
it 'reports
|
149
|
+
it 'reports separete cases of nested iterators if levels are different' do
|
146
150
|
source = <<-EOS
|
147
|
-
def bad
|
151
|
+
def bad
|
148
152
|
@fred.each {|item| item.each {|part| part.foo} }
|
149
153
|
@jim.each {|ting| ting.each {|piece| piece.each {|atom| atom.foo } } }
|
150
154
|
end
|
151
155
|
EOS
|
152
|
-
|
153
|
-
expect(
|
154
|
-
warning = warnings.first
|
155
|
-
|
156
|
-
expect(warning.parameters[:name]).to eq('bad')
|
157
|
-
expect(warning.lines).to eq([3])
|
156
|
+
expect(source).to reek_of(:NestedIterators, name: 'bad', lines: [2], count: 2)
|
157
|
+
expect(source).to reek_of(:NestedIterators, name: 'bad', lines: [3], count: 3)
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
@@ -2,11 +2,6 @@ require_relative '../../spec_helper'
|
|
2
2
|
require_lib 'reek/smells/smell_configuration'
|
3
3
|
|
4
4
|
RSpec.describe Reek::Smells::SmellConfiguration do
|
5
|
-
it 'returns the default value when key not found' do
|
6
|
-
cf = described_class.new({})
|
7
|
-
expect(cf.value('fred', nil, 27)).to eq(27)
|
8
|
-
end
|
9
|
-
|
10
5
|
context 'when overriding default configs' do
|
11
6
|
let(:base_config) do
|
12
7
|
{
|
@@ -217,6 +217,28 @@ RSpec.describe Reek::Smells::UtilityFunction do
|
|
217
217
|
end
|
218
218
|
end
|
219
219
|
|
220
|
+
context 'with the default configuration' do
|
221
|
+
it 'reports private methods' do
|
222
|
+
src = <<-EOS
|
223
|
+
class C
|
224
|
+
private
|
225
|
+
def m1(a) a.to_s; end
|
226
|
+
end
|
227
|
+
EOS
|
228
|
+
expect(src).to reek_of(:UtilityFunction)
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'reports protected methods' do
|
232
|
+
src = <<-EOS
|
233
|
+
class C
|
234
|
+
protected
|
235
|
+
def m1(a) a.to_s; end
|
236
|
+
end
|
237
|
+
EOS
|
238
|
+
expect(src).to reek_of(:UtilityFunction)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
220
242
|
describe 'disabling UtilityFunction via configuration for non-public methods' do
|
221
243
|
let(:config) do
|
222
244
|
{ Reek::Smells::UtilityFunction::PUBLIC_METHODS_ONLY_KEY => true }
|
data/spec/spec_helper.rb
CHANGED
@@ -82,6 +82,11 @@ RSpec.configure do |config|
|
|
82
82
|
config.mock_with :rspec do |mocks|
|
83
83
|
mocks.verify_partial_doubles = true
|
84
84
|
end
|
85
|
+
|
86
|
+
# Avoid infinitely running tests. This is mainly useful when running mutant.
|
87
|
+
config.around(:each) do |example|
|
88
|
+
Timeout.timeout(5, &example)
|
89
|
+
end
|
85
90
|
end
|
86
91
|
|
87
92
|
private
|
data/tasks/ataru.rake
ADDED
data/tasks/mutant.rake
ADDED
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: 4.0.
|
4
|
+
version: 4.0.4
|
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: 2016-
|
14
|
+
date: 2016-06-12 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: codeclimate-engine-rb
|
@@ -33,20 +33,20 @@ dependencies:
|
|
33
33
|
requirements:
|
34
34
|
- - "~>"
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version:
|
36
|
+
version: 2.3.1
|
37
37
|
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 2.3.
|
39
|
+
version: 2.3.1.2
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
46
|
+
version: 2.3.1
|
47
47
|
- - ">="
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: 2.3.
|
49
|
+
version: 2.3.1.2
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
51
|
name: rainbow
|
52
52
|
requirement: !ruby/object:Gem::Requirement
|
@@ -372,8 +372,10 @@ files:
|
|
372
372
|
- spec/samples/two_smelly_files/dirty_one.rb
|
373
373
|
- spec/samples/two_smelly_files/dirty_two.rb
|
374
374
|
- spec/spec_helper.rb
|
375
|
+
- tasks/ataru.rake
|
375
376
|
- tasks/configuration.rake
|
376
377
|
- tasks/console.rake
|
378
|
+
- tasks/mutant.rake
|
377
379
|
- tasks/reek.rake
|
378
380
|
- tasks/rubocop.rake
|
379
381
|
- tasks/test.rake
|