reek 1.2.8 → 1.2.9
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/README.md +40 -25
- data/Rakefile +2 -15
- data/bin/reek +1 -1
- data/features/{options.feature → command_line_interface/options.feature} +1 -3
- data/features/{stdin.feature → command_line_interface/stdin.feature} +2 -2
- data/features/{masking_smells.feature → configuration_files/masking_smells.feature} +23 -23
- data/features/{rake_task.feature → rake_task/rake_task.feature} +9 -9
- data/features/{reports.feature → reports/reports.feature} +10 -10
- data/features/{yaml.feature → reports/yaml.feature} +2 -2
- data/features/{api.feature → ruby_api/api.feature} +6 -6
- data/features/samples.feature +239 -247
- data/features/step_definitions/reek_steps.rb +15 -1
- data/features/support/env.rb +0 -1
- data/lib/reek.rb +1 -4
- data/lib/reek/cli/command_line.rb +6 -5
- data/lib/reek/cli/report.rb +1 -1
- data/lib/reek/core/hash_extensions.rb +29 -0
- data/lib/reek/core/method_context.rb +3 -16
- data/lib/reek/core/object_refs.rb +5 -22
- data/lib/reek/core/smell_repository.rb +65 -0
- data/lib/reek/core/sniffer.rb +7 -76
- data/lib/reek/core/warning_collector.rb +1 -5
- data/lib/reek/examiner.rb +3 -13
- data/lib/reek/rake/task.rb +10 -2
- data/lib/reek/smell_warning.rb +1 -0
- data/lib/reek/smells/smell_detector.rb +0 -3
- data/lib/reek/smells/uncommunicative_module_name.rb +6 -3
- data/lib/reek/smells/uncommunicative_variable_name.rb +1 -1
- data/lib/reek/source/config_file.rb +8 -2
- data/lib/reek/source/sexp_formatter.rb +1 -1
- data/lib/reek/source/source_repository.rb +31 -0
- data/lib/reek/source/tree_dresser.rb +1 -1
- data/lib/reek/spec/should_reek.rb +5 -2
- data/lib/reek/version.rb +3 -0
- data/lib/xp.reek +63 -0
- data/reek.gemspec +16 -28
- data/spec/gem/manifest_spec.rb +22 -0
- data/spec/gem/updates_spec.rb +26 -0
- data/spec/gem/yard_spec.rb +15 -0
- data/spec/matchers/smell_of_matcher.rb +0 -1
- data/spec/reek/cli/reek_command_spec.rb +1 -1
- data/spec/reek/core/method_context_spec.rb +2 -2
- data/spec/reek/core/object_refs_spec.rb +115 -118
- data/spec/reek/smell_warning_spec.rb +2 -2
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +3 -0
- data/spec/reek/source/sexp_formatter_spec.rb +19 -0
- data/spec/reek/spec/should_reek_spec.rb +21 -3
- data/tasks/deployment.rake +69 -0
- data/tasks/develop.rake +29 -0
- data/tasks/test.rake +1 -6
- metadata +200 -138
@@ -31,13 +31,27 @@ Then /^the exit status indicates smells$/ do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
Then /^it reports:$/ do |report|
|
34
|
-
@last_stdout.should == report
|
34
|
+
@last_stdout.chomp.should == report.chomp
|
35
|
+
end
|
36
|
+
|
37
|
+
Then /^it reports this yaml:$/ do |expected_yaml|
|
38
|
+
expected_warnings = YAML.load(expected_yaml.chomp)
|
39
|
+
actual_warnings = YAML.load(@last_stdout)
|
40
|
+
actual_warnings.should == expected_warnings
|
41
|
+
end
|
42
|
+
|
43
|
+
Then /^it reports something like: (.*)$/ do |line|
|
44
|
+
@last_stdout.chomp.should match Regexp.new(Regexp.escape(line))
|
35
45
|
end
|
36
46
|
|
37
47
|
Then /^stderr reports:$/ do |report|
|
38
48
|
@last_stderr.should == report
|
39
49
|
end
|
40
50
|
|
51
|
+
Then /^it reports an error$/ do
|
52
|
+
@last_stderr.chomp.should_not be_empty
|
53
|
+
end
|
54
|
+
|
41
55
|
Then /^it reports the error ['"](.*)['"]$/ do |string|
|
42
56
|
@last_stderr.chomp.should == string
|
43
57
|
end
|
data/features/support/env.rb
CHANGED
data/lib/reek.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Reek's core functionality
|
3
3
|
#
|
4
|
-
|
5
|
-
VERSION = '1.2.8'
|
6
|
-
end
|
7
|
-
|
4
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), 'reek', 'version')
|
8
5
|
require File.join(File.dirname(File.expand_path(__FILE__)), 'reek', 'examiner')
|
9
6
|
require File.join(File.dirname(File.expand_path(__FILE__)), 'reek', 'smell_warning')
|
@@ -49,7 +49,7 @@ Examples:
|
|
49
49
|
#{progname} -q lib
|
50
50
|
cat my_class.rb | #{progname}
|
51
51
|
|
52
|
-
See http://wiki.github.com/
|
52
|
+
See http://wiki.github.com/troessner/reek for detailed help.
|
53
53
|
|
54
54
|
EOB
|
55
55
|
end
|
@@ -87,12 +87,13 @@ EOB
|
|
87
87
|
HelpCommand.new(@parser)
|
88
88
|
elsif @command_class == VersionCommand
|
89
89
|
VersionCommand.new(@parser.program_name)
|
90
|
-
elsif @command_class == YamlCommand
|
91
|
-
sources = get_sources
|
92
|
-
YamlCommand.create(sources, @config_files)
|
93
90
|
else
|
94
91
|
sources = get_sources
|
95
|
-
|
92
|
+
if @command_class == YamlCommand
|
93
|
+
YamlCommand.create(sources, @config_files)
|
94
|
+
else
|
95
|
+
ReekCommand.create(sources, @report_class, @config_files)
|
96
|
+
end
|
96
97
|
end
|
97
98
|
end
|
98
99
|
|
data/lib/reek/cli/report.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
#
|
2
|
+
# Extensions to +Hash+ needed by Reek.
|
3
|
+
#
|
4
|
+
class Hash
|
5
|
+
def push_keys(hash)
|
6
|
+
keys.each {|key| hash[key].adopt!(self[key]) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def adopt!(other)
|
10
|
+
other.keys.each do |key|
|
11
|
+
ov = other[key]
|
12
|
+
if Array === ov and has_key?(key)
|
13
|
+
self[key] += ov
|
14
|
+
else
|
15
|
+
self[key] = ov
|
16
|
+
end
|
17
|
+
end
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def adopt(other)
|
22
|
+
self.deep_copy.adopt!(other)
|
23
|
+
end
|
24
|
+
|
25
|
+
def deep_copy
|
26
|
+
YAML::load(YAML::dump(self))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -24,19 +24,6 @@ module Reek
|
|
24
24
|
def is_assignment_block?(param)
|
25
25
|
Array === param and param[0] == :block
|
26
26
|
end
|
27
|
-
|
28
|
-
def names
|
29
|
-
return @names if @names
|
30
|
-
@names = self[1..-1].select {|arg| is_arg?(arg)}.map {|arg| arg.to_s }
|
31
|
-
end
|
32
|
-
|
33
|
-
def length
|
34
|
-
names.length
|
35
|
-
end
|
36
|
-
|
37
|
-
def include?(name)
|
38
|
-
names.include?(name)
|
39
|
-
end
|
40
27
|
end
|
41
28
|
|
42
29
|
#
|
@@ -65,14 +52,14 @@ module Reek
|
|
65
52
|
receiver ||= [:self]
|
66
53
|
case receiver[0]
|
67
54
|
when :lvar
|
68
|
-
@refs.
|
55
|
+
@refs.record_reference_to(receiver) unless meth == :new
|
69
56
|
when :self
|
70
|
-
|
57
|
+
@refs.record_reference_to(:self)
|
71
58
|
end
|
72
59
|
end
|
73
60
|
|
74
61
|
def record_use_of_self
|
75
|
-
@refs.
|
62
|
+
@refs.record_reference_to(:self)
|
76
63
|
end
|
77
64
|
|
78
65
|
def envious_receivers
|
@@ -9,24 +9,12 @@ module Reek
|
|
9
9
|
@refs = Hash.new(0)
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
|
12
|
+
def record_reference_to(exp)
|
13
|
+
@refs[exp] += 1
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
|
18
|
-
case type
|
19
|
-
when :gvar
|
20
|
-
return
|
21
|
-
when :self
|
22
|
-
record_reference_to_self
|
23
|
-
else
|
24
|
-
@refs[exp] += 1
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def refs_to_self
|
29
|
-
@refs[SELF_REF]
|
16
|
+
def references_to(exp)
|
17
|
+
@refs[exp]
|
30
18
|
end
|
31
19
|
|
32
20
|
def max_refs
|
@@ -39,13 +27,8 @@ module Reek
|
|
39
27
|
end
|
40
28
|
|
41
29
|
def self_is_max?
|
42
|
-
max_keys.length == 0 || @refs[
|
30
|
+
max_keys.length == 0 || @refs[:self] == max_refs
|
43
31
|
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
SELF_REF = Sexp.from_array([:lit, :self])
|
48
|
-
|
49
32
|
end
|
50
33
|
end
|
51
34
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'smells')
|
2
|
+
|
3
|
+
module Reek
|
4
|
+
module Core
|
5
|
+
class SmellRepository
|
6
|
+
|
7
|
+
def self.smell_classes
|
8
|
+
# SMELL: Duplication -- these should be loaded by listing the files
|
9
|
+
[
|
10
|
+
Smells::Attribute,
|
11
|
+
Smells::BooleanParameter,
|
12
|
+
Smells::ClassVariable,
|
13
|
+
Smells::ControlCouple,
|
14
|
+
Smells::DataClump,
|
15
|
+
Smells::Duplication,
|
16
|
+
Smells::FeatureEnvy,
|
17
|
+
Smells::IrresponsibleModule,
|
18
|
+
Smells::LargeClass,
|
19
|
+
Smells::LongMethod,
|
20
|
+
Smells::LongParameterList,
|
21
|
+
Smells::LongYieldList,
|
22
|
+
Smells::NestedIterators,
|
23
|
+
Smells::SimulatedPolymorphism,
|
24
|
+
Smells::UncommunicativeMethodName,
|
25
|
+
Smells::UncommunicativeModuleName,
|
26
|
+
Smells::UncommunicativeParameterName,
|
27
|
+
Smells::UncommunicativeVariableName,
|
28
|
+
Smells::UtilityFunction,
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize source_description
|
33
|
+
@typed_detectors = nil
|
34
|
+
@detectors = Hash.new
|
35
|
+
SmellRepository.smell_classes.each do |klass|
|
36
|
+
@detectors[klass] = klass.new(source_description)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def configure(klass, config)
|
41
|
+
@detectors[klass].configure_with(config)
|
42
|
+
end
|
43
|
+
|
44
|
+
def report_on listener
|
45
|
+
@detectors.each_value { |detector| detector.report_on(listener) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def examine(scope, node_type)
|
49
|
+
smell_listeners[node_type].each do |detector|
|
50
|
+
detector.examine(scope)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def smell_listeners()
|
57
|
+
unless @typed_detectors
|
58
|
+
@typed_detectors = Hash.new {|hash,key| hash[key] = [] }
|
59
|
+
@detectors.each_value { |detector| detector.register(@typed_detectors) }
|
60
|
+
end
|
61
|
+
@typed_detectors
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/reek/core/sniffer.rb
CHANGED
@@ -1,36 +1,8 @@
|
|
1
1
|
require File.join(File.dirname(File.expand_path(__FILE__)), 'code_parser')
|
2
|
-
require File.join(File.dirname(File.
|
2
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_repository')
|
3
3
|
require File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'source', 'config_file')
|
4
4
|
require 'yaml'
|
5
|
-
|
6
|
-
#
|
7
|
-
# Extensions to +Hash+ needed by Reek.
|
8
|
-
#
|
9
|
-
class Hash
|
10
|
-
def push_keys(hash)
|
11
|
-
keys.each {|key| hash[key].adopt!(self[key]) }
|
12
|
-
end
|
13
|
-
|
14
|
-
def adopt!(other)
|
15
|
-
other.keys.each do |key|
|
16
|
-
ov = other[key]
|
17
|
-
if Array === ov and has_key?(key)
|
18
|
-
self[key] += ov
|
19
|
-
else
|
20
|
-
self[key] = ov
|
21
|
-
end
|
22
|
-
end
|
23
|
-
self
|
24
|
-
end
|
25
|
-
|
26
|
-
def adopt(other)
|
27
|
-
self.deep_copy.adopt!(other)
|
28
|
-
end
|
29
|
-
|
30
|
-
def deep_copy
|
31
|
-
YAML::load(YAML::dump(self))
|
32
|
-
end
|
33
|
-
end
|
5
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), 'hash_extensions')
|
34
6
|
|
35
7
|
module Reek
|
36
8
|
module Core
|
@@ -40,65 +12,24 @@ module Reek
|
|
40
12
|
#
|
41
13
|
class Sniffer
|
42
14
|
|
43
|
-
def
|
44
|
-
|
45
|
-
[
|
46
|
-
Smells::Attribute,
|
47
|
-
Smells::BooleanParameter,
|
48
|
-
Smells::ClassVariable,
|
49
|
-
Smells::ControlCouple,
|
50
|
-
Smells::DataClump,
|
51
|
-
Smells::Duplication,
|
52
|
-
Smells::FeatureEnvy,
|
53
|
-
Smells::IrresponsibleModule,
|
54
|
-
Smells::LargeClass,
|
55
|
-
Smells::LongMethod,
|
56
|
-
Smells::LongParameterList,
|
57
|
-
Smells::LongYieldList,
|
58
|
-
Smells::NestedIterators,
|
59
|
-
Smells::SimulatedPolymorphism,
|
60
|
-
Smells::UncommunicativeMethodName,
|
61
|
-
Smells::UncommunicativeModuleName,
|
62
|
-
Smells::UncommunicativeParameterName,
|
63
|
-
Smells::UncommunicativeVariableName,
|
64
|
-
Smells::UtilityFunction,
|
65
|
-
]
|
66
|
-
end
|
67
|
-
|
68
|
-
def initialize(src, config_files = [])
|
69
|
-
@typed_detectors = nil
|
70
|
-
@detectors = Hash.new
|
71
|
-
Sniffer.smell_classes.each do |klass|
|
72
|
-
@detectors[klass] = klass.new(src.desc)
|
73
|
-
end
|
15
|
+
def initialize(src, config_files = [], smell_repository=Core::SmellRepository.new(src.desc))
|
16
|
+
@smell_repository = smell_repository
|
74
17
|
config_files.each{ |cf| Reek::Source::ConfigFile.new(cf).configure(self) }
|
75
18
|
@source = src
|
76
19
|
src.configure(self)
|
77
20
|
end
|
78
21
|
|
79
22
|
def configure(klass, config)
|
80
|
-
@
|
23
|
+
@smell_repository.configure klass, config
|
81
24
|
end
|
82
25
|
|
83
26
|
def report_on(listener)
|
84
27
|
CodeParser.new(self).process(@source.syntax_tree)
|
85
|
-
@
|
28
|
+
@smell_repository.report_on(listener)
|
86
29
|
end
|
87
30
|
|
88
31
|
def examine(scope, node_type)
|
89
|
-
|
90
|
-
detector.examine(scope)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
def smell_listeners()
|
97
|
-
unless @typed_detectors
|
98
|
-
@typed_detectors = Hash.new {|hash,key| hash[key] = [] }
|
99
|
-
@detectors.each_value { |detector| detector.register(@typed_detectors) }
|
100
|
-
end
|
101
|
-
@typed_detectors
|
32
|
+
@smell_repository.examine scope, node_type
|
102
33
|
end
|
103
34
|
end
|
104
35
|
end
|
@@ -16,11 +16,7 @@ module Reek
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def warnings
|
19
|
-
@warnings.to_a.sort
|
20
|
-
first_sig = [first.context, first.message, first.smell_class]
|
21
|
-
second_sig = [second.context, second.message, second.smell_class]
|
22
|
-
first_sig <=> second_sig
|
23
|
-
end
|
19
|
+
@warnings.to_a.sort
|
24
20
|
end
|
25
21
|
end
|
26
22
|
end
|
data/lib/reek/examiner.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.join(File.dirname(File.expand_path(__FILE__)), 'core', 'sniffer')
|
2
2
|
require File.join(File.dirname(File.expand_path(__FILE__)), 'core', 'warning_collector')
|
3
|
-
require File.join(File.dirname(File.expand_path(__FILE__)), 'source')
|
3
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), 'source', 'source_repository')
|
4
4
|
|
5
5
|
module Reek
|
6
6
|
|
@@ -28,18 +28,8 @@ module Reek
|
|
28
28
|
# each of which is opened and parsed for source code.
|
29
29
|
#
|
30
30
|
def initialize(source, config_files = [])
|
31
|
-
sources =
|
32
|
-
|
33
|
-
@description = 'dir'
|
34
|
-
Source::SourceLocator.new(source).all_sources
|
35
|
-
when Source::SourceCode
|
36
|
-
@description = source.desc
|
37
|
-
[source]
|
38
|
-
else
|
39
|
-
src = source.to_reek_source
|
40
|
-
@description = src.desc
|
41
|
-
[src]
|
42
|
-
end
|
31
|
+
sources = Source::SourceRepository.parse(source)
|
32
|
+
@description = sources.description
|
43
33
|
collector = Core::WarningCollector.new
|
44
34
|
sources.each { |src| Core::Sniffer.new(src, config_files).report_on(collector) }
|
45
35
|
@smells = collector.warnings
|
data/lib/reek/rake/task.rb
CHANGED
@@ -124,8 +124,16 @@ module Reek
|
|
124
124
|
end
|
125
125
|
|
126
126
|
def ruby_options
|
127
|
-
|
128
|
-
|
127
|
+
if bundler?
|
128
|
+
%w(-S bundle exec)
|
129
|
+
else
|
130
|
+
lib_path = @libs.join(File::PATH_SEPARATOR)
|
131
|
+
@ruby_opts.clone << "-I\"#{lib_path}\""
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def bundler?
|
136
|
+
File.exist?('./Gemfile')
|
129
137
|
end
|
130
138
|
|
131
139
|
def sort_option
|