reek 3.2 → 3.2.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 +4 -0
- data/lib/reek/ast/ast_node_class_map.rb +1 -5
- data/lib/reek/ast/node.rb +2 -4
- data/lib/reek/ast/object_refs.rb +5 -9
- data/lib/reek/ast/reference_collector.rb +2 -4
- data/lib/reek/cli/application.rb +9 -12
- data/lib/reek/cli/command.rb +0 -4
- data/lib/reek/cli/input.rb +4 -4
- data/lib/reek/cli/option_interpreter.rb +7 -11
- data/lib/reek/cli/options.rb +40 -42
- data/lib/reek/cli/reek_command.rb +3 -3
- data/lib/reek/cli/warning_collector.rb +3 -7
- data/lib/reek/code_comment.rb +1 -5
- data/lib/reek/context/code_context.rb +17 -19
- data/lib/reek/examiner.rb +6 -8
- data/lib/reek/rake/task.rb +22 -12
- data/lib/reek/report/formatter.rb +1 -5
- data/lib/reek/report/report.rb +13 -22
- data/lib/reek/smells/attribute.rb +6 -9
- data/lib/reek/smells/control_parameter.rb +13 -21
- data/lib/reek/smells/data_clump.rb +9 -17
- data/lib/reek/smells/duplicate_method_call.rb +6 -12
- data/lib/reek/smells/long_parameter_list.rb +2 -2
- data/lib/reek/smells/long_yield_list.rb +4 -4
- data/lib/reek/smells/nested_iterators.rb +2 -4
- data/lib/reek/smells/nil_check.rb +2 -6
- data/lib/reek/smells/repeated_conditional.rb +2 -2
- data/lib/reek/smells/smell_configuration.rb +7 -15
- data/lib/reek/smells/smell_detector.rb +10 -23
- data/lib/reek/smells/smell_warning.rb +6 -6
- data/lib/reek/smells/too_many_instance_variables.rb +2 -2
- data/lib/reek/smells/too_many_methods.rb +2 -2
- data/lib/reek/smells/too_many_statements.rb +4 -4
- data/lib/reek/smells/uncommunicative_method_name.rb +5 -5
- data/lib/reek/smells/uncommunicative_module_name.rb +5 -5
- data/lib/reek/smells/uncommunicative_parameter_name.rb +4 -8
- data/lib/reek/smells/uncommunicative_variable_name.rb +4 -8
- data/lib/reek/source/source_code.rb +1 -5
- data/lib/reek/spec/should_reek.rb +4 -9
- data/lib/reek/spec/should_reek_of.rb +5 -8
- data/lib/reek/spec/should_reek_only_of.rb +8 -12
- data/lib/reek/tree_dresser.rb +2 -6
- data/lib/reek/tree_walker.rb +22 -28
- data/lib/reek/version.rb +1 -1
- metadata +1 -1
data/lib/reek/code_comment.rb
CHANGED
@@ -21,7 +21,7 @@ module Reek
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def descriptive?
|
24
|
-
text.split(/\s+/).length >= 2
|
24
|
+
@text.split(/\s+/).length >= 2
|
25
25
|
end
|
26
26
|
|
27
27
|
protected
|
@@ -32,9 +32,5 @@ module Reek
|
|
32
32
|
# TODO: extend this to all configs -------------------^
|
33
33
|
# TODO: extend to allow configuration of whole smell class, not just subclass
|
34
34
|
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
private_attr_reader :text
|
39
35
|
end
|
40
36
|
end
|
@@ -70,11 +70,11 @@ module Reek
|
|
70
70
|
# @param child [CodeContext] the child context to register
|
71
71
|
def append_child_context(child)
|
72
72
|
child.visibility = tracked_visibility
|
73
|
-
children << child
|
73
|
+
@children << child
|
74
74
|
end
|
75
75
|
|
76
76
|
def count_statements(num)
|
77
|
-
|
77
|
+
@num_statements += num
|
78
78
|
end
|
79
79
|
|
80
80
|
def record_call_to(exp)
|
@@ -83,19 +83,19 @@ module Reek
|
|
83
83
|
case type
|
84
84
|
when :lvar, :lvasgn
|
85
85
|
unless exp.object_creation_call?
|
86
|
-
refs.record_reference_to(receiver.name, line: exp.line)
|
86
|
+
@refs.record_reference_to(receiver.name, line: exp.line)
|
87
87
|
end
|
88
88
|
when :self
|
89
|
-
refs.record_reference_to(:self, line: exp.line)
|
89
|
+
@refs.record_reference_to(:self, line: exp.line)
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
93
|
def record_use_of_self
|
94
|
-
refs.record_reference_to(:self)
|
94
|
+
@refs.record_reference_to(:self)
|
95
95
|
end
|
96
96
|
|
97
97
|
def name
|
98
|
-
exp.name
|
98
|
+
@exp.name
|
99
99
|
end
|
100
100
|
|
101
101
|
def local_nodes(type, &blk)
|
@@ -103,7 +103,7 @@ module Reek
|
|
103
103
|
end
|
104
104
|
|
105
105
|
def each_node(type, ignoring, &blk)
|
106
|
-
exp.each_node(type, ignoring, &blk)
|
106
|
+
@exp.each_node(type, ignoring, &blk)
|
107
107
|
end
|
108
108
|
|
109
109
|
def matches?(candidates)
|
@@ -119,7 +119,8 @@ module Reek
|
|
119
119
|
end
|
120
120
|
|
121
121
|
def full_name
|
122
|
-
|
122
|
+
context = @context ? @context.full_name : ''
|
123
|
+
exp.full_name(context)
|
123
124
|
end
|
124
125
|
|
125
126
|
def config_for(detector_class)
|
@@ -139,49 +140,46 @@ module Reek
|
|
139
140
|
# @param names [Array<Symbol>]
|
140
141
|
def track_visibility(visibility, names = [])
|
141
142
|
if names.any?
|
142
|
-
children.each do |child|
|
143
|
+
@children.each do |child|
|
143
144
|
child.visibility = visibility if names.include? child.name
|
144
145
|
end
|
145
146
|
else
|
146
|
-
|
147
|
+
@tracked_visibility = visibility
|
147
148
|
end
|
148
149
|
end
|
149
150
|
|
150
151
|
def type
|
151
|
-
exp.type
|
152
|
+
@exp.type
|
152
153
|
end
|
153
154
|
|
154
155
|
# Iterate over +self+ and child contexts.
|
155
156
|
def each(&block)
|
156
157
|
yield self
|
157
|
-
children.each do |child|
|
158
|
+
@children.each do |child|
|
158
159
|
child.each(&block)
|
159
160
|
end
|
160
161
|
end
|
161
162
|
|
162
163
|
protected
|
163
164
|
|
164
|
-
attr_writer :
|
165
|
+
attr_writer :visibility
|
165
166
|
|
166
167
|
private
|
167
168
|
|
168
|
-
private_attr_writer :tracked_visibility
|
169
|
-
private_attr_reader :context, :refs
|
170
|
-
|
171
169
|
def tracked_visibility
|
172
170
|
@tracked_visibility ||= :public
|
173
171
|
end
|
174
172
|
|
175
173
|
def config
|
176
|
-
@config ||= if exp
|
177
|
-
CodeComment.new(exp.full_comment || '').config
|
174
|
+
@config ||= if @exp
|
175
|
+
CodeComment.new(@exp.full_comment || '').config
|
178
176
|
else
|
179
177
|
{}
|
180
178
|
end
|
181
179
|
end
|
182
180
|
|
183
181
|
def context_config_for(detector_class)
|
184
|
-
context ? context.config_for(detector_class) : {}
|
182
|
+
@context ? @context.config_for(detector_class) : {}
|
185
183
|
end
|
186
184
|
end
|
187
185
|
end
|
data/lib/reek/examiner.rb
CHANGED
@@ -39,14 +39,14 @@ module Reek
|
|
39
39
|
# @return [String] description of the source being analysed
|
40
40
|
#
|
41
41
|
def description
|
42
|
-
@description ||= source.description
|
42
|
+
@description ||= @source.description
|
43
43
|
end
|
44
44
|
|
45
45
|
#
|
46
46
|
# @return [Array<SmellWarning>] the smells found in the source
|
47
47
|
#
|
48
48
|
def smells
|
49
|
-
@smells ||= collector.warnings
|
49
|
+
@smells ||= @collector.warnings
|
50
50
|
end
|
51
51
|
|
52
52
|
#
|
@@ -65,15 +65,13 @@ module Reek
|
|
65
65
|
|
66
66
|
private
|
67
67
|
|
68
|
-
private_attr_reader :configuration, :collector, :smell_types, :source
|
69
|
-
|
70
68
|
def run
|
71
69
|
smell_repository = Smells::SmellRepository.new(source_description: description,
|
72
|
-
smell_types: smell_types,
|
73
|
-
configuration: configuration)
|
74
|
-
syntax_tree = source.syntax_tree
|
70
|
+
smell_types: @smell_types,
|
71
|
+
configuration: @configuration)
|
72
|
+
syntax_tree = @source.syntax_tree
|
75
73
|
TreeWalker.new(smell_repository, syntax_tree).walk if syntax_tree
|
76
|
-
smell_repository.report_on(collector)
|
74
|
+
smell_repository.report_on(@collector)
|
77
75
|
end
|
78
76
|
|
79
77
|
def eligible_smell_types(filter_by_smells = [])
|
data/lib/reek/rake/task.rb
CHANGED
@@ -39,17 +39,17 @@ module Reek
|
|
39
39
|
|
40
40
|
# Path to reek's config file.
|
41
41
|
# Setting the REEK_CFG environment variable overrides this.
|
42
|
-
|
42
|
+
attr_writer :config_file
|
43
43
|
|
44
44
|
# Glob pattern to match source files.
|
45
45
|
# Setting the REEK_SRC environment variable overrides this.
|
46
46
|
# Defaults to 'lib/**/*.rb'.
|
47
|
-
|
47
|
+
attr_writer :source_files
|
48
48
|
|
49
49
|
# String containing commandline options to be passed to Reek.
|
50
50
|
# Setting the REEK_OPTS environment variable overrides this value.
|
51
51
|
# Defaults to ''.
|
52
|
-
|
52
|
+
attr_writer :reek_opts
|
53
53
|
|
54
54
|
# Whether or not to fail Rake when an error occurs (typically when smells are found).
|
55
55
|
# Defaults to true.
|
@@ -60,11 +60,10 @@ module Reek
|
|
60
60
|
attr_writer :verbose
|
61
61
|
|
62
62
|
def initialize(name = :reek)
|
63
|
-
@config_file = ENV['REEK_CFG']
|
64
63
|
@name = name
|
65
|
-
@reek_opts =
|
64
|
+
@reek_opts = ''
|
66
65
|
@fail_on_error = true
|
67
|
-
@source_files =
|
66
|
+
@source_files = 'lib/**/*.rb'
|
68
67
|
@verbose = false
|
69
68
|
|
70
69
|
yield self if block_given?
|
@@ -73,17 +72,15 @@ module Reek
|
|
73
72
|
|
74
73
|
private
|
75
74
|
|
76
|
-
private_attr_reader :fail_on_error, :name, :verbose
|
77
|
-
|
78
75
|
def define_task
|
79
76
|
desc 'Check for code smells'
|
80
|
-
task(name) { run_task }
|
77
|
+
task(@name) { run_task }
|
81
78
|
end
|
82
79
|
|
83
80
|
def run_task
|
84
|
-
puts "\n\n!!! Running 'reek' rake command: #{command}\n\n" if verbose
|
81
|
+
puts "\n\n!!! Running 'reek' rake command: #{command}\n\n" if @verbose
|
85
82
|
system(*command)
|
86
|
-
abort("\n\n!!! `reek` has found smells - exiting!") if sys_call_failed? && fail_on_error
|
83
|
+
abort("\n\n!!! `reek` has found smells - exiting!") if sys_call_failed? && @fail_on_error
|
87
84
|
end
|
88
85
|
|
89
86
|
def command
|
@@ -92,12 +89,25 @@ module Reek
|
|
92
89
|
reject(&:empty?)
|
93
90
|
end
|
94
91
|
|
92
|
+
def source_files
|
93
|
+
FileList[ENV['REEK_SRC'] || @source_files]
|
94
|
+
end
|
95
|
+
|
96
|
+
def reek_opts
|
97
|
+
ENV['REEK_OPTS'] || @reek_opts
|
98
|
+
end
|
99
|
+
|
100
|
+
def config_file
|
101
|
+
ENV['REEK_CFG'] || @config_file
|
102
|
+
end
|
103
|
+
|
95
104
|
def sys_call_failed?
|
96
105
|
!$CHILD_STATUS.success?
|
97
106
|
end
|
98
107
|
|
99
108
|
def config_file_as_argument
|
100
|
-
|
109
|
+
return [] unless @config_file
|
110
|
+
['-c', @config_file]
|
101
111
|
end
|
102
112
|
|
103
113
|
def reek_opts_as_arguments
|
@@ -35,7 +35,7 @@ module Reek
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def format(warning)
|
38
|
-
"#{location_formatter.format(warning)}#{base_format(warning)}"
|
38
|
+
"#{@location_formatter.format(warning)}#{base_format(warning)}"
|
39
39
|
end
|
40
40
|
|
41
41
|
private
|
@@ -43,10 +43,6 @@ module Reek
|
|
43
43
|
def base_format(warning)
|
44
44
|
"#{warning.context} #{warning.message} (#{warning.smell_type})"
|
45
45
|
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
private_attr_reader :location_formatter
|
50
46
|
end
|
51
47
|
|
52
48
|
#
|
data/lib/reek/report/report.rb
CHANGED
@@ -30,8 +30,8 @@ module Reek
|
|
30
30
|
#
|
31
31
|
# @param [Reek::Examiner] examiner object to report on
|
32
32
|
def add_examiner(examiner)
|
33
|
-
|
34
|
-
examiners << examiner
|
33
|
+
@total_smell_count += examiner.smells_count
|
34
|
+
@examiners << examiner
|
35
35
|
self
|
36
36
|
end
|
37
37
|
|
@@ -42,22 +42,13 @@ module Reek
|
|
42
42
|
|
43
43
|
# @api private
|
44
44
|
def smells?
|
45
|
-
total_smell_count > 0
|
45
|
+
@total_smell_count > 0
|
46
46
|
end
|
47
47
|
|
48
48
|
# @api private
|
49
49
|
def smells
|
50
|
-
examiners.map(&:smells).flatten
|
50
|
+
@examiners.map(&:smells).flatten
|
51
51
|
end
|
52
|
-
|
53
|
-
protected
|
54
|
-
|
55
|
-
attr_accessor :total_smell_count
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
private_attr_reader :examiners, :options, :report_formatter,
|
60
|
-
:sort_by_issue_count, :warning_formatter
|
61
52
|
end
|
62
53
|
|
63
54
|
#
|
@@ -73,7 +64,7 @@ module Reek
|
|
73
64
|
private
|
74
65
|
|
75
66
|
def smell_summaries
|
76
|
-
examiners.map { |ex| summarize_single_examiner(ex) }.reject(&:empty?)
|
67
|
+
@examiners.map { |ex| summarize_single_examiner(ex) }.reject(&:empty?)
|
77
68
|
end
|
78
69
|
|
79
70
|
def display_summary
|
@@ -81,33 +72,33 @@ module Reek
|
|
81
72
|
end
|
82
73
|
|
83
74
|
def display_total_smell_count
|
84
|
-
return unless examiners.size > 1
|
75
|
+
return unless @examiners.size > 1
|
85
76
|
print total_smell_count_message
|
86
77
|
end
|
87
78
|
|
88
79
|
def summarize_single_examiner(examiner)
|
89
80
|
result = heading_formatter.header(examiner)
|
90
81
|
if examiner.smelly?
|
91
|
-
formatted_list = report_formatter.format_list(examiner.smells,
|
92
|
-
|
82
|
+
formatted_list = @report_formatter.format_list(examiner.smells,
|
83
|
+
@warning_formatter)
|
93
84
|
result += ":\n#{formatted_list}"
|
94
85
|
end
|
95
86
|
result
|
96
87
|
end
|
97
88
|
|
98
89
|
def sort_examiners
|
99
|
-
examiners.sort_by!(&:smells_count).reverse! if sort_by_issue_count
|
90
|
+
@examiners.sort_by!(&:smells_count).reverse! if @sort_by_issue_count
|
100
91
|
end
|
101
92
|
|
102
93
|
def total_smell_count_message
|
103
94
|
colour = smells? ? WARNINGS_COLOR : NO_WARNINGS_COLOR
|
104
|
-
s = total_smell_count == 1 ? '' : 's'
|
105
|
-
Rainbow("#{total_smell_count} total warning#{s}\n").color(colour)
|
95
|
+
s = @total_smell_count == 1 ? '' : 's'
|
96
|
+
Rainbow("#{@total_smell_count} total warning#{s}\n").color(colour)
|
106
97
|
end
|
107
98
|
|
108
99
|
def heading_formatter
|
109
100
|
@heading_formatter ||=
|
110
|
-
options.fetch(:heading_formatter, HeadingFormatter::Quiet).new(report_formatter)
|
101
|
+
@options.fetch(:heading_formatter, HeadingFormatter::Quiet).new(@report_formatter)
|
111
102
|
end
|
112
103
|
end
|
113
104
|
|
@@ -127,7 +118,7 @@ module Reek
|
|
127
118
|
def show
|
128
119
|
print ::JSON.generate(
|
129
120
|
smells.map do |smell|
|
130
|
-
smell.yaml_hash(warning_formatter)
|
121
|
+
smell.yaml_hash(@warning_formatter)
|
131
122
|
end
|
132
123
|
)
|
133
124
|
end
|
@@ -34,8 +34,8 @@ module Reek
|
|
34
34
|
# @return [Array<SmellWarning>]
|
35
35
|
#
|
36
36
|
def examine_context(ctx)
|
37
|
-
|
38
|
-
|
37
|
+
@visiblity_tracker = {}
|
38
|
+
@visiblity_mode = :public
|
39
39
|
attributes_in(ctx).map do |attribute, line|
|
40
40
|
SmellWarning.new self,
|
41
41
|
context: ctx.full_name,
|
@@ -47,9 +47,6 @@ module Reek
|
|
47
47
|
|
48
48
|
private
|
49
49
|
|
50
|
-
private_attr_accessor :visiblity_mode, :visiblity_tracker
|
51
|
-
private_attr_reader :result
|
52
|
-
|
53
50
|
def attributes_in(module_ctx)
|
54
51
|
attributes = Set.new
|
55
52
|
module_ctx.local_nodes(:send) do |call_node|
|
@@ -81,7 +78,7 @@ module Reek
|
|
81
78
|
|
82
79
|
def track_argument(arg, line)
|
83
80
|
arg_name = arg.children.first
|
84
|
-
visiblity_tracker[arg_name] = visiblity_mode
|
81
|
+
@visiblity_tracker[arg_name] = @visiblity_mode
|
85
82
|
[arg_name, line]
|
86
83
|
end
|
87
84
|
|
@@ -91,14 +88,14 @@ module Reek
|
|
91
88
|
|
92
89
|
def track_visibility(call_node)
|
93
90
|
if call_node.arg_names.any?
|
94
|
-
call_node.arg_names.each { |arg| visiblity_tracker[arg] = call_node.method_name }
|
91
|
+
call_node.arg_names.each { |arg| @visiblity_tracker[arg] = call_node.method_name }
|
95
92
|
else
|
96
|
-
|
93
|
+
@visiblity_mode = call_node.method_name
|
97
94
|
end
|
98
95
|
end
|
99
96
|
|
100
97
|
def recorded_public_methods
|
101
|
-
visiblity_tracker.select { |_, visbility| visbility == :public }
|
98
|
+
@visiblity_tracker.select { |_, visbility| visbility == :public }
|
102
99
|
end
|
103
100
|
end
|
104
101
|
end
|
@@ -73,20 +73,16 @@ module Reek
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def smells?
|
76
|
-
occurences.any?
|
76
|
+
@occurences.any?
|
77
77
|
end
|
78
78
|
|
79
79
|
def lines
|
80
|
-
occurences.map(&:line)
|
80
|
+
@occurences.map(&:line)
|
81
81
|
end
|
82
82
|
|
83
83
|
def name
|
84
|
-
param.to_s
|
84
|
+
@param.to_s
|
85
85
|
end
|
86
|
-
|
87
|
-
private
|
88
|
-
|
89
|
-
private_attr_reader :occurences, :param
|
90
86
|
end
|
91
87
|
|
92
88
|
# Finds cases of ControlParameter in a particular node for a particular parameter
|
@@ -112,15 +108,13 @@ module Reek
|
|
112
108
|
|
113
109
|
private
|
114
110
|
|
115
|
-
private_attr_reader :node, :param
|
116
|
-
|
117
111
|
def conditional_nodes
|
118
|
-
node.body_nodes(CONDITIONAL_NODE_TYPES)
|
112
|
+
@node.body_nodes(CONDITIONAL_NODE_TYPES)
|
119
113
|
end
|
120
114
|
|
121
115
|
def nested_finders
|
122
116
|
@nested_finders ||= conditional_nodes.flat_map do |node|
|
123
|
-
self.class.new(node, param)
|
117
|
+
self.class.new(node, @param)
|
124
118
|
end
|
125
119
|
end
|
126
120
|
|
@@ -135,12 +129,12 @@ module Reek
|
|
135
129
|
|
136
130
|
def uses_of_param_in_condition
|
137
131
|
return [] unless condition
|
138
|
-
condition.each_node(:lvar).select { |inner| inner.var_name == param }
|
132
|
+
condition.each_node(:lvar).select { |inner| inner.var_name == @param }
|
139
133
|
end
|
140
134
|
|
141
135
|
def condition
|
142
|
-
return nil unless CONDITIONAL_NODE_TYPES.include? node.type
|
143
|
-
node.condition
|
136
|
+
return nil unless CONDITIONAL_NODE_TYPES.include? @node.type
|
137
|
+
@node.condition
|
144
138
|
end
|
145
139
|
|
146
140
|
def regular_call_involving_param?(call_node)
|
@@ -156,12 +150,12 @@ module Reek
|
|
156
150
|
end
|
157
151
|
|
158
152
|
def call_involving_param?(call_node)
|
159
|
-
call_node.each_node(:lvar).any? { |it| it.var_name == param }
|
153
|
+
call_node.each_node(:lvar).any? { |it| it.var_name == @param }
|
160
154
|
end
|
161
155
|
|
162
156
|
def uses_param_in_body?
|
163
|
-
nodes = node.body_nodes([:lvar], [:if, :case, :and, :or])
|
164
|
-
nodes.any? { |lvar_node| lvar_node.var_name == param }
|
157
|
+
nodes = @node.body_nodes([:lvar], [:if, :case, :and, :or])
|
158
|
+
nodes.any? { |lvar_node| lvar_node.var_name == @param }
|
165
159
|
end
|
166
160
|
end
|
167
161
|
|
@@ -181,14 +175,12 @@ module Reek
|
|
181
175
|
|
182
176
|
private
|
183
177
|
|
184
|
-
private_attr_reader :context
|
185
|
-
|
186
178
|
def potential_parameters
|
187
|
-
context.exp.parameter_names
|
179
|
+
@context.exp.parameter_names
|
188
180
|
end
|
189
181
|
|
190
182
|
def find_matches(param)
|
191
|
-
ControlParameterFinder.new(context.exp, param).find_matches
|
183
|
+
ControlParameterFinder.new(@context.exp, param).find_matches
|
192
184
|
end
|
193
185
|
end
|
194
186
|
end
|