reek 3.2.1 → 3.3.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/CHANGELOG.md +5 -0
- data/Rakefile +0 -1
- data/config/defaults.reek +1 -1
- data/features/samples.feature +17 -16
- data/lib/reek.rb +0 -1
- data/lib/reek/ast/ast_node_class_map.rb +5 -1
- data/lib/reek/ast/node.rb +10 -3
- data/lib/reek/ast/object_refs.rb +11 -5
- data/lib/reek/ast/reference_collector.rb +6 -2
- data/lib/reek/ast/sexp_extensions.rb +42 -1
- data/lib/reek/ast/sexp_formatter.rb +2 -1
- data/lib/reek/cli/application.rb +12 -9
- data/lib/reek/cli/command.rb +6 -0
- data/lib/reek/cli/input.rb +4 -4
- data/lib/reek/cli/option_interpreter.rb +11 -7
- data/lib/reek/cli/options.rb +42 -40
- data/lib/reek/cli/reek_command.rb +3 -3
- data/lib/reek/cli/silencer.rb +12 -3
- data/lib/reek/cli/warning_collector.rb +8 -3
- data/lib/reek/code_comment.rb +6 -1
- data/lib/reek/configuration/app_configuration.rb +65 -100
- data/lib/reek/configuration/configuration_file_finder.rb +4 -13
- data/lib/reek/configuration/configuration_validator.rb +35 -0
- data/lib/reek/configuration/default_directive.rb +12 -0
- data/lib/reek/configuration/directory_directives.rb +54 -0
- data/lib/reek/configuration/excluded_paths.rb +18 -0
- data/lib/reek/context/code_context.rb +19 -17
- data/lib/reek/examiner.rb +9 -7
- data/lib/reek/rake/task.rb +12 -22
- data/lib/reek/report/formatter.rb +6 -1
- data/lib/reek/report/report.rb +22 -13
- data/lib/reek/smells/attribute.rb +6 -53
- data/lib/reek/smells/control_parameter.rb +21 -13
- data/lib/reek/smells/data_clump.rb +17 -9
- data/lib/reek/smells/duplicate_method_call.rb +12 -6
- 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 +4 -2
- data/lib/reek/smells/nil_check.rb +6 -2
- data/lib/reek/smells/repeated_conditional.rb +3 -3
- data/lib/reek/smells/smell_configuration.rb +17 -7
- data/lib/reek/smells/smell_detector.rb +24 -11
- data/lib/reek/smells/smell_repository.rb +1 -1
- 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 +4 -4
- 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 +6 -6
- data/lib/reek/smells/uncommunicative_parameter_name.rb +8 -4
- data/lib/reek/smells/uncommunicative_variable_name.rb +9 -5
- data/lib/reek/smells/utility_function.rb +1 -1
- data/lib/reek/source/source_code.rb +5 -1
- data/lib/reek/source/source_locator.rb +3 -2
- data/lib/reek/spec.rb +3 -3
- data/lib/reek/spec/should_reek.rb +10 -5
- data/lib/reek/spec/should_reek_of.rb +9 -6
- data/lib/reek/spec/should_reek_only_of.rb +13 -8
- data/lib/reek/tree_dresser.rb +6 -2
- data/lib/reek/tree_walker.rb +40 -32
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +1 -1
- data/spec/reek/ast/node_spec.rb +1 -2
- data/spec/reek/ast/object_refs_spec.rb +40 -42
- data/spec/reek/ast/sexp_extensions_spec.rb +98 -104
- data/spec/reek/cli/warning_collector_spec.rb +8 -12
- data/spec/reek/code_comment_spec.rb +3 -5
- data/spec/reek/configuration/app_configuration_spec.rb +43 -57
- data/spec/reek/configuration/configuration_file_finder_spec.rb +5 -7
- data/spec/reek/configuration/default_directive_spec.rb +13 -0
- data/spec/reek/configuration/directory_directives_spec.rb +89 -0
- data/spec/reek/configuration/excluded_paths_spec.rb +30 -0
- data/spec/reek/context/code_context_spec.rb +63 -62
- data/spec/reek/context/method_context_spec.rb +8 -12
- data/spec/reek/context/module_context_spec.rb +1 -1
- data/spec/reek/context/root_context_spec.rb +3 -7
- data/spec/reek/examiner_spec.rb +14 -25
- data/spec/reek/smells/attribute_spec.rb +2 -4
- data/spec/reek/smells/boolean_parameter_spec.rb +5 -7
- data/spec/reek/smells/class_variable_spec.rb +29 -44
- data/spec/reek/smells/control_parameter_spec.rb +7 -9
- data/spec/reek/smells/data_clump_spec.rb +25 -32
- data/spec/reek/smells/duplicate_method_call_spec.rb +8 -7
- data/spec/reek/smells/feature_envy_spec.rb +16 -17
- data/spec/reek/smells/irresponsible_module_spec.rb +2 -4
- data/spec/reek/smells/long_parameter_list_spec.rb +6 -9
- data/spec/reek/smells/long_yield_list_spec.rb +6 -9
- data/spec/reek/smells/nested_iterators_spec.rb +14 -16
- data/spec/reek/smells/repeated_conditional_spec.rb +25 -25
- data/spec/reek/smells/smell_configuration_spec.rb +32 -27
- data/spec/reek/smells/smell_detector_shared.rb +12 -13
- data/spec/reek/smells/smell_warning_spec.rb +54 -58
- data/spec/reek/smells/too_many_instance_variables_spec.rb +9 -9
- data/spec/reek/smells/too_many_methods_spec.rb +13 -14
- data/spec/reek/smells/too_many_statements_spec.rb +8 -10
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +8 -9
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +12 -13
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +7 -10
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +16 -20
- data/spec/reek/smells/utility_function_spec.rb +11 -15
- data/spec/reek/source/source_code_spec.rb +6 -11
- data/spec/reek/spec/should_reek_of_spec.rb +19 -30
- data/spec/reek/spec/should_reek_only_of_spec.rb +28 -34
- data/spec/reek/tree_walker_spec.rb +14 -2
- data/spec/spec_helper.rb +2 -3
- data/tasks/test.rake +0 -5
- metadata +10 -6
- data/docs/Configuration-Files.md +0 -49
- data/spec/gem/updates_spec.rb +0 -25
- data/spec/gem/yard_spec.rb +0 -11
- data/spec/reek/smells/behaves_like_variable_detector.rb +0 -39
@@ -38,12 +38,17 @@ module Reek
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def inherited(subclass)
|
41
|
-
|
42
|
-
@subclasses << subclass
|
41
|
+
subclasses << subclass
|
43
42
|
end
|
44
43
|
|
45
44
|
def descendants
|
46
|
-
|
45
|
+
subclasses
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def subclasses
|
51
|
+
@subclasses ||= []
|
47
52
|
end
|
48
53
|
end
|
49
54
|
|
@@ -69,7 +74,7 @@ module Reek
|
|
69
74
|
end
|
70
75
|
end
|
71
76
|
|
72
|
-
attr_reader :smells_found
|
77
|
+
attr_reader :smells_found # SMELL: only published for tests
|
73
78
|
|
74
79
|
def initialize(source, config = self.class.default_config)
|
75
80
|
@source = source
|
@@ -78,17 +83,17 @@ module Reek
|
|
78
83
|
end
|
79
84
|
|
80
85
|
def register(hooks)
|
81
|
-
return unless
|
86
|
+
return unless config.enabled?
|
82
87
|
self.class.contexts.each { |ctx| hooks[ctx] << self }
|
83
88
|
end
|
84
89
|
|
85
90
|
# SMELL: Getter (only used in 1 test)
|
86
91
|
def enabled?
|
87
|
-
|
92
|
+
config.enabled?
|
88
93
|
end
|
89
94
|
|
90
|
-
def configure_with(
|
91
|
-
|
95
|
+
def configure_with(new_config)
|
96
|
+
config.merge!(new_config)
|
92
97
|
end
|
93
98
|
|
94
99
|
def examine(context)
|
@@ -96,7 +101,7 @@ module Reek
|
|
96
101
|
return if exception?(context)
|
97
102
|
|
98
103
|
sm = examine_context(context)
|
99
|
-
|
104
|
+
self.smells_found += sm
|
100
105
|
end
|
101
106
|
|
102
107
|
def enabled_for?(context)
|
@@ -108,16 +113,24 @@ module Reek
|
|
108
113
|
end
|
109
114
|
|
110
115
|
def report_on(report)
|
111
|
-
|
116
|
+
smells_found.each { |smell| smell.report_on(report) }
|
112
117
|
end
|
113
118
|
|
114
119
|
def value(key, ctx, fall_back)
|
115
|
-
config_for(ctx)[key] ||
|
120
|
+
config_for(ctx)[key] || config.value(key, ctx, fall_back)
|
116
121
|
end
|
117
122
|
|
118
123
|
def config_for(ctx)
|
119
124
|
ctx.config_for(self.class)
|
120
125
|
end
|
126
|
+
|
127
|
+
protected
|
128
|
+
|
129
|
+
attr_writer :smells_found
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
private_attr_reader :config
|
121
134
|
end
|
122
135
|
end
|
123
136
|
end
|
@@ -15,7 +15,7 @@ module Reek
|
|
15
15
|
|
16
16
|
def initialize(source_description: nil,
|
17
17
|
smell_types: self.class.smell_types,
|
18
|
-
configuration: Configuration::AppConfiguration.
|
18
|
+
configuration: Configuration::AppConfiguration.default)
|
19
19
|
@source_via = source_description
|
20
20
|
@configuration = configuration
|
21
21
|
@smell_types = smell_types
|
@@ -8,15 +8,15 @@ module Reek
|
|
8
8
|
class SmellWarning
|
9
9
|
include Comparable
|
10
10
|
extend Forwardable
|
11
|
-
|
11
|
+
attr_reader :context, :lines, :message, :parameters, :smell_detector
|
12
12
|
def_delegators :smell_detector, :smell_category, :smell_type, :source
|
13
13
|
|
14
14
|
def initialize(smell_detector, options = {})
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
@smell_detector = smell_detector
|
16
|
+
@context = options.fetch(:context, '').to_s
|
17
|
+
@lines = options.fetch(:lines)
|
18
|
+
@message = options.fetch(:message)
|
19
|
+
@parameters = options.fetch(:parameters, {})
|
20
20
|
end
|
21
21
|
|
22
22
|
def hash
|
@@ -39,9 +39,9 @@ module Reek
|
|
39
39
|
# @return [Array<SmellWarning>]
|
40
40
|
#
|
41
41
|
def examine_context(ctx)
|
42
|
-
|
42
|
+
max_allowed_ivars = value(MAX_ALLOWED_IVARS_KEY, ctx, DEFAULT_MAX_IVARS)
|
43
43
|
count = ctx.local_nodes(:ivasgn).map { |ivasgn| ivasgn[1] }.uniq.length
|
44
|
-
return [] if count <=
|
44
|
+
return [] if count <= max_allowed_ivars
|
45
45
|
[SmellWarning.new(self,
|
46
46
|
context: ctx.full_name,
|
47
47
|
lines: [ctx.exp.line],
|
@@ -18,7 +18,7 @@ module Reek
|
|
18
18
|
# The name of the config field that sets the maximum number of methods
|
19
19
|
# permitted in a class.
|
20
20
|
MAX_ALLOWED_METHODS_KEY = 'max_methods'
|
21
|
-
DEFAULT_MAX_METHODS =
|
21
|
+
DEFAULT_MAX_METHODS = 15
|
22
22
|
|
23
23
|
def self.smell_category
|
24
24
|
'LargeClass'
|
@@ -41,13 +41,13 @@ module Reek
|
|
41
41
|
# @return [Array<SmellWarning>]
|
42
42
|
#
|
43
43
|
def examine_context(ctx)
|
44
|
-
|
44
|
+
max_allowed_methods = value(MAX_ALLOWED_METHODS_KEY, ctx, DEFAULT_MAX_METHODS)
|
45
45
|
actual = ctx.node_instance_methods.length
|
46
|
-
return [] if actual <=
|
46
|
+
return [] if actual <= max_allowed_methods
|
47
47
|
[SmellWarning.new(self,
|
48
48
|
context: ctx.full_name,
|
49
49
|
lines: [ctx.exp.line],
|
50
|
-
message:
|
50
|
+
message: "has at least #{actual} methods",
|
51
51
|
parameters: { count: actual })]
|
52
52
|
end
|
53
53
|
end
|
@@ -33,11 +33,11 @@ module Reek
|
|
33
33
|
# @return [Array<SmellWarning>]
|
34
34
|
#
|
35
35
|
def examine_context(ctx)
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
max_allowed_statements = value(MAX_ALLOWED_STATEMENTS_KEY,
|
37
|
+
ctx,
|
38
|
+
DEFAULT_MAX_STATEMENTS)
|
39
39
|
count = ctx.num_statements
|
40
|
-
return [] if count <=
|
40
|
+
return [] if count <= max_allowed_statements
|
41
41
|
[SmellWarning.new(self,
|
42
42
|
context: ctx.full_name,
|
43
43
|
lines: [ctx.exp.line],
|
@@ -47,13 +47,13 @@ module Reek
|
|
47
47
|
# @return [Array<SmellWarning>]
|
48
48
|
#
|
49
49
|
def examine_context(ctx)
|
50
|
-
|
51
|
-
|
50
|
+
reject_names = value(REJECT_KEY, ctx, DEFAULT_REJECT_SET)
|
51
|
+
accept_names = value(ACCEPT_KEY, ctx, DEFAULT_ACCEPT_SET)
|
52
52
|
name = ctx.name.to_s
|
53
|
-
return [] if
|
53
|
+
return [] if accept_names.include?(ctx.full_name)
|
54
54
|
var = name.gsub(/^[@\*\&]*/, '')
|
55
|
-
return [] if
|
56
|
-
return [] unless
|
55
|
+
return [] if accept_names.include?(var)
|
56
|
+
return [] unless reject_names.find { |patt| patt =~ var }
|
57
57
|
[SmellWarning.new(self,
|
58
58
|
context: ctx.full_name,
|
59
59
|
lines: [ctx.exp.line],
|
@@ -41,7 +41,7 @@ module Reek
|
|
41
41
|
)
|
42
42
|
end
|
43
43
|
|
44
|
-
def self.contexts
|
44
|
+
def self.contexts # :nodoc:
|
45
45
|
[:module, :class]
|
46
46
|
end
|
47
47
|
|
@@ -52,15 +52,15 @@ module Reek
|
|
52
52
|
#
|
53
53
|
# :reek:Duplication { allow_calls: [ to_s ] }
|
54
54
|
def examine_context(ctx)
|
55
|
-
|
56
|
-
|
55
|
+
reject_names = value(REJECT_KEY, ctx, DEFAULT_REJECT_SET)
|
56
|
+
accept_names = value(ACCEPT_KEY, ctx, DEFAULT_ACCEPT_SET)
|
57
57
|
exp = ctx.exp
|
58
58
|
full_name = ctx.full_name
|
59
59
|
name = exp.simple_name.to_s
|
60
|
-
return [] if
|
60
|
+
return [] if accept_names.include?(full_name)
|
61
61
|
var = name.gsub(/^[@\*\&]*/, '')
|
62
|
-
return [] if
|
63
|
-
return [] unless
|
62
|
+
return [] if accept_names.include?(var)
|
63
|
+
return [] unless reject_names.find { |patt| patt =~ var }
|
64
64
|
[SmellWarning.new(self,
|
65
65
|
context: full_name,
|
66
66
|
lines: [exp.line],
|
@@ -47,8 +47,8 @@ module Reek
|
|
47
47
|
# @return [Array<SmellWarning>]
|
48
48
|
#
|
49
49
|
def examine_context(ctx)
|
50
|
-
|
51
|
-
|
50
|
+
self.reject_names = value(REJECT_KEY, ctx, DEFAULT_REJECT_SET)
|
51
|
+
self.accept_names = value(ACCEPT_KEY, ctx, DEFAULT_ACCEPT_SET)
|
52
52
|
context_expression = ctx.exp
|
53
53
|
context_expression.parameter_names.select do |name|
|
54
54
|
bad_name?(name) && ctx.uses_param?(name)
|
@@ -63,9 +63,13 @@ module Reek
|
|
63
63
|
|
64
64
|
def bad_name?(name)
|
65
65
|
var = name.to_s.gsub(/^[@\*\&]*/, '')
|
66
|
-
return false if var == '*' ||
|
67
|
-
|
66
|
+
return false if var == '*' || accept_names.include?(var)
|
67
|
+
reject_names.find { |patt| patt =~ var }
|
68
68
|
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
private_attr_accessor :accept_names, :reject_names
|
69
73
|
end
|
70
74
|
end
|
71
75
|
end
|
@@ -41,7 +41,7 @@ module Reek
|
|
41
41
|
)
|
42
42
|
end
|
43
43
|
|
44
|
-
def self.contexts
|
44
|
+
def self.contexts # :nodoc:
|
45
45
|
[:module, :class, :def, :defs]
|
46
46
|
end
|
47
47
|
|
@@ -51,8 +51,8 @@ module Reek
|
|
51
51
|
# @return [Array<SmellWarning>]
|
52
52
|
#
|
53
53
|
def examine_context(ctx)
|
54
|
-
|
55
|
-
|
54
|
+
self.reject_names = value(REJECT_KEY, ctx, DEFAULT_REJECT_SET)
|
55
|
+
self.accept_names = value(ACCEPT_KEY, ctx, DEFAULT_ACCEPT_SET)
|
56
56
|
variable_names(ctx.exp).select do |name, _lines|
|
57
57
|
bad_name?(name, ctx)
|
58
58
|
end.map do |name, lines|
|
@@ -66,8 +66,8 @@ module Reek
|
|
66
66
|
|
67
67
|
def bad_name?(name, _ctx)
|
68
68
|
var = name.to_s.gsub(/^[@\*\&]*/, '')
|
69
|
-
return false if
|
70
|
-
|
69
|
+
return false if accept_names.include?(var)
|
70
|
+
reject_names.find { |patt| patt =~ var }
|
71
71
|
end
|
72
72
|
|
73
73
|
def variable_names(exp)
|
@@ -121,6 +121,10 @@ module Reek
|
|
121
121
|
var = varname.to_sym
|
122
122
|
accumulator[var].push(exp.line)
|
123
123
|
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
private_attr_accessor :accept_names, :reject_names
|
124
128
|
end
|
125
129
|
end
|
126
130
|
end
|
@@ -82,7 +82,7 @@ module Reek
|
|
82
82
|
@syntax_tree ||=
|
83
83
|
begin
|
84
84
|
begin
|
85
|
-
ast, comments =
|
85
|
+
ast, comments = parser.parse_with_comments(source, description)
|
86
86
|
rescue Racc::ParseError, Parser::SyntaxError => error
|
87
87
|
$stderr.puts "#{description}: #{error.class.name}: #{error}"
|
88
88
|
end
|
@@ -92,6 +92,10 @@ module Reek
|
|
92
92
|
TreeDresser.new.dress(ast, comment_map)
|
93
93
|
end
|
94
94
|
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
private_attr_reader :parser, :source
|
95
99
|
end
|
96
100
|
end
|
97
101
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'private_attr/everywhere'
|
1
2
|
require 'find'
|
2
3
|
require 'pathname'
|
3
4
|
|
@@ -11,7 +12,7 @@ module Reek
|
|
11
12
|
# Initialize with the paths we want to search.
|
12
13
|
#
|
13
14
|
# paths - a list of paths as Strings
|
14
|
-
def initialize(paths, configuration: Configuration::AppConfiguration.
|
15
|
+
def initialize(paths, configuration: Configuration::AppConfiguration.default)
|
15
16
|
@paths = paths.flat_map do |string|
|
16
17
|
path = Pathname.new(string)
|
17
18
|
current_directory?(path) ? path.entries : path
|
@@ -45,7 +46,7 @@ module Reek
|
|
45
46
|
end
|
46
47
|
|
47
48
|
def path_excluded?(path)
|
48
|
-
configuration.
|
49
|
+
configuration.path_excluded?(path)
|
49
50
|
end
|
50
51
|
|
51
52
|
def print_no_such_file_error(path)
|
data/lib/reek/spec.rb
CHANGED
@@ -87,7 +87,7 @@ module Reek
|
|
87
87
|
#
|
88
88
|
def reek_of(smell_category,
|
89
89
|
smell_details = {},
|
90
|
-
configuration = Configuration::AppConfiguration.
|
90
|
+
configuration = Configuration::AppConfiguration.default)
|
91
91
|
ShouldReekOf.new(smell_category, smell_details, configuration)
|
92
92
|
end
|
93
93
|
|
@@ -98,14 +98,14 @@ module Reek
|
|
98
98
|
# 1.) "reek_of" doesn't mind if there are other smells of a different category.
|
99
99
|
# "reek_only_of" will fail in that case.
|
100
100
|
# 2.) "reek_only_of" doesn't support the additional smell_details hash.
|
101
|
-
def reek_only_of(smell_category, configuration = Configuration::AppConfiguration.
|
101
|
+
def reek_only_of(smell_category, configuration = Configuration::AppConfiguration.default)
|
102
102
|
ShouldReekOnlyOf.new(smell_category, configuration)
|
103
103
|
end
|
104
104
|
|
105
105
|
#
|
106
106
|
# Returns +true+ if and only if the target source code contains smells.
|
107
107
|
#
|
108
|
-
def reek(configuration = Configuration::AppConfiguration.
|
108
|
+
def reek(configuration = Configuration::AppConfiguration.default)
|
109
109
|
ShouldReek.new configuration
|
110
110
|
end
|
111
111
|
end
|
@@ -8,23 +8,28 @@ module Reek
|
|
8
8
|
#
|
9
9
|
# @api private
|
10
10
|
class ShouldReek
|
11
|
-
def initialize(configuration = Configuration::AppConfiguration.
|
11
|
+
def initialize(configuration = Configuration::AppConfiguration.default)
|
12
12
|
@configuration = configuration
|
13
13
|
end
|
14
14
|
|
15
15
|
def matches?(actual)
|
16
|
-
|
17
|
-
|
16
|
+
self.examiner = Examiner.new(actual, configuration: configuration)
|
17
|
+
examiner.smelly?
|
18
18
|
end
|
19
19
|
|
20
20
|
def failure_message
|
21
|
-
"Expected #{
|
21
|
+
"Expected #{examiner.description} to reek, but it didn't"
|
22
22
|
end
|
23
23
|
|
24
24
|
def failure_message_when_negated
|
25
|
-
rpt = Report::Formatter.format_list(
|
25
|
+
rpt = Report::Formatter.format_list(examiner.smells)
|
26
26
|
"Expected no smells, but got:\n#{rpt}"
|
27
27
|
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
private_attr_reader :configuration
|
32
|
+
private_attr_accessor :examiner
|
28
33
|
end
|
29
34
|
end
|
30
35
|
end
|
@@ -10,28 +10,31 @@ module Reek
|
|
10
10
|
class ShouldReekOf
|
11
11
|
def initialize(smell_category,
|
12
12
|
smell_details = {},
|
13
|
-
configuration = Configuration::AppConfiguration.
|
13
|
+
configuration = Configuration::AppConfiguration.default)
|
14
14
|
@smell_category = normalize smell_category
|
15
15
|
@smell_details = smell_details
|
16
16
|
@configuration = configuration
|
17
17
|
end
|
18
18
|
|
19
19
|
def matches?(actual)
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
self.examiner = Examiner.new(actual, configuration: configuration)
|
21
|
+
self.all_smells = examiner.smells
|
22
|
+
all_smells.any? { |warning| warning.matches?(smell_category, smell_details) }
|
23
23
|
end
|
24
24
|
|
25
25
|
def failure_message
|
26
|
-
"Expected #{
|
26
|
+
"Expected #{examiner.description} to reek of #{smell_category}, but it didn't"
|
27
27
|
end
|
28
28
|
|
29
29
|
def failure_message_when_negated
|
30
|
-
"Expected #{
|
30
|
+
"Expected #{examiner.description} not to reek of #{smell_category}, but it did"
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
34
34
|
|
35
|
+
private_attr_reader :configuration, :smell_category, :smell_details
|
36
|
+
private_attr_accessor :all_smells, :examiner
|
37
|
+
|
35
38
|
def normalize(smell_category_or_type)
|
36
39
|
# In theory, users can give us many different types of input (see the documentation for
|
37
40
|
# reek_of below), however we're basically ignoring all of those subleties and just
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative '../examiner'
|
2
2
|
require_relative '../report/formatter'
|
3
|
+
require_relative 'should_reek_of'
|
3
4
|
|
4
5
|
module Reek
|
5
6
|
module Spec
|
@@ -10,24 +11,28 @@ module Reek
|
|
10
11
|
# @api private
|
11
12
|
class ShouldReekOnlyOf < ShouldReekOf
|
12
13
|
def matches?(actual)
|
13
|
-
matches_examiner?(Examiner.new(actual, configuration:
|
14
|
+
matches_examiner?(Examiner.new(actual, configuration: configuration))
|
14
15
|
end
|
15
16
|
|
16
17
|
def matches_examiner?(examiner)
|
17
|
-
|
18
|
-
|
19
|
-
return false if
|
20
|
-
|
18
|
+
self.examiner = examiner
|
19
|
+
self.warnings = examiner.smells
|
20
|
+
return false if warnings.empty?
|
21
|
+
warnings.all? { |warning| warning.matches?(smell_category) }
|
21
22
|
end
|
22
23
|
|
23
24
|
def failure_message
|
24
|
-
rpt = Report::Formatter.format_list(
|
25
|
-
"Expected #{
|
25
|
+
rpt = Report::Formatter.format_list(warnings)
|
26
|
+
"Expected #{examiner.description} to reek only of #{smell_category}, but got:\n#{rpt}"
|
26
27
|
end
|
27
28
|
|
28
29
|
def failure_message_when_negated
|
29
|
-
"Expected #{
|
30
|
+
"Expected #{examiner.description} not to reek only of #{smell_category}, but it did"
|
30
31
|
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
private_attr_accessor :warnings
|
31
36
|
end
|
32
37
|
end
|
33
38
|
end
|