reek 2.2.1 → 3.0.0
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/.rubocop.yml +1 -1
- data/.travis.yml +9 -4
- data/CHANGELOG +8 -0
- data/Gemfile +6 -4
- data/README.md +6 -0
- data/docs/API.md +51 -22
- data/docs/Configuration-Files.md +12 -1
- data/docs/Feature-Envy.md +30 -10
- data/docs/How-reek-works-internally.md +109 -39
- data/docs/RSpec-matchers.md +26 -22
- data/docs/Reek-Driven-Development.md +0 -8
- data/docs/Utility-Function.md +8 -10
- data/features/{ruby_api/api.feature → command_line_interface/basic_usage.feature} +2 -2
- data/features/programmatic_access.feature +21 -2
- data/features/samples.feature +3 -1
- data/lib/reek.rb +2 -2
- data/lib/reek/{core → ast}/ast_node_class_map.rb +8 -8
- data/lib/reek/{sexp/sexp_node.rb → ast/node.rb} +47 -6
- data/lib/reek/{core → ast}/object_refs.rb +2 -1
- data/lib/reek/{core → ast}/reference_collector.rb +2 -1
- data/lib/reek/{sexp → ast}/sexp_extensions.rb +10 -5
- data/lib/reek/{sexp → ast}/sexp_formatter.rb +7 -5
- data/lib/reek/cli/application.rb +1 -0
- data/lib/reek/cli/command.rb +1 -0
- data/lib/reek/cli/input.rb +4 -1
- data/lib/reek/cli/option_interpreter.rb +6 -4
- data/lib/reek/cli/options.rb +2 -1
- data/lib/reek/cli/reek_command.rb +3 -2
- data/lib/reek/cli/silencer.rb +1 -0
- data/lib/reek/{core → cli}/warning_collector.rb +2 -1
- data/lib/reek/code_comment.rb +36 -0
- data/lib/reek/configuration/app_configuration.rb +17 -2
- data/lib/reek/configuration/configuration_file_finder.rb +1 -0
- data/lib/reek/{core → context}/code_context.rb +7 -5
- data/lib/reek/{core → context}/method_context.rb +5 -3
- data/lib/reek/{core → context}/module_context.rb +8 -3
- data/lib/reek/{core/stop_context.rb → context/root_context.rb} +4 -2
- data/lib/reek/{core → context}/singleton_method_context.rb +2 -1
- data/lib/reek/examiner.rb +82 -0
- data/lib/reek/report/formatter.rb +70 -0
- data/lib/reek/report/heading_formatter.rb +45 -0
- data/lib/reek/report/location_formatter.rb +35 -0
- data/lib/reek/report/report.rb +198 -0
- data/lib/reek/smells.rb +24 -13
- data/lib/reek/smells/attribute.rb +6 -4
- data/lib/reek/smells/boolean_parameter.rb +3 -1
- data/lib/reek/smells/class_variable.rb +3 -1
- data/lib/reek/smells/control_parameter.rb +3 -1
- data/lib/reek/smells/data_clump.rb +3 -1
- data/lib/reek/smells/duplicate_method_call.rb +3 -1
- data/lib/reek/smells/feature_envy.rb +3 -1
- data/lib/reek/smells/irresponsible_module.rb +12 -7
- data/lib/reek/smells/long_parameter_list.rb +5 -3
- data/lib/reek/smells/long_yield_list.rb +3 -1
- data/lib/reek/smells/module_initialize.rb +3 -1
- data/lib/reek/smells/nested_iterators.rb +3 -1
- data/lib/reek/smells/nil_check.rb +3 -1
- data/lib/reek/smells/prima_donna_method.rb +3 -1
- data/lib/reek/smells/repeated_conditional.rb +5 -3
- data/lib/reek/{core → smells}/smell_configuration.rb +3 -1
- data/lib/reek/smells/smell_detector.rb +9 -7
- data/lib/reek/{core → smells}/smell_repository.rb +3 -2
- data/lib/reek/smells/smell_warning.rb +6 -4
- data/lib/reek/smells/too_many_instance_variables.rb +3 -1
- data/lib/reek/smells/too_many_methods.rb +3 -1
- data/lib/reek/smells/too_many_statements.rb +3 -1
- data/lib/reek/smells/uncommunicative_method_name.rb +3 -1
- data/lib/reek/smells/uncommunicative_module_name.rb +3 -1
- data/lib/reek/smells/uncommunicative_parameter_name.rb +3 -1
- data/lib/reek/smells/uncommunicative_variable_name.rb +3 -1
- data/lib/reek/smells/unused_parameters.rb +3 -1
- data/lib/reek/smells/utility_function.rb +5 -2
- data/lib/reek/source/source_code.rb +40 -9
- data/lib/reek/source/source_locator.rb +30 -12
- data/lib/reek/spec/should_reek.rb +5 -4
- data/lib/reek/spec/should_reek_of.rb +3 -2
- data/lib/reek/spec/should_reek_only_of.rb +5 -4
- data/lib/reek/tree_dresser.rb +32 -0
- data/lib/reek/tree_walker.rb +182 -0
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +3 -3
- data/spec/factories/factories.rb +2 -0
- data/spec/reek/{sexp/sexp_node_spec.rb → ast/node_spec.rb} +2 -2
- data/spec/reek/{core → ast}/object_refs_spec.rb +3 -3
- data/spec/reek/{core → ast}/reference_collector_spec.rb +2 -2
- data/spec/reek/{sexp → ast}/sexp_extensions_spec.rb +6 -16
- data/spec/reek/{sexp → ast}/sexp_formatter_spec.rb +2 -2
- data/spec/reek/cli/option_interpreter_spec.rb +2 -1
- data/spec/reek/{core → cli}/warning_collector_spec.rb +3 -3
- data/spec/reek/{core/code_comment_spec.rb → code_comment_spec.rb} +3 -3
- data/spec/reek/configuration/app_configuration_spec.rb +31 -18
- data/spec/reek/{core → context}/code_context_spec.rb +14 -15
- data/spec/reek/{core → context}/method_context_spec.rb +8 -8
- data/spec/reek/{core → context}/module_context_spec.rb +4 -4
- data/spec/reek/context/root_context_spec.rb +14 -0
- data/spec/reek/{core → context}/singleton_method_context_spec.rb +4 -4
- data/spec/reek/{core/examiner_spec.rb → examiner_spec.rb} +3 -42
- data/spec/reek/{cli → report}/html_report_spec.rb +5 -5
- data/spec/reek/report/json_report_spec.rb +20 -0
- data/spec/reek/{cli → report}/text_report_spec.rb +14 -14
- data/spec/reek/{cli → report}/xml_report_spec.rb +7 -7
- data/spec/reek/report/yaml_report_spec.rb +20 -0
- data/spec/reek/smells/attribute_spec.rb +2 -1
- data/spec/reek/smells/boolean_parameter_spec.rb +1 -1
- data/spec/reek/smells/class_variable_spec.rb +5 -5
- data/spec/reek/smells/control_parameter_spec.rb +1 -1
- data/spec/reek/smells/data_clump_spec.rb +1 -1
- data/spec/reek/smells/duplicate_method_call_spec.rb +3 -3
- data/spec/reek/smells/feature_envy_spec.rb +1 -1
- data/spec/reek/smells/irresponsible_module_spec.rb +24 -28
- data/spec/reek/smells/long_parameter_list_spec.rb +2 -2
- data/spec/reek/smells/long_yield_list_spec.rb +2 -2
- data/spec/reek/smells/nested_iterators_spec.rb +1 -1
- data/spec/reek/smells/nil_check_spec.rb +2 -2
- data/spec/reek/smells/prima_donna_method_spec.rb +3 -3
- data/spec/reek/smells/repeated_conditional_spec.rb +6 -6
- data/spec/reek/{core → smells}/smell_configuration_spec.rb +4 -4
- data/spec/reek/smells/smell_detector_shared.rb +2 -2
- data/spec/reek/{core → smells}/smell_repository_spec.rb +5 -4
- data/spec/reek/smells/too_many_instance_variables_spec.rb +1 -1
- data/spec/reek/smells/too_many_methods_spec.rb +4 -4
- data/spec/reek/smells/too_many_statements_spec.rb +2 -2
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +1 -1
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +4 -4
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +2 -2
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +3 -3
- data/spec/reek/smells/utility_function_spec.rb +23 -1
- data/spec/reek/source/source_code_spec.rb +1 -1
- data/spec/reek/source/source_locator_spec.rb +30 -0
- data/spec/reek/spec/should_reek_of_spec.rb +0 -17
- data/spec/reek/spec/should_reek_spec.rb +0 -25
- data/spec/reek/tree_dresser_spec.rb +16 -0
- data/spec/reek/{core/tree_walker_spec.rb → tree_walker_spec.rb} +5 -5
- data/spec/samples/{simple_configuration.reek → configuration/simple_configuration.reek} +0 -0
- data/spec/samples/configuration/with_excluded_paths.reek +4 -0
- data/spec/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +5 -0
- data/spec/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +2 -0
- data/spec/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +6 -0
- data/spec/spec_helper.rb +6 -7
- data/tasks/develop.rake +2 -2
- metadata +71 -69
- data/lib/reek/cli/report/formatter.rb +0 -69
- data/lib/reek/cli/report/heading_formatter.rb +0 -45
- data/lib/reek/cli/report/location_formatter.rb +0 -34
- data/lib/reek/cli/report/report.rb +0 -191
- data/lib/reek/core/ast_node.rb +0 -38
- data/lib/reek/core/code_comment.rb +0 -37
- data/lib/reek/core/examiner.rb +0 -85
- data/lib/reek/core/tree_dresser.rb +0 -24
- data/lib/reek/core/tree_walker.rb +0 -180
- data/lib/reek/source/source_repository.rb +0 -43
- data/spec/reek/cli/json_report_spec.rb +0 -20
- data/spec/reek/cli/yaml_report_spec.rb +0 -20
- data/spec/reek/core/object_source_spec.rb +0 -18
- data/spec/reek/core/stop_context_spec.rb +0 -14
- data/spec/reek/core/tree_dresser_spec.rb +0 -16
@@ -1,24 +0,0 @@
|
|
1
|
-
require_relative 'ast_node_class_map'
|
2
|
-
|
3
|
-
module Reek
|
4
|
-
module Core
|
5
|
-
#
|
6
|
-
# Adorns an abstract syntax tree with mix-in modules to make accessing
|
7
|
-
# the tree more understandable and less implementation-dependent.
|
8
|
-
#
|
9
|
-
class TreeDresser
|
10
|
-
def initialize(klass_map = ASTNodeClassMap.new)
|
11
|
-
@klass_map = klass_map
|
12
|
-
end
|
13
|
-
|
14
|
-
def dress(sexp, comment_map)
|
15
|
-
return sexp unless sexp.is_a? AST::Node
|
16
|
-
type = sexp.type
|
17
|
-
children = sexp.children.map { |child| dress(child, comment_map) }
|
18
|
-
comments = comment_map[sexp]
|
19
|
-
@klass_map.klass_for(type).new(type, children,
|
20
|
-
location: sexp.loc, comments: comments)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,180 +0,0 @@
|
|
1
|
-
require_relative 'method_context'
|
2
|
-
require_relative 'module_context'
|
3
|
-
require_relative 'stop_context'
|
4
|
-
require_relative 'singleton_method_context'
|
5
|
-
|
6
|
-
module Reek
|
7
|
-
module Core
|
8
|
-
#
|
9
|
-
# Traverses a Sexp abstract syntax tree and fires events whenever
|
10
|
-
# it encounters specific node types.
|
11
|
-
#
|
12
|
-
# SMELL: This class is responsible for counting statements and for feeding
|
13
|
-
# each context to the smell repository.
|
14
|
-
class TreeWalker
|
15
|
-
def initialize(smell_repository = Core::SmellRepository.new)
|
16
|
-
@smell_repository = smell_repository
|
17
|
-
@element = StopContext.new
|
18
|
-
end
|
19
|
-
|
20
|
-
def process(exp)
|
21
|
-
context_processor = "process_#{exp.type}"
|
22
|
-
if context_processor_exists?(context_processor)
|
23
|
-
send(context_processor, exp)
|
24
|
-
else
|
25
|
-
process_default exp
|
26
|
-
end
|
27
|
-
@element
|
28
|
-
end
|
29
|
-
|
30
|
-
def process_default(exp)
|
31
|
-
exp.children.each do |child|
|
32
|
-
process(child) if child.is_a? AST::Node
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def process_module(exp)
|
37
|
-
inside_new_context(ModuleContext, exp) do
|
38
|
-
process_default(exp)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
alias_method :process_class, :process_module
|
43
|
-
|
44
|
-
def process_def(exp)
|
45
|
-
inside_new_context(MethodContext, exp) do
|
46
|
-
count_clause(exp.body)
|
47
|
-
process_default(exp)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def process_defs(exp)
|
52
|
-
inside_new_context(SingletonMethodContext, exp) do
|
53
|
-
count_clause(exp.body)
|
54
|
-
process_default(exp)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def process_args(_) end
|
59
|
-
|
60
|
-
#
|
61
|
-
# Recording of calls to methods and self
|
62
|
-
#
|
63
|
-
|
64
|
-
def process_send(exp)
|
65
|
-
@element.record_call_to(exp)
|
66
|
-
process_default(exp)
|
67
|
-
end
|
68
|
-
|
69
|
-
alias_method :process_attrasgn, :process_send
|
70
|
-
alias_method :process_op_asgn, :process_send
|
71
|
-
|
72
|
-
def process_ivar(exp)
|
73
|
-
@element.record_use_of_self
|
74
|
-
process_default(exp)
|
75
|
-
end
|
76
|
-
|
77
|
-
alias_method :process_ivasgn, :process_ivar
|
78
|
-
|
79
|
-
def process_self(_)
|
80
|
-
@element.record_use_of_self
|
81
|
-
end
|
82
|
-
|
83
|
-
alias_method :process_zsuper, :process_self
|
84
|
-
|
85
|
-
#
|
86
|
-
# Statement counting
|
87
|
-
#
|
88
|
-
|
89
|
-
def process_block(exp)
|
90
|
-
count_clause(exp.block)
|
91
|
-
process_default(exp)
|
92
|
-
end
|
93
|
-
|
94
|
-
def process_begin(exp)
|
95
|
-
count_statement_list(exp.children)
|
96
|
-
@element.count_statements(-1)
|
97
|
-
process_default(exp)
|
98
|
-
end
|
99
|
-
|
100
|
-
alias_method :process_kwbegin, :process_begin
|
101
|
-
|
102
|
-
def process_if(exp)
|
103
|
-
count_clause(exp[2])
|
104
|
-
count_clause(exp[3])
|
105
|
-
@element.count_statements(-1)
|
106
|
-
process_default(exp)
|
107
|
-
end
|
108
|
-
|
109
|
-
def process_while(exp)
|
110
|
-
count_clause(exp[2])
|
111
|
-
@element.count_statements(-1)
|
112
|
-
process_default(exp)
|
113
|
-
end
|
114
|
-
|
115
|
-
alias_method :process_until, :process_while
|
116
|
-
|
117
|
-
def process_for(exp)
|
118
|
-
count_clause(exp[3])
|
119
|
-
@element.count_statements(-1)
|
120
|
-
process_default(exp)
|
121
|
-
end
|
122
|
-
|
123
|
-
def process_rescue(exp)
|
124
|
-
count_clause(exp[1])
|
125
|
-
@element.count_statements(-1)
|
126
|
-
process_default(exp)
|
127
|
-
end
|
128
|
-
|
129
|
-
def process_resbody(exp)
|
130
|
-
count_statement_list(exp[2..-1].compact)
|
131
|
-
process_default(exp)
|
132
|
-
end
|
133
|
-
|
134
|
-
def process_case(exp)
|
135
|
-
count_clause(exp.else_body)
|
136
|
-
@element.count_statements(-1)
|
137
|
-
process_default(exp)
|
138
|
-
end
|
139
|
-
|
140
|
-
def process_when(exp)
|
141
|
-
count_clause(exp.body)
|
142
|
-
process_default(exp)
|
143
|
-
end
|
144
|
-
|
145
|
-
private
|
146
|
-
|
147
|
-
def context_processor_exists?(name)
|
148
|
-
respond_to?(name)
|
149
|
-
end
|
150
|
-
|
151
|
-
def count_clause(sexp)
|
152
|
-
@element.count_statements(1) if sexp
|
153
|
-
end
|
154
|
-
|
155
|
-
def count_statement_list(statement_list)
|
156
|
-
@element.count_statements statement_list.length
|
157
|
-
end
|
158
|
-
|
159
|
-
def inside_new_context(klass, exp)
|
160
|
-
scope = klass.new(@element, exp)
|
161
|
-
push(scope) do
|
162
|
-
yield
|
163
|
-
check_smells(exp.type)
|
164
|
-
end
|
165
|
-
scope
|
166
|
-
end
|
167
|
-
|
168
|
-
def check_smells(type)
|
169
|
-
@smell_repository.examine(@element, type)
|
170
|
-
end
|
171
|
-
|
172
|
-
def push(scope)
|
173
|
-
orig = @element
|
174
|
-
@element = scope
|
175
|
-
yield
|
176
|
-
@element = orig
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
require_relative 'source_code'
|
2
|
-
require_relative 'source_locator'
|
3
|
-
|
4
|
-
module Reek
|
5
|
-
module Source
|
6
|
-
#
|
7
|
-
# A collection of source code. If the collection is initialized with an array
|
8
|
-
# it is assumed to be a list of file paths. Otherwise it is assumed to be a
|
9
|
-
# single unit of Ruby source code.
|
10
|
-
#
|
11
|
-
class SourceRepository
|
12
|
-
attr_reader :description
|
13
|
-
|
14
|
-
def initialize(description, sources)
|
15
|
-
@description = description
|
16
|
-
@sources = sources
|
17
|
-
end
|
18
|
-
|
19
|
-
# TODO: This method is a least partially broken.
|
20
|
-
# Regardless of how you call reek, be it:
|
21
|
-
# reek lib/
|
22
|
-
# reek lib/file_one.rb lib/file_two.rb
|
23
|
-
# echo "def m; end" | reek
|
24
|
-
# we *always* end up in the "when Source::SourceCode" branch.
|
25
|
-
# So it seems like 80% of this method is never used.
|
26
|
-
def self.parse(source)
|
27
|
-
case source
|
28
|
-
when Array
|
29
|
-
new 'dir', Source::SourceLocator.new(source).sources
|
30
|
-
when Source::SourceCode
|
31
|
-
new source.description, [source]
|
32
|
-
else
|
33
|
-
src = Source::SourceCode.from source
|
34
|
-
new src.description, [src]
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def each(&block)
|
39
|
-
@sources.each(&block)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
require_relative '../../../lib/reek/core/examiner'
|
3
|
-
require_relative '../../../lib/reek/cli/report/report'
|
4
|
-
require_relative '../../../lib/reek/cli/report/formatter'
|
5
|
-
|
6
|
-
RSpec.describe Reek::CLI::Report::JSONReport do
|
7
|
-
let(:instance) { Reek::CLI::Report::JSONReport.new }
|
8
|
-
|
9
|
-
context 'empty source' do
|
10
|
-
let(:examiner) { Reek::Core::Examiner.new('') }
|
11
|
-
|
12
|
-
before do
|
13
|
-
instance.add_examiner examiner
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'prints empty json' do
|
17
|
-
expect { instance.show }.to output(/^\[\]$/).to_stdout
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
require_relative '../../../lib/reek/core/examiner'
|
3
|
-
require_relative '../../../lib/reek/cli/report/report'
|
4
|
-
require_relative '../../../lib/reek/cli/report/formatter'
|
5
|
-
|
6
|
-
RSpec.describe Reek::CLI::Report::YAMLReport do
|
7
|
-
let(:instance) { Reek::CLI::Report::YAMLReport.new }
|
8
|
-
|
9
|
-
context 'empty source' do
|
10
|
-
let(:examiner) { Reek::Core::Examiner.new('') }
|
11
|
-
|
12
|
-
before do
|
13
|
-
instance.add_examiner examiner
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'prints empty yaml' do
|
17
|
-
expect { instance.show }.to output(/^--- \[\]\n.*$/).to_stdout
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
RSpec.describe Dir do
|
4
|
-
it 'reports correct smells via the Dir matcher' do
|
5
|
-
files = Dir['spec/samples/two_smelly_files/*.rb']
|
6
|
-
expect(files).to reek
|
7
|
-
expect(files).to reek_of(:UncommunicativeVariableName)
|
8
|
-
expect(files).not_to reek_of(:LargeClass)
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'copes with daft file specs' do
|
12
|
-
expect(Dir['spec/samples/two_smelly_files/*/.rb']).not_to reek
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'copes with empty array' do
|
16
|
-
expect([]).not_to reek
|
17
|
-
end
|
18
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
require_relative '../../../lib/reek/core/stop_context'
|
3
|
-
|
4
|
-
RSpec.describe Reek::Core::StopContext do
|
5
|
-
before :each do
|
6
|
-
@stop = Reek::Core::StopContext.new
|
7
|
-
end
|
8
|
-
|
9
|
-
context 'full_name' do
|
10
|
-
it 'reports full context' do
|
11
|
-
expect(@stop.full_name).to eq('')
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
require_relative '../../../lib/reek/core/tree_dresser'
|
3
|
-
|
4
|
-
RSpec.describe Reek::Core::TreeDresser do
|
5
|
-
let(:ifnode) { Parser::AST::Node.new(:if) }
|
6
|
-
let(:sendnode) { Parser::AST::Node.new(:send) }
|
7
|
-
let(:dresser) { described_class.new }
|
8
|
-
|
9
|
-
it 'dresses :if sexp with IfNode' do
|
10
|
-
expect(dresser.dress(ifnode, {})).to be_a Reek::Sexp::SexpExtensions::IfNode
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'dresses :send sexp with SendNode' do
|
14
|
-
expect(dresser.dress(sendnode, {})).to be_a Reek::Sexp::SexpExtensions::SendNode
|
15
|
-
end
|
16
|
-
end
|