reek 3.4.0 → 3.4.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 +9 -0
- data/features/step_definitions/reek_steps.rb +19 -16
- data/lib/reek/ast/sexp_extensions.rb +17 -8
- data/lib/reek/cli/application.rb +21 -12
- data/lib/reek/cli/option_interpreter.rb +1 -6
- data/lib/reek/cli/options.rb +32 -22
- data/lib/reek/report/location_formatter.rb +11 -5
- data/lib/reek/smells/smell_warning.rb +10 -2
- data/lib/reek/smells/uncommunicative_method_name.rb +25 -21
- data/lib/reek/smells/uncommunicative_parameter_name.rb +14 -15
- data/lib/reek/spec/should_reek_of.rb +44 -9
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +2 -2
- data/spec/reek/ast/node_spec.rb +1 -1
- data/spec/reek/ast/object_refs_spec.rb +1 -1
- data/spec/reek/ast/reference_collector_spec.rb +1 -1
- data/spec/reek/ast/sexp_extensions_spec.rb +49 -2
- data/spec/reek/ast/sexp_formatter_spec.rb +1 -1
- data/spec/reek/cli/option_interpreter_spec.rb +7 -7
- data/spec/reek/cli/options_spec.rb +27 -19
- data/spec/reek/cli/warning_collector_spec.rb +2 -2
- data/spec/reek/code_comment_spec.rb +1 -1
- data/spec/reek/configuration/app_configuration_spec.rb +4 -4
- data/spec/reek/configuration/default_directive_spec.rb +1 -1
- data/spec/reek/configuration/directory_directives_spec.rb +1 -1
- data/spec/reek/configuration/excluded_paths_spec.rb +1 -1
- data/spec/reek/context/code_context_spec.rb +2 -2
- data/spec/reek/context/method_context_spec.rb +1 -1
- data/spec/reek/context/module_context_spec.rb +2 -2
- data/spec/reek/context/root_context_spec.rb +1 -1
- data/spec/reek/context/singleton_method_context_spec.rb +1 -1
- data/spec/reek/examiner_spec.rb +1 -1
- data/spec/reek/report/html_report_spec.rb +2 -2
- data/spec/reek/report/json_report_spec.rb +3 -3
- data/spec/reek/report/location_formatter_spec.rb +30 -0
- data/spec/reek/report/text_report_spec.rb +4 -4
- data/spec/reek/report/xml_report_spec.rb +2 -2
- data/spec/reek/report/yaml_report_spec.rb +3 -3
- data/spec/reek/smells/attribute_spec.rb +1 -1
- data/spec/reek/smells/boolean_parameter_spec.rb +1 -1
- data/spec/reek/smells/class_variable_spec.rb +2 -2
- 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 +2 -2
- data/spec/reek/smells/irresponsible_module_spec.rb +2 -2
- 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/module_initialize_spec.rb +1 -1
- 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 +1 -1
- data/spec/reek/smells/repeated_conditional_spec.rb +3 -3
- data/spec/reek/smells/smell_configuration_spec.rb +1 -1
- data/spec/reek/smells/smell_repository_spec.rb +2 -2
- data/spec/reek/smells/smell_warning_spec.rb +1 -1
- data/spec/reek/smells/too_many_instance_variables_spec.rb +1 -1
- data/spec/reek/smells/too_many_methods_spec.rb +1 -1
- data/spec/reek/smells/too_many_statements_spec.rb +1 -1
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +2 -2
- 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 +1 -1
- data/spec/reek/smells/unused_parameters_spec.rb +1 -1
- data/spec/reek/smells/utility_function_spec.rb +2 -2
- data/spec/reek/source/source_code_spec.rb +1 -1
- data/spec/reek/source/source_locator_spec.rb +2 -2
- data/spec/reek/spec/should_reek_of_spec.rb +90 -37
- data/spec/reek/spec/should_reek_only_of_spec.rb +1 -1
- data/spec/reek/spec/should_reek_spec.rb +1 -1
- data/spec/reek/tree_dresser_spec.rb +2 -2
- data/spec/reek/tree_walker_spec.rb +2 -2
- data/spec/spec_helper.rb +6 -0
- metadata +7 -6
@@ -18,14 +18,9 @@ module Reek
|
|
18
18
|
#
|
19
19
|
# See {file:docs/Uncommunicative-Parameter-Name.md} for details.
|
20
20
|
class UncommunicativeParameterName < SmellDetector
|
21
|
-
# The name of the config field that lists the regexps of
|
22
|
-
# smelly names to be reported.
|
23
21
|
REJECT_KEY = 'reject'
|
24
22
|
DEFAULT_REJECT_PATTERNS = [/^.$/, /[0-9]$/, /[A-Z]/, /^_/]
|
25
23
|
|
26
|
-
# The name of the config field that lists the specific names that are
|
27
|
-
# to be treated as exceptions; these names will not be reported as
|
28
|
-
# uncommunicative.
|
29
24
|
ACCEPT_KEY = 'accept'
|
30
25
|
DEFAULT_ACCEPT_NAMES = []
|
31
26
|
|
@@ -45,14 +40,15 @@ module Reek
|
|
45
40
|
#
|
46
41
|
# @return [Array<SmellWarning>]
|
47
42
|
#
|
48
|
-
def examine_context(
|
49
|
-
|
50
|
-
|
51
|
-
|
43
|
+
def examine_context(context)
|
44
|
+
expression = context.exp
|
45
|
+
expression.parameter_names.select do |name|
|
46
|
+
sanitized_name = sanitize name
|
47
|
+
uncommunicative_parameter_name?(name: sanitized_name, context: context)
|
52
48
|
end.map do |name|
|
53
49
|
smell_warning(
|
54
|
-
context:
|
55
|
-
lines: [
|
50
|
+
context: context,
|
51
|
+
lines: [expression.line],
|
56
52
|
message: "has the parameter name '#{name}'",
|
57
53
|
parameters: { name: name.to_s })
|
58
54
|
end
|
@@ -60,10 +56,13 @@ module Reek
|
|
60
56
|
|
61
57
|
private
|
62
58
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
59
|
+
def uncommunicative_parameter_name?(name: raise, context: raise)
|
60
|
+
!acceptable_name?(name: name, context: context) && context.uses_param?(name)
|
61
|
+
end
|
62
|
+
|
63
|
+
def acceptable_name?(name: raise, context: raise)
|
64
|
+
accept_names(context).any? { |accept_name| name == accept_name } ||
|
65
|
+
reject_patterns(context).none? { |pattern| name.match pattern }
|
67
66
|
end
|
68
67
|
|
69
68
|
def reject_patterns(context)
|
@@ -7,6 +7,12 @@ module Reek
|
|
7
7
|
# code smell.
|
8
8
|
#
|
9
9
|
class ShouldReekOf
|
10
|
+
attr_reader :failure_message, :failure_message_when_negated
|
11
|
+
|
12
|
+
private_attr_reader :configuration, :smell_category, :smell_details
|
13
|
+
private_attr_writer :failure_message, :failure_message_when_negated
|
14
|
+
private_attr_accessor :examiner
|
15
|
+
|
10
16
|
def initialize(smell_category,
|
11
17
|
smell_details = {},
|
12
18
|
configuration = Configuration::AppConfiguration.default)
|
@@ -17,22 +23,51 @@ module Reek
|
|
17
23
|
|
18
24
|
def matches?(actual)
|
19
25
|
self.examiner = Examiner.new(actual, configuration: configuration)
|
20
|
-
|
21
|
-
|
26
|
+
set_failure_messages
|
27
|
+
matching_smell_types? && matching_smell_details?
|
22
28
|
end
|
23
29
|
|
24
|
-
|
25
|
-
|
30
|
+
private
|
31
|
+
|
32
|
+
def set_failure_messages
|
33
|
+
# We set the failure messages for non-matching smell type unconditionally since we
|
34
|
+
# need that in any case for "failure_message_when_negated" below.
|
35
|
+
# Depending on the existence of matching smell type we check for matching
|
36
|
+
# smell details and then overwrite our failure messages conditionally.
|
37
|
+
set_failure_messages_for_smell_type
|
38
|
+
set_failure_messages_for_smell_details if matching_smell_types? && !matching_smell_details?
|
26
39
|
end
|
27
40
|
|
28
|
-
def
|
29
|
-
|
41
|
+
def matching_smell_types
|
42
|
+
@matching_smell_types ||= examiner.smells.
|
43
|
+
select { |warning| warning.matches_smell_type?(smell_category) }
|
30
44
|
end
|
31
45
|
|
32
|
-
|
46
|
+
def matching_smell_types?
|
47
|
+
matching_smell_types.any?
|
48
|
+
end
|
33
49
|
|
34
|
-
|
35
|
-
|
50
|
+
def matching_smell_details?
|
51
|
+
matching_smell_types.any? { |warning| warning.matches_smell_details?(smell_details) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_failure_messages_for_smell_type
|
55
|
+
self.failure_message = "Expected #{origin} to reek of #{smell_category}, "\
|
56
|
+
'but it didn\'t'
|
57
|
+
self.failure_message_when_negated = "Expected #{origin} not to reek "\
|
58
|
+
"of #{smell_category}, but it did"
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_failure_messages_for_smell_details
|
62
|
+
self.failure_message = "Expected #{origin} to reek of #{smell_category} "\
|
63
|
+
"(which it did) with smell details #{smell_details}, which it didn't"
|
64
|
+
self.failure_message_when_negated = "Expected #{origin} not to reek of "\
|
65
|
+
"#{smell_category} with smell details #{smell_details}, but it did"
|
66
|
+
end
|
67
|
+
|
68
|
+
def origin
|
69
|
+
examiner.description
|
70
|
+
end
|
36
71
|
|
37
72
|
# :reek:UtilityFunction
|
38
73
|
def normalize(smell_category_or_type)
|
data/lib/reek/version.rb
CHANGED
data/reek.gemspec
CHANGED
@@ -28,12 +28,12 @@ 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.9.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'
|
35
35
|
s.add_development_dependency 'factory_girl', '~> 4.0'
|
36
36
|
s.add_development_dependency 'rake', '~> 10.0'
|
37
37
|
s.add_development_dependency 'rspec', '~> 3.0'
|
38
|
-
s.add_development_dependency 'rubocop', '~> 0.
|
38
|
+
s.add_development_dependency 'rubocop', '~> 0.34.0'
|
39
39
|
end
|
data/spec/reek/ast/node_spec.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require_relative '../../spec_helper'
|
2
|
-
|
2
|
+
require_lib 'reek/ast/sexp_extensions'
|
3
3
|
|
4
4
|
RSpec.describe Reek::AST::SexpExtensions::DefNode do
|
5
5
|
context 'with no parameters' do
|
@@ -231,6 +231,22 @@ RSpec.describe Reek::AST::SexpExtensions::DefsNode do
|
|
231
231
|
end
|
232
232
|
end
|
233
233
|
|
234
|
+
RSpec.describe Reek::AST::SexpExtensions::LvarNode do
|
235
|
+
let(:node) { sexp(:lvar, :foo) }
|
236
|
+
|
237
|
+
describe '#simple_name' do
|
238
|
+
it 'returns the lvar’s name' do
|
239
|
+
expect(node.simple_name).to eq(:foo)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe '#var_name' do
|
244
|
+
it 'returns the lvar’s name' do
|
245
|
+
expect(node.var_name).to eq(:foo)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
234
250
|
RSpec.describe Reek::AST::SexpExtensions::SendNode do
|
235
251
|
context 'with no parameters' do
|
236
252
|
let(:node) { sexp(:send, nil, :hello) }
|
@@ -238,6 +254,26 @@ RSpec.describe Reek::AST::SexpExtensions::SendNode do
|
|
238
254
|
it 'has no argument names' do
|
239
255
|
expect(node.arg_names).to eq []
|
240
256
|
end
|
257
|
+
|
258
|
+
it 'is not considered to be a writable attr' do
|
259
|
+
expect(sexp(:send, nil, :attr).attr_with_writable_flag?).to be_falsey
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
context 'when it’s ‘new’ with no parameters and no receiver' do
|
264
|
+
let(:bare_new) { sexp(:send, nil, :new) }
|
265
|
+
|
266
|
+
it 'is not considered to be a module creation call' do
|
267
|
+
expect(bare_new.module_creation_call?).to be_falsey
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'is not considered to have a module creation receiver' do
|
271
|
+
expect(bare_new.module_creation_receiver?).to be_falsey
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'is considered to be an object creation call' do
|
275
|
+
expect(bare_new.object_creation_call?).to be_truthy
|
276
|
+
end
|
241
277
|
end
|
242
278
|
|
243
279
|
context 'with 1 literal parameter' do
|
@@ -264,6 +300,10 @@ RSpec.describe Reek::AST::SexpExtensions::BlockNode do
|
|
264
300
|
it 'has no parameter names' do
|
265
301
|
expect(node.parameter_names).to eq []
|
266
302
|
end
|
303
|
+
|
304
|
+
it 'has a name' do
|
305
|
+
expect(node.simple_name).to eq(:block)
|
306
|
+
end
|
267
307
|
end
|
268
308
|
|
269
309
|
context 'with 1 parameter' do
|
@@ -337,7 +377,14 @@ RSpec.describe Reek::AST::SexpExtensions::CasgnNode do
|
|
337
377
|
end
|
338
378
|
|
339
379
|
it 'does not define a module' do
|
340
|
-
expect(subject.defines_module?).to
|
380
|
+
expect(subject.defines_module?).to be_falsey
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
context 'with implicit receiver to new' do
|
385
|
+
it 'does not define a module' do
|
386
|
+
exp = sexp(:casgn, nil, :Foo, sexp(:send, nil, :new))
|
387
|
+
expect(exp.defines_module?).to be_falsey
|
341
388
|
end
|
342
389
|
end
|
343
390
|
end
|
@@ -1,19 +1,19 @@
|
|
1
1
|
require_relative '../../spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
require_lib 'reek/cli/options'
|
4
|
+
require_lib 'reek/cli/option_interpreter'
|
5
|
+
require_lib 'reek/report/report'
|
5
6
|
|
6
7
|
RSpec.describe Reek::CLI::OptionInterpreter do
|
7
8
|
describe '#reporter' do
|
8
|
-
let(:instance) { Reek::CLI::OptionInterpreter.new(options) }
|
9
|
-
|
10
9
|
context 'with a valid set of options' do
|
11
10
|
let(:options) do
|
12
|
-
|
13
|
-
location_format: :plain)
|
11
|
+
Reek::CLI::Options.new.parse
|
14
12
|
end
|
13
|
+
subject { described_class.new(options) }
|
14
|
+
|
15
15
|
it 'returns an object of the correct subclass of Report::Base' do
|
16
|
-
expect(
|
16
|
+
expect(subject.reporter).to be_instance_of Reek::Report::TextReport
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -1,28 +1,36 @@
|
|
1
1
|
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
require_relative '../../../lib/reek/cli/options'
|
2
|
+
require_lib 'reek/cli/options'
|
4
3
|
|
5
4
|
RSpec.describe Reek::CLI::Options do
|
6
|
-
describe '#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
allow($stdout).to receive_messages(tty?: false)
|
11
|
-
expect(options.colored).to be false
|
12
|
-
end
|
5
|
+
describe '#initialize' do
|
6
|
+
it 'sets a valid default value for report_format' do
|
7
|
+
expect(subject.report_format).to eq :text
|
8
|
+
end
|
13
9
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
it 'sets a valid default value for location_format' do
|
11
|
+
expect(subject.location_format).to eq :numbers
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'enables colors when stdout is a TTY' do
|
15
|
+
allow($stdout).to receive_messages(tty?: false)
|
16
|
+
expect(subject.colored).to be false
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
it 'does not enable colors when stdout is not a TTY' do
|
20
|
+
allow($stdout).to receive_messages(tty?: true)
|
21
|
+
expect(subject.colored).to be true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'parse' do
|
26
|
+
it 'raises on invalid argument in ARGV' do
|
27
|
+
options = described_class.new
|
28
|
+
options.argv = ['-z']
|
29
|
+
expect { options.parse }.to raise_error(OptionParser::InvalidOption)
|
30
|
+
end
|
22
31
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
32
|
+
it 'returns self' do
|
33
|
+
expect(subject.parse).to be_a(described_class)
|
26
34
|
end
|
27
35
|
end
|
28
36
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
|
2
|
+
require_lib 'reek/cli/warning_collector'
|
3
|
+
require_lib 'reek/smells/smell_warning'
|
4
4
|
|
5
5
|
RSpec.describe Reek::CLI::WarningCollector do
|
6
6
|
let(:collector) { described_class.new }
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'pathname'
|
2
2
|
require_relative '../../spec_helper'
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
require_lib 'reek/configuration/app_configuration'
|
4
|
+
require_lib 'reek/configuration/directory_directives'
|
5
|
+
require_lib 'reek/configuration/default_directive'
|
6
|
+
require_lib 'reek/configuration/excluded_paths'
|
7
7
|
|
8
8
|
RSpec.describe Reek::Configuration::AppConfiguration do
|
9
9
|
describe '#new' do
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
|
2
|
+
require_lib 'reek/context/method_context'
|
3
|
+
require_lib 'reek/context/module_context'
|
4
4
|
|
5
5
|
RSpec.describe Reek::Context::CodeContext do
|
6
6
|
context 'name recognition' do
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
|
2
|
+
require_lib 'reek/context/module_context'
|
3
|
+
require_lib 'reek/context/root_context'
|
4
4
|
|
5
5
|
RSpec.describe Reek::Context::ModuleContext do
|
6
6
|
it 'should report module name for smell in method' do
|