reek 6.0.0 → 6.0.3

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.github/workflows/ruby.yml +52 -0
  4. data/.rubocop.yml +2 -0
  5. data/.rubocop_todo.yml +27 -20
  6. data/CHANGELOG.md +16 -0
  7. data/Gemfile +5 -6
  8. data/README.md +10 -4
  9. data/docs/Boolean-Parameter.md +2 -2
  10. data/docs/templates/default/docstring/setup.rb +1 -3
  11. data/features/command_line_interface/options.feature +2 -2
  12. data/features/configuration_files/schema_validation.feature +1 -1
  13. data/features/reports/json.feature +3 -3
  14. data/features/reports/reports.feature +4 -4
  15. data/features/reports/yaml.feature +3 -3
  16. data/features/step_definitions/reek_steps.rb +1 -1
  17. data/features/step_definitions/sample_file_steps.rb +2 -2
  18. data/features/support/env.rb +0 -1
  19. data/lib/reek/ast/node.rb +1 -1
  20. data/lib/reek/cli/options.rb +1 -1
  21. data/lib/reek/configuration/app_configuration.rb +4 -3
  22. data/lib/reek/configuration/configuration_converter.rb +2 -2
  23. data/lib/reek/configuration/directory_directives.rb +9 -3
  24. data/lib/reek/configuration/excluded_paths.rb +2 -1
  25. data/lib/reek/context/code_context.rb +1 -1
  26. data/lib/reek/context/module_context.rb +3 -1
  27. data/lib/reek/context/refinement_context.rb +16 -0
  28. data/lib/reek/context_builder.rb +16 -2
  29. data/lib/reek/report/code_climate/code_climate_configuration.yml +1 -1
  30. data/lib/reek/smell_detectors/base_detector.rb +1 -0
  31. data/lib/reek/smell_detectors/boolean_parameter.rb +3 -1
  32. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +1 -1
  33. data/lib/reek/smell_warning.rb +1 -2
  34. data/lib/reek/source/source_locator.rb +13 -10
  35. data/lib/reek/spec/smell_matcher.rb +2 -1
  36. data/lib/reek/version.rb +1 -1
  37. data/lib/reek.rb +1 -0
  38. data/reek.gemspec +10 -2
  39. data/spec/performance/reek/smell_detectors/runtime_speed_spec.rb +2 -4
  40. data/spec/quality/documentation_spec.rb +2 -1
  41. data/spec/reek/code_comment_spec.rb +20 -23
  42. data/spec/reek/configuration/directory_directives_spec.rb +6 -0
  43. data/spec/reek/configuration/excluded_paths_spec.rb +12 -3
  44. data/spec/reek/report/code_climate/code_climate_configuration_spec.rb +1 -3
  45. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +26 -26
  46. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
  47. data/spec/reek/report/location_formatter_spec.rb +3 -3
  48. data/spec/reek/smell_detectors/base_detector_spec.rb +3 -3
  49. data/spec/reek/smell_detectors/utility_function_spec.rb +16 -0
  50. data/spec/reek/smell_warning_spec.rb +12 -12
  51. data/spec/reek/spec/should_reek_of_spec.rb +0 -1
  52. data/spec/reek/spec/should_reek_only_of_spec.rb +6 -6
  53. data/spec/reek/spec/smell_matcher_spec.rb +1 -1
  54. data/spec/spec_helper.rb +18 -5
  55. data/tasks/configuration.rake +1 -2
  56. metadata +21 -27
  57. data/.travis.yml +0 -36
  58. data/spec/factories/factories.rb +0 -37
@@ -14,6 +14,8 @@ module Reek
14
14
  #
15
15
  # See {file:docs/Boolean-Parameter.md} for details.
16
16
  class BooleanParameter < BaseDetector
17
+ BOOLEAN_VALUES = [:true, :false].freeze
18
+
17
19
  #
18
20
  # Checks whether the given method has any Boolean parameters.
19
21
  #
@@ -21,7 +23,7 @@ module Reek
21
23
  #
22
24
  def sniff
23
25
  context.default_assignments.select do |_parameter, value|
24
- [:true, :false].include?(value.type)
26
+ BOOLEAN_VALUES.include?(value.type)
25
27
  end.map do |parameter, _value|
26
28
  smell_warning(
27
29
  lines: [source_line],
@@ -74,7 +74,7 @@ module Reek
74
74
  end
75
75
 
76
76
  def uncommunicative_variable_name?(name)
77
- sanitized_name = name.to_s.gsub(/^[@\*\&]*/, '')
77
+ sanitized_name = name.to_s.gsub(/^[@*&]*/, '')
78
78
  !acceptable_name?(sanitized_name)
79
79
  end
80
80
 
@@ -31,8 +31,7 @@ module Reek
31
31
  # public API.
32
32
  #
33
33
  # @quality :reek:LongParameterList { max_params: 6 }
34
- def initialize(smell_type, context: '', lines:, message:,
35
- source:, parameters: {})
34
+ def initialize(smell_type, lines:, message:, source:, context: '', parameters: {})
36
35
  @smell_type = smell_type
37
36
  @source = source
38
37
  @context = context.to_s
@@ -33,23 +33,26 @@ module Reek
33
33
 
34
34
  attr_reader :configuration, :paths, :options
35
35
 
36
- # @quality :reek:TooManyStatements { max_statements: 7 }
37
- # @quality :reek:NestedIterators { max_allowed_nesting: 2 }
38
36
  def source_paths
39
37
  paths.each_with_object([]) do |given_path, relevant_paths|
40
- unless given_path.exist?
38
+ if given_path.exist?
39
+ relevant_paths.concat source_files_from_path(given_path)
40
+ else
41
41
  print_no_such_file_error(given_path)
42
- next
43
42
  end
43
+ end
44
+ end
44
45
 
45
- given_path.find do |path|
46
- if path.directory?
47
- ignore_path?(path) ? Find.prune : next
48
- elsif ruby_file?(path)
49
- relevant_paths << path unless ignore_file?(path)
50
- end
46
+ def source_files_from_path(given_path)
47
+ relevant_paths = []
48
+ given_path.find do |path|
49
+ if path.directory?
50
+ Find.prune if ignore_path?(path)
51
+ elsif ruby_file?(path)
52
+ relevant_paths << path unless ignore_file?(path)
51
53
  end
52
54
  end
55
+ relevant_paths
53
56
  end
54
57
 
55
58
  def ignore_file?(path)
@@ -43,8 +43,9 @@ module Reek
43
43
  raise ArgumentError, "The attribute '#{extra_keys.first}' is not available for comparison"
44
44
  end
45
45
 
46
+ # :reek:FeatureEnvy
46
47
  def common_parameters_equal?(other_parameters)
47
- smell_warning.parameters.slice(*other_parameters.keys) == other_parameters
48
+ smell_warning.parameters.values_at(*other_parameters.keys) == other_parameters.values
48
49
  end
49
50
 
50
51
  def common_attributes_equal?(attributes)
data/lib/reek/version.rb CHANGED
@@ -8,6 +8,6 @@ module Reek
8
8
  # @public
9
9
  module Version
10
10
  # @public
11
- STRING = '6.0.0'
11
+ STRING = '6.0.3'
12
12
  end
13
13
  end
data/lib/reek.rb CHANGED
@@ -8,6 +8,7 @@ require_relative 'reek/examiner'
8
8
  require_relative 'reek/report'
9
9
 
10
10
  module Reek
11
+ DEFAULT_SMELL_CONFIGURATION = File.join(__dir__, '../docs/defaults.reek.yml').freeze
11
12
  DEFAULT_CONFIGURATION_FILE_NAME = '.reek.yml'
12
13
  DETECTORS_KEY = 'detectors'
13
14
  EXCLUDE_PATHS_KEY = 'exclude_paths'
data/reek.gemspec CHANGED
@@ -19,8 +19,16 @@ Gem::Specification.new do |s|
19
19
  s.required_ruby_version = '>= 2.4.0'
20
20
  s.summary = 'Code smell detector for Ruby'
21
21
 
22
+ s.metadata = {
23
+ 'homepage_uri' => 'https://github.com/troessner/reek',
24
+ 'source_code_uri' => 'https://github.com/troessner/reek',
25
+ 'bug_tracker_uri' => 'https://github.com/troessner/reek/issues',
26
+ 'changelog_uri' => 'https://github.com/troessner/reek/CHANGELOG.md',
27
+ 'documentation_uri' => 'https://www.rubydoc.info/gems/reek'
28
+ }
29
+
22
30
  s.add_runtime_dependency 'kwalify', '~> 0.7.0'
23
- s.add_runtime_dependency 'parser', '< 2.8', '>= 2.5.0.0', '!= 2.5.1.1'
24
- s.add_runtime_dependency 'psych', '~> 3.1.0'
31
+ s.add_runtime_dependency 'parser', '~> 3.0.0'
32
+ s.add_runtime_dependency 'psych', '~> 3.1'
25
33
  s.add_runtime_dependency 'rainbow', '>= 2.0', '< 4.0'
26
34
  end
@@ -6,10 +6,8 @@ RSpec.describe 'Runtime speed' do
6
6
 
7
7
  it 'runs on our smelly sources in less than 5 seconds' do
8
8
  expect do
9
- source_directory.each_entry do |entry|
10
- next if %w(. ..).include?(entry.to_s)
11
-
12
- examiner = Reek::Examiner.new entry.to_path
9
+ Dir[source_directory.join('**/*.rb')].each do |entry|
10
+ examiner = Reek::Examiner.new Pathname.new(entry)
13
11
  examiner.smells.size
14
12
  end
15
13
  end.to perform_under(5).sec
@@ -4,6 +4,7 @@ require 'kramdown'
4
4
  RSpec.describe 'Documentation' do
5
5
  root = File.expand_path('../..', __dir__)
6
6
  files = Dir.glob(File.join(root, '*.md')) + Dir.glob(File.join(root, 'docs', '*.md'))
7
+ code_types = [:codeblock, :codespan]
7
8
 
8
9
  files.each do |file|
9
10
  describe "from #{file}" do
@@ -13,7 +14,7 @@ RSpec.describe 'Documentation' do
13
14
 
14
15
  blocks.each do |block|
15
16
  # Only consider code blocks with language 'ruby'.
16
- next unless [:codeblock, :codespan].include?(block.type)
17
+ next unless code_types.include?(block.type)
17
18
  next unless block.attr['class'] == 'language-ruby'
18
19
 
19
20
  it "has a valid sample at #{block.options[:location] + 1}" do
@@ -3,7 +3,7 @@ require_lib 'reek/code_comment'
3
3
 
4
4
  RSpec.describe Reek::CodeComment do
5
5
  context 'with an empty comment' do
6
- let(:comment) { build(:code_comment, comment: '') }
6
+ let(:comment) { build_code_comment(comment: '') }
7
7
 
8
8
  it 'is not descriptive' do
9
9
  expect(comment).not_to be_descriptive
@@ -16,22 +16,22 @@ RSpec.describe Reek::CodeComment do
16
16
 
17
17
  describe '#descriptive' do
18
18
  it 'rejects an empty comment' do
19
- comment = build(:code_comment, comment: '#')
19
+ comment = build_code_comment(comment: '#')
20
20
  expect(comment).not_to be_descriptive
21
21
  end
22
22
 
23
23
  it 'rejects a 1-word comment' do
24
- comment = build(:code_comment, comment: "# alpha\n# ")
24
+ comment = build_code_comment(comment: "# alpha\n# ")
25
25
  expect(comment).not_to be_descriptive
26
26
  end
27
27
 
28
28
  it 'accepts a 2-word comment' do
29
- comment = build(:code_comment, comment: '# alpha bravo ')
29
+ comment = build_code_comment(comment: '# alpha bravo ')
30
30
  expect(comment).to be_descriptive
31
31
  end
32
32
 
33
33
  it 'accepts a multi-word comment' do
34
- comment = build(:code_comment, comment: "# alpha bravo \n# charlie \n # delta ")
34
+ comment = build_code_comment(comment: "# alpha bravo \n# charlie \n # delta ")
35
35
  expect(comment).to be_descriptive
36
36
  end
37
37
  end
@@ -39,8 +39,7 @@ RSpec.describe Reek::CodeComment do
39
39
  describe 'good comment config' do
40
40
  it 'parses hashed options' do
41
41
  comment = '# :reek:DuplicateMethodCall { max_calls: 3 }'
42
- config = build(:code_comment,
43
- comment: comment).config
42
+ config = build_code_comment(comment: comment).config
44
43
 
45
44
  expect(config).to include('DuplicateMethodCall')
46
45
  expect(config['DuplicateMethodCall']).to have_key 'max_calls'
@@ -52,7 +51,7 @@ RSpec.describe Reek::CodeComment do
52
51
  # :reek:DuplicateMethodCall { max_calls: 3 }
53
52
  # :reek:NestedIterators { enabled: true }
54
53
  RUBY
55
- config = build(:code_comment, comment: comment).config
54
+ config = build_code_comment(comment: comment).config
56
55
 
57
56
  expect(config).to include('DuplicateMethodCall', 'NestedIterators')
58
57
  expect(config['DuplicateMethodCall']['max_calls']).to eq 3
@@ -63,7 +62,7 @@ RSpec.describe Reek::CodeComment do
63
62
  comment = <<-RUBY
64
63
  #:reek:DuplicateMethodCall { max_calls: 3 } and :reek:NestedIterators { enabled: true }
65
64
  RUBY
66
- config = build(:code_comment, comment: comment).config
65
+ config = build_code_comment(comment: comment).config
67
66
 
68
67
  expect(config).to include('DuplicateMethodCall', 'NestedIterators')
69
68
  expect(config['DuplicateMethodCall']['max_calls']).to eq 3
@@ -73,7 +72,7 @@ RSpec.describe Reek::CodeComment do
73
72
 
74
73
  it 'parses multiple unhashed options on the same line' do
75
74
  comment = '# :reek:DuplicateMethodCall and :reek:NestedIterators'
76
- config = build(:code_comment, comment: comment).config
75
+ config = build_code_comment(comment: comment).config
77
76
 
78
77
  expect(config).to include('DuplicateMethodCall', 'NestedIterators')
79
78
  expect(config['DuplicateMethodCall']).to include('enabled')
@@ -84,7 +83,7 @@ RSpec.describe Reek::CodeComment do
84
83
 
85
84
  it 'disables the smell if no options are specifed' do
86
85
  comment = '# :reek:DuplicateMethodCall'
87
- config = build(:code_comment, comment: comment).config
86
+ config = build_code_comment(comment: comment).config
88
87
 
89
88
  expect(config).to include('DuplicateMethodCall')
90
89
  expect(config['DuplicateMethodCall']).to include('enabled')
@@ -93,14 +92,13 @@ RSpec.describe Reek::CodeComment do
93
92
 
94
93
  it 'does not disable the smell if options are specifed' do
95
94
  comment = '# :reek:DuplicateMethodCall { max_calls: 3 }'
96
- config = build(:code_comment, comment: comment).config
95
+ config = build_code_comment(comment: comment).config
97
96
 
98
97
  expect(config['DuplicateMethodCall']).not_to include('enabled')
99
98
  end
100
99
 
101
100
  it 'ignores smells after a space' do
102
- config = build(:code_comment,
103
- comment: '# :reek: DuplicateMethodCall').config
101
+ config = build_code_comment(comment: '# :reek: DuplicateMethodCall').config
104
102
  expect(config).not_to include('DuplicateMethodCall')
105
103
  end
106
104
 
@@ -111,7 +109,7 @@ RSpec.describe Reek::CodeComment do
111
109
  # :reek:NestedIterators { enabled: true }
112
110
  # comment
113
111
  RUBY
114
- comment = build(:code_comment, comment: original_comment)
112
+ comment = build_code_comment(comment: original_comment)
115
113
 
116
114
  expect(comment.send(:sanitized_comment)).to eq('Actual comment')
117
115
  end
@@ -122,8 +120,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
122
120
  context 'when the comment contains an unknown detector name' do
123
121
  it 'raises BadDetectorInCommentError' do
124
122
  expect do
125
- build(:code_comment,
126
- comment: '# :reek:DoesNotExist')
123
+ build_code_comment(comment: '# :reek:DoesNotExist')
127
124
  end.to raise_error(Reek::Errors::BadDetectorInCommentError)
128
125
  end
129
126
  end
@@ -132,7 +129,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
132
129
  it 'raises GarbageDetectorConfigurationInCommentError' do
133
130
  expect do
134
131
  comment = '# :reek:UncommunicativeMethodName { thats: a: bad: config }'
135
- build(:code_comment, comment: comment)
132
+ build_code_comment(comment: comment)
136
133
  end.to raise_error(Reek::Errors::GarbageDetectorConfigurationInCommentError)
137
134
  end
138
135
  end
@@ -140,7 +137,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
140
137
  context 'when the legacy comment format was used' do
141
138
  it 'raises LegacyCommentSeparatorError' do
142
139
  comment = '# :reek:DuplicateMethodCall:'
143
- expect { build(:code_comment, comment: comment) }.
140
+ expect { build_code_comment(comment: comment) }.
144
141
  to raise_error Reek::Errors::LegacyCommentSeparatorError
145
142
  end
146
143
  end
@@ -151,7 +148,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
151
148
  expect do
152
149
  # exclude -> exlude and enabled -> nabled
153
150
  comment = '# :reek:UncommunicativeMethodName { exlude: alfa, nabled: true }'
154
- build(:code_comment, comment: comment)
151
+ build_code_comment(comment: comment)
155
152
  end.to raise_error(Reek::Errors::BadDetectorConfigurationKeyInCommentError)
156
153
  end
157
154
  end
@@ -160,7 +157,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
160
157
  it 'does not raise' do
161
158
  expect do
162
159
  comment = '# :reek:UncommunicativeMethodName { exclude: alfa, enabled: true }'
163
- build(:code_comment, comment: comment)
160
+ build_code_comment(comment: comment)
164
161
  end.not_to raise_error
165
162
  end
166
163
  end
@@ -170,7 +167,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
170
167
  expect do
171
168
  # max_copies -> mx_copies and min_clump_size -> mn_clump_size
172
169
  comment = '# :reek:DataClump { mx_copies: 4, mn_clump_size: 3 }'
173
- build(:code_comment, comment: comment)
170
+ build_code_comment(comment: comment)
174
171
  end.to raise_error(Reek::Errors::BadDetectorConfigurationKeyInCommentError)
175
172
  end
176
173
  end
@@ -179,7 +176,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
179
176
  it 'does not raise' do
180
177
  expect do
181
178
  comment = '# :reek:DataClump { max_copies: 4, min_clump_size: 3 }'
182
- build(:code_comment, comment: comment)
179
+ build_code_comment(comment: comment)
183
180
  end.not_to raise_error
184
181
  end
185
182
  end
@@ -89,6 +89,12 @@ RSpec.describe Reek::Configuration::DirectoryDirectives do
89
89
  expect(hit.to_s).to eq('bar/**/.spec/*')
90
90
  end
91
91
 
92
+ it 'returns the corresponding directory when source_base_dir is an absolute_path' do
93
+ source_base_dir = Pathname.new('foo/bar').expand_path
94
+ hit = directives.send :best_match_for, source_base_dir
95
+ expect(hit.to_s).to eq('foo/bar')
96
+ end
97
+
92
98
  it 'does not match an arbitrary directory when source_base_dir contains a character that could match the .' do
93
99
  source_base_dir = 'bar/something/aspec/direct'
94
100
  hit = directives.send :best_match_for, source_base_dir
@@ -5,12 +5,21 @@ require_lib 'reek/configuration/excluded_paths'
5
5
  RSpec.describe Reek::Configuration::ExcludedPaths do
6
6
  describe '#add' do
7
7
  let(:exclusions) { [].extend(described_class) }
8
- let(:paths) { ['smelly/sources'] }
9
- let(:expected_exclude_paths) { [Pathname('smelly/sources')] }
8
+ let(:paths) do
9
+ %w(samples/directory_does_not_exist/
10
+ samples/source_with_non_ruby_files/
11
+ samples/**/ignore_me*)
12
+ end
13
+
14
+ let(:expected_exclude_paths) do
15
+ [Pathname('samples/source_with_non_ruby_files/'),
16
+ Pathname('samples/source_with_exclude_paths/ignore_me'),
17
+ Pathname('samples/source_with_exclude_paths/nested/ignore_me_as_well')]
18
+ end
10
19
 
11
20
  it 'adds the given paths as Pathname' do
12
21
  exclusions.add(paths)
13
- expect(exclusions).to eq expected_exclude_paths
22
+ expect(exclusions).to match_array expected_exclude_paths
14
23
  end
15
24
  end
16
25
  end
@@ -3,9 +3,7 @@ require_lib 'reek/report/code_climate/code_climate_configuration'
3
3
 
4
4
  RSpec.describe Reek::Report::CodeClimateConfiguration do
5
5
  yml = described_class.load
6
- smell_types = Reek::SmellDetectors::BaseDetector.descendants.map do |descendant|
7
- descendant.name.demodulize
8
- end
6
+ smell_types = Reek::SmellDetectors::BaseDetector.descendants.map(&:smell_type)
9
7
 
10
8
  smell_types.each do |name|
11
9
  config = yml.fetch(name)
@@ -8,12 +8,12 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
8
8
  context 'when fingerprinting a warning with no parameters' do
9
9
  let(:expected_fingerprint) { 'e68badd29db51c92363a7c6a2438d722' }
10
10
  let(:warning) do
11
- build(:smell_warning,
12
- smell_type: 'UtilityFunction',
13
- context: 'alfa',
14
- message: "doesn't depend on instance state (maybe move it to another class?)",
15
- lines: lines,
16
- source: 'a/ruby/source/file.rb')
11
+ Reek::SmellWarning.new(
12
+ 'UtilityFunction',
13
+ context: 'alfa',
14
+ message: "doesn't depend on instance state (maybe move it to another class?)",
15
+ lines: lines,
16
+ source: 'a/ruby/source/file.rb')
17
17
  end
18
18
 
19
19
  context 'with code at a specific location' do
@@ -35,12 +35,12 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
35
35
 
36
36
  context 'when the fingerprint should not be computed' do
37
37
  let(:warning) do
38
- build(:smell_warning,
39
- smell_type: 'ManualDispatch',
40
- context: 'Alfa#bravo',
41
- message: 'manually dispatches method call',
42
- lines: [4],
43
- source: 'a/ruby/source/file.rb')
38
+ Reek::SmellWarning.new(
39
+ 'ManualDispatch',
40
+ context: 'Alfa#bravo',
41
+ message: 'manually dispatches method call',
42
+ lines: [4],
43
+ source: 'a/ruby/source/file.rb')
44
44
  end
45
45
 
46
46
  it 'returns nil' do
@@ -50,13 +50,13 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
50
50
 
51
51
  context 'when the smell warning has only identifying parameters' do
52
52
  let(:warning) do
53
- build(:smell_warning,
54
- smell_type: 'ClassVariable',
55
- context: 'Alfa',
56
- message: "declares the class variable '@@#{name}'",
57
- lines: [4],
58
- parameters: { name: "@@#{name}" },
59
- source: 'a/ruby/source/file.rb')
53
+ Reek::SmellWarning.new(
54
+ 'ClassVariable',
55
+ context: 'Alfa',
56
+ message: "declares the class variable '@@#{name}'",
57
+ lines: [4],
58
+ parameters: { name: "@@#{name}" },
59
+ source: 'a/ruby/source/file.rb')
60
60
  end
61
61
 
62
62
  context 'when the name is one thing' do
@@ -80,13 +80,13 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
80
80
 
81
81
  context 'when the smell warning has identifying and non-identifying parameters' do
82
82
  let(:warning) do
83
- build(:smell_warning,
84
- smell_type: 'DuplicateMethodCall',
85
- context: "Alfa##{name}",
86
- message: "calls '#{name}' #{count} times",
87
- lines: lines,
88
- parameters: { name: "@@#{name}", count: count },
89
- source: 'a/ruby/source/file.rb')
83
+ Reek::SmellWarning.new(
84
+ 'DuplicateMethodCall',
85
+ context: "Alfa##{name}",
86
+ message: "calls '#{name}' #{count} times",
87
+ lines: lines,
88
+ parameters: { name: "@@#{name}", count: count },
89
+ source: 'a/ruby/source/file.rb')
90
90
  end
91
91
 
92
92
  context 'when the parameters are provided' do
@@ -4,12 +4,12 @@ require_lib 'reek/report/code_climate/code_climate_formatter'
4
4
  RSpec.describe Reek::Report::CodeClimateFormatter do
5
5
  describe '#render' do
6
6
  let(:warning) do
7
- build(:smell_warning,
8
- smell_type: 'UtilityFunction',
9
- context: 'context foo',
10
- message: 'message bar',
11
- lines: [1, 2],
12
- source: 'a/ruby/source/file.rb')
7
+ Reek::SmellWarning.new(
8
+ 'UtilityFunction',
9
+ context: 'context foo',
10
+ message: 'message bar',
11
+ lines: [1, 2],
12
+ source: 'a/ruby/source/file.rb')
13
13
  end
14
14
  let(:rendered) { described_class.new(warning).render }
15
15
  let(:json) { JSON.parse rendered.chop }
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
2
2
  require_lib 'reek/report/location_formatter'
3
3
 
4
4
  RSpec.describe Reek::Report::BlankLocationFormatter do
5
- let(:warning) { build(:smell_warning, lines: [11, 9, 250, 100]) }
5
+ let(:warning) { build_smell_warning(lines: [11, 9, 250, 100]) }
6
6
 
7
7
  describe '.format' do
8
8
  it 'returns a blank String regardless of the warning' do
@@ -12,7 +12,7 @@ RSpec.describe Reek::Report::BlankLocationFormatter do
12
12
  end
13
13
 
14
14
  RSpec.describe Reek::Report::DefaultLocationFormatter do
15
- let(:warning) { build(:smell_warning, lines: [11, 9, 250, 100]) }
15
+ let(:warning) { build_smell_warning(lines: [11, 9, 250, 100]) }
16
16
 
17
17
  describe '.format' do
18
18
  it 'returns a prefix with sorted line numbers' do
@@ -22,7 +22,7 @@ RSpec.describe Reek::Report::DefaultLocationFormatter do
22
22
  end
23
23
 
24
24
  RSpec.describe Reek::Report::SingleLineLocationFormatter do
25
- let(:warning) { build(:smell_warning, lines: [11, 9, 250, 100]) }
25
+ let(:warning) { build_smell_warning(lines: [11, 9, 250, 100]) }
26
26
 
27
27
  describe '.format' do
28
28
  it 'returns the first line where the smell was found' do
@@ -5,13 +5,13 @@ require_lib 'reek/smell_detectors/duplicate_method_call'
5
5
  RSpec.describe Reek::SmellDetectors::BaseDetector do
6
6
  describe '.todo_configuration_for' do
7
7
  it 'returns exclusion configuration for the given smells' do
8
- smell = create(:smell_warning, smell_type: 'Foo', context: 'Foo#bar')
8
+ smell = build_smell_warning(smell_type: 'Foo', context: 'Foo#bar')
9
9
  result = described_class.todo_configuration_for([smell])
10
10
  expect(result).to eq('BaseDetector' => { 'exclude' => ['Foo#bar'] })
11
11
  end
12
12
 
13
13
  it 'merges identical contexts' do
14
- smell = create(:smell_warning, smell_type: 'Foo', context: 'Foo#bar')
14
+ smell = build_smell_warning(smell_type: 'Foo', context: 'Foo#bar')
15
15
  result = described_class.todo_configuration_for([smell, smell])
16
16
  expect(result).to eq('BaseDetector' => { 'exclude' => ['Foo#bar'] })
17
17
  end
@@ -20,7 +20,7 @@ RSpec.describe Reek::SmellDetectors::BaseDetector do
20
20
  let(:subclass) { Reek::SmellDetectors::TooManyStatements }
21
21
 
22
22
  it 'includes default exclusions' do
23
- smell = create(:smell_warning, smell_type: 'TooManyStatements', context: 'Foo#bar')
23
+ smell = build_smell_warning(smell_type: 'TooManyStatements', context: 'Foo#bar')
24
24
  result = subclass.todo_configuration_for([smell])
25
25
 
26
26
  aggregate_failures do
@@ -161,6 +161,22 @@ RSpec.describe Reek::SmellDetectors::UtilityFunction do
161
161
  end
162
162
  end
163
163
 
164
+ context 'when examining refinements' do
165
+ it 'reports on the refined class' do
166
+ src = <<-RUBY
167
+ module Alfa
168
+ refine Bravo do
169
+ def bravo(charlie)
170
+ charlie.delta.echo
171
+ end
172
+ end
173
+ end
174
+ RUBY
175
+
176
+ expect(src).to reek_of(:UtilityFunction, context: 'Bravo#bravo')
177
+ end
178
+ end
179
+
164
180
  describe 'method visibility' do
165
181
  it 'reports private methods' do
166
182
  src = <<-RUBY
@@ -24,23 +24,23 @@ RSpec.describe Reek::SmellWarning do
24
24
  end
25
25
 
26
26
  context 'when smells differ only by detector' do
27
- let(:first) { build(:smell_warning, smell_type: 'DuplicateMethodCall') }
28
- let(:second) { build(:smell_warning, smell_type: 'FeatureEnvy') }
27
+ let(:first) { build_smell_warning(smell_type: 'DuplicateMethodCall') }
28
+ let(:second) { build_smell_warning(smell_type: 'FeatureEnvy') }
29
29
 
30
30
  it_behaves_like 'first sorts ahead of second'
31
31
  end
32
32
 
33
33
  context 'when smells differ only by lines' do
34
- let(:first) { build(:smell_warning, smell_type: 'FeatureEnvy', lines: [2]) }
35
- let(:second) { build(:smell_warning, smell_type: 'FeatureEnvy', lines: [3]) }
34
+ let(:first) { build_smell_warning(smell_type: 'FeatureEnvy', lines: [2]) }
35
+ let(:second) { build_smell_warning(smell_type: 'FeatureEnvy', lines: [3]) }
36
36
 
37
37
  it_behaves_like 'first sorts ahead of second'
38
38
  end
39
39
 
40
40
  context 'when smells differ only by context' do
41
- let(:first) { build(:smell_warning, smell_type: 'DuplicateMethodCall', context: 'first') }
41
+ let(:first) { build_smell_warning(smell_type: 'DuplicateMethodCall', context: 'first') }
42
42
  let(:second) do
43
- build(:smell_warning, smell_type: 'DuplicateMethodCall', context: 'second')
43
+ build_smell_warning(smell_type: 'DuplicateMethodCall', context: 'second')
44
44
  end
45
45
 
46
46
  it_behaves_like 'first sorts ahead of second'
@@ -48,11 +48,11 @@ RSpec.describe Reek::SmellWarning do
48
48
 
49
49
  context 'when smells differ only by message' do
50
50
  let(:first) do
51
- build(:smell_warning, smell_type: 'DuplicateMethodCall',
51
+ build_smell_warning(smell_type: 'DuplicateMethodCall',
52
52
  context: 'ctx', message: 'first message')
53
53
  end
54
54
  let(:second) do
55
- build(:smell_warning, smell_type: 'DuplicateMethodCall',
55
+ build_smell_warning(smell_type: 'DuplicateMethodCall',
56
56
  context: 'ctx', message: 'second message')
57
57
  end
58
58
 
@@ -61,10 +61,10 @@ RSpec.describe Reek::SmellWarning do
61
61
 
62
62
  context 'when smells differ by name and message' do
63
63
  let(:first) do
64
- build(:smell_warning, smell_type: 'FeatureEnvy', message: 'second message')
64
+ build_smell_warning(smell_type: 'FeatureEnvy', message: 'second message')
65
65
  end
66
66
  let(:second) do
67
- build(:smell_warning, smell_type: 'UtilityFunction', message: 'first message')
67
+ build_smell_warning(smell_type: 'UtilityFunction', message: 'first message')
68
68
  end
69
69
 
70
70
  it_behaves_like 'first sorts ahead of second'
@@ -72,13 +72,13 @@ RSpec.describe Reek::SmellWarning do
72
72
 
73
73
  context 'when smells differ everywhere' do
74
74
  let(:first) do
75
- build(:smell_warning, smell_type: 'DuplicateMethodCall',
75
+ build_smell_warning(smell_type: 'DuplicateMethodCall',
76
76
  context: 'Dirty#a',
77
77
  message: 'calls @s.title twice')
78
78
  end
79
79
 
80
80
  let(:second) do
81
- build(:smell_warning, smell_type: 'UncommunicativeVariableName',
81
+ build_smell_warning(smell_type: 'UncommunicativeVariableName',
82
82
  context: 'Dirty',
83
83
  message: "has the variable name '@s'")
84
84
  end
@@ -1,7 +1,6 @@
1
1
  require 'pathname'
2
2
  require_relative '../../spec_helper'
3
3
  require_lib 'reek/spec'
4
- require 'active_support/core_ext/hash/except'
5
4
 
6
5
  RSpec.describe Reek::Spec::ShouldReekOf do
7
6
  describe 'smell type selection' do