reek 3.1 → 3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -2
  3. data/{CHANGELOG → CHANGELOG.md} +150 -123
  4. data/README.md +61 -21
  5. data/Rakefile +2 -1
  6. data/bin/reek +1 -0
  7. data/config/defaults.reek +2 -2
  8. data/docs/Attribute.md +9 -13
  9. data/docs/Basic-Smell-Options.md +2 -2
  10. data/docs/Command-Line-Options.md +2 -2
  11. data/docs/Too-Many-Instance-Variables.md +1 -1
  12. data/features/samples.feature +22 -31
  13. data/features/step_definitions/sample_file_steps.rb +2 -2
  14. data/features/support/env.rb +1 -0
  15. data/lib/reek.rb +1 -0
  16. data/lib/reek/ast/ast_node_class_map.rb +5 -1
  17. data/lib/reek/ast/node.rb +4 -2
  18. data/lib/reek/ast/object_refs.rb +9 -5
  19. data/lib/reek/ast/reference_collector.rb +4 -2
  20. data/lib/reek/cli/application.rb +12 -9
  21. data/lib/reek/cli/command.rb +4 -0
  22. data/lib/reek/cli/input.rb +4 -4
  23. data/lib/reek/cli/option_interpreter.rb +11 -7
  24. data/lib/reek/cli/options.rb +42 -40
  25. data/lib/reek/cli/reek_command.rb +3 -3
  26. data/lib/reek/cli/warning_collector.rb +7 -3
  27. data/lib/reek/code_comment.rb +5 -1
  28. data/lib/reek/configuration/app_configuration.rb +4 -4
  29. data/lib/reek/context/code_context.rb +19 -17
  30. data/lib/reek/examiner.rb +8 -6
  31. data/lib/reek/rake/task.rb +13 -22
  32. data/lib/reek/report/formatter.rb +5 -1
  33. data/lib/reek/report/report.rb +46 -44
  34. data/lib/reek/smells/attribute.rb +42 -24
  35. data/lib/reek/smells/control_parameter.rb +21 -13
  36. data/lib/reek/smells/data_clump.rb +17 -9
  37. data/lib/reek/smells/duplicate_method_call.rb +12 -6
  38. data/lib/reek/smells/long_parameter_list.rb +2 -2
  39. data/lib/reek/smells/long_yield_list.rb +4 -4
  40. data/lib/reek/smells/nested_iterators.rb +4 -2
  41. data/lib/reek/smells/nil_check.rb +6 -2
  42. data/lib/reek/smells/repeated_conditional.rb +2 -2
  43. data/lib/reek/smells/smell_configuration.rb +15 -7
  44. data/lib/reek/smells/smell_detector.rb +23 -10
  45. data/lib/reek/smells/smell_repository.rb +9 -16
  46. data/lib/reek/smells/smell_warning.rb +6 -6
  47. data/lib/reek/smells/too_many_instance_variables.rb +4 -4
  48. data/lib/reek/smells/too_many_methods.rb +2 -2
  49. data/lib/reek/smells/too_many_statements.rb +4 -4
  50. data/lib/reek/smells/uncommunicative_method_name.rb +5 -5
  51. data/lib/reek/smells/uncommunicative_module_name.rb +5 -5
  52. data/lib/reek/smells/uncommunicative_parameter_name.rb +8 -4
  53. data/lib/reek/smells/uncommunicative_variable_name.rb +8 -4
  54. data/lib/reek/source/source_code.rb +6 -2
  55. data/lib/reek/source/source_locator.rb +4 -4
  56. data/lib/reek/spec/should_reek.rb +9 -4
  57. data/lib/reek/spec/should_reek_of.rb +8 -5
  58. data/lib/reek/spec/should_reek_only_of.rb +12 -8
  59. data/lib/reek/tree_dresser.rb +6 -2
  60. data/lib/reek/tree_walker.rb +28 -22
  61. data/lib/reek/version.rb +1 -1
  62. data/reek.gemspec +6 -5
  63. data/spec/gem/yard_spec.rb +6 -9
  64. data/spec/reek/code_comment_spec.rb +1 -1
  65. data/spec/reek/report/xml_report_spec.rb +11 -21
  66. data/spec/reek/smells/attribute_spec.rb +73 -57
  67. data/spec/reek/smells/too_many_instance_variables_spec.rb +26 -12
  68. data/spec/reek/source/source_locator_spec.rb +2 -2
  69. data/spec/samples/checkstyle.xml +12 -1
  70. data/spec/spec_helper.rb +1 -0
  71. metadata +20 -7
  72. data/spec/samples/unusual_syntax.rb +0 -21
@@ -1,14 +1,11 @@
1
+ require 'open3'
1
2
  require_relative '../spec_helper'
2
- require 'tempfile'
3
3
 
4
4
  RSpec.describe 'yardoc' do
5
- before :each do
6
- stderr_file = Tempfile.new('yardoc')
7
- stderr_file.close
8
- @stdout = `yardoc 2> #{stderr_file.path}`
9
- @stderr = IO.read(stderr_file.path)
10
- end
11
- it 'raises no warnings' do
12
- expect(@stderr).to eq('')
5
+ it 'executes successfully with no warnings' do
6
+ stdout, stderr, status = Open3.capture3('yardoc')
7
+ expect(stdout).to_not include('[warn]')
8
+ expect(stderr).to be_empty
9
+ expect(status).to be_success
13
10
  end
14
11
  end
@@ -38,7 +38,7 @@ RSpec.describe Reek::CodeComment do
38
38
  expect(config['Duplication']).to include('enabled')
39
39
  expect(config['Duplication']['enabled']).to be_falsey
40
40
  end
41
- it 'parses hashed options with ruby names' do
41
+ it 'parses hashed options with Ruby names' do
42
42
  comment = '# :reek:nested_iterators: { enabled: true }'
43
43
  config = described_class.new(comment).config
44
44
  expect(config).to include('NestedIterators')
@@ -1,35 +1,25 @@
1
- require 'pathname'
2
1
  require_relative '../../spec_helper'
3
2
  require_relative '../../../lib/reek/examiner'
4
3
  require_relative '../../../lib/reek/report/report'
5
- require_relative '../../../lib/reek/report/formatter'
6
4
 
7
5
  RSpec.describe Reek::Report::XMLReport do
8
- let(:instance) { Reek::Report::XMLReport.new }
6
+ let(:xml_report) { Reek::Report::XMLReport.new }
9
7
 
10
8
  context 'empty source' do
11
- let(:examiner) { Reek::Examiner.new('') }
12
-
13
- before do
14
- instance.add_examiner examiner
15
- end
16
-
17
- it 'prints empty checkstyle xml' do
18
- expect { instance.show }.to output("<?xml version='1.0'?>\n<checkstyle/>\n").to_stdout
9
+ it 'prints empty checkstyle XML' do
10
+ xml_report.add_examiner Reek::Examiner.new('')
11
+ xml = "<?xml version='1.0'?>\n<checkstyle/>\n"
12
+ expect { xml_report.show }.to output(xml).to_stdout
19
13
  end
20
14
  end
21
15
 
22
16
  context 'source with voliations' do
23
- let(:examiner) { Reek::Examiner.new('def simple(a) a[0] end') }
24
-
25
- before do
26
- allow(File).to receive(:realpath).and_return('/some/path')
27
- instance.add_examiner examiner
28
- end
29
-
30
- it 'prints non-empty checkstyle xml' do
31
- sample_path = SAMPLES_PATH.join('checkstyle.xml')
32
- expect { instance.show }.to output(sample_path.read).to_stdout
17
+ it 'prints non-empty checkstyle XML' do
18
+ path = SAMPLES_PATH.join('two_smelly_files/dirty_one.rb')
19
+ xml_report.add_examiner Reek::Examiner.new(path)
20
+ xml = SAMPLES_PATH.join('checkstyle.xml').read
21
+ xml = xml.gsub(path.to_s, path.expand_path.to_s)
22
+ expect { xml_report.show }.to output(xml).to_stdout
33
23
  end
34
24
  end
35
25
  end
@@ -1,16 +1,8 @@
1
1
  require_relative '../../spec_helper'
2
2
  require_relative '../../../lib/reek/smells/attribute'
3
- require_relative '../../../lib/reek/smells/smell_configuration'
4
3
  require_relative 'smell_detector_shared'
5
4
 
6
5
  RSpec.describe Reek::Smells::Attribute do
7
- let(:config) do
8
- {
9
- Reek::Smells::Attribute => { Reek::Smells::SmellConfiguration::ENABLED_KEY => true }
10
- }
11
- end
12
- let(:configuration) { test_configuration_for(config) }
13
-
14
6
  before(:each) do
15
7
  @source_name = 'dummy_source'
16
8
  @detector = build(:smell_detector, smell_type: :Attribute, source: @source_name)
@@ -20,99 +12,123 @@ RSpec.describe Reek::Smells::Attribute do
20
12
 
21
13
  context 'with no attributes' do
22
14
  it 'records nothing' do
23
- expect('
15
+ src = <<-EOS
24
16
  class Klass
25
17
  end
26
- ').to_not reek_of(:Attribute, {}, configuration)
18
+ EOS
19
+ expect(src).to_not reek_of(:Attribute)
27
20
  end
28
21
  end
29
22
 
30
23
  context 'with attributes' do
31
- it 'records nothing' do
32
- expect('
24
+ it 'records nothing for attribute readers' do
25
+ src = <<-EOS
33
26
  class Klass
34
- attr :super_private, :super_private2
35
- private :super_private, :super_private2
36
- private
37
- attr :super_thing
38
- public
39
- attr :super_thing2
40
- private
41
- attr :super_thing2
27
+ attr :my_attr
28
+ attr_reader :my_attr2
42
29
  end
43
- ').to_not reek_of(:Attribute, {}, configuration)
30
+ EOS
31
+ expect(src).to_not reek_of(:Attribute)
44
32
  end
45
33
 
46
- it 'records attr attribute in a module' do
47
- expect('
34
+ it 'records writer attribute' do
35
+ src = <<-EOS
36
+ class Klass
37
+ attr_writer :my_attr
38
+ end
39
+ EOS
40
+ expect(src).to reek_of(:Attribute, name: 'my_attr')
41
+ end
42
+
43
+ it 'records attr_writer attribute in a module' do
44
+ src = <<-EOS
48
45
  module Mod
49
- attr :my_attr
46
+ attr_writer :my_attr
50
47
  end
51
- ').to reek_of(:Attribute, { name: 'my_attr' }, configuration)
48
+ EOS
49
+ expect(src).to reek_of(:Attribute, name: 'my_attr')
52
50
  end
53
51
 
54
- it 'records attr attribute' do
55
- expect('
52
+ it 'records accessor attribute' do
53
+ src = <<-EOS
56
54
  class Klass
57
- attr :my_attr
55
+ attr_accessor :my_attr
58
56
  end
59
- ').to reek_of(:Attribute, { name: 'my_attr' }, configuration)
57
+ EOS
58
+ expect(src).to reek_of(:Attribute, name: 'my_attr')
60
59
  end
61
60
 
62
- it 'records reader attribute' do
63
- expect('
61
+ it 'records attr defining a writer' do
62
+ src = <<-EOS
64
63
  class Klass
65
- attr_reader :my_attr
64
+ attr :my_attr, true
66
65
  end
67
- ').to reek_of(:Attribute, { name: 'my_attr' }, configuration)
66
+ EOS
67
+ expect(src).to reek_of(:Attribute, name: 'my_attr')
68
68
  end
69
69
 
70
- it 'records writer attribute' do
71
- expect('
70
+ it "doesn't record protected attributes" do
71
+ src = '
72
72
  class Klass
73
- attr_writer :my_attr
73
+ protected
74
+ attr_writer :attr1
75
+ attr_accessor :attr2
76
+ attr :attr3
77
+ attr :attr4, true
78
+ attr_reader :attr5
74
79
  end
75
- ').to reek_of(:Attribute, { name: 'my_attr' }, configuration)
80
+ '
81
+ expect(src).to_not reek_of(:Attribute)
76
82
  end
77
83
 
78
- it 'records accessor attribute' do
79
- expect('
84
+ it "doesn't record private attributes" do
85
+ src = '
80
86
  class Klass
81
- attr_accessor :my_attr
87
+ private
88
+ attr_writer :attr1
89
+ attr_accessor :attr2
90
+ attr :attr3
91
+ attr :attr4, true
92
+ attr_reader :attr5
82
93
  end
83
- ').to reek_of(:Attribute, { name: 'my_attr' }, configuration)
94
+ '
95
+ expect(src).to_not reek_of(:Attribute)
84
96
  end
85
97
 
86
- it 'records attr attribute after switching visbility' do
87
- expect('
98
+ it 'records attr_writer defined in public section' do
99
+ src = <<-EOS
88
100
  class Klass
89
101
  private
90
- attr :my_attr
91
- public :my_attr
92
- private :my_attr
93
- public :my_attr
102
+ public
103
+ attr_writer :my_attr
94
104
  end
95
- ').to reek_of(:Attribute, { name: 'my_attr' }, configuration)
105
+ EOS
106
+ expect(src).to reek_of(:Attribute, name: 'my_attr')
96
107
  end
97
108
 
98
- it "doesn't record protected attributes" do
99
- src = '
109
+ it 'records attr_writer after switching visbility to public' do
110
+ src = <<-EOS
100
111
  class Klass
101
- protected
102
- attr :iam_protected
112
+ private
113
+ attr_writer :my_attr
114
+ public :my_attr
103
115
  end
104
- '
105
- expect(src).to_not reek_of(:Attribute, { name: 'iam_protected' }, configuration)
116
+ EOS
117
+ expect(src).to reek_of(:Attribute, name: 'my_attr')
106
118
  end
107
119
 
108
- it "doesn't record private attributes" do
120
+ it 'resets visibility in new contexts' do
109
121
  src = '
110
122
  class Klass
111
123
  private
112
- attr :iam_private
124
+ attr_writer :attr1
125
+ end
126
+
127
+ class OtherKlass
128
+ attr_writer :attr1
113
129
  end
114
130
  '
115
- expect(src).to_not reek_of(:Attribute, { name: 'iam_private' }, configuration)
131
+ expect(src).to reek_of(:Attribute)
116
132
  end
117
133
  end
118
134
  end
@@ -10,12 +10,26 @@ RSpec.describe Reek::Smells::TooManyInstanceVariables do
10
10
 
11
11
  it_should_behave_like 'SmellDetector'
12
12
 
13
+ def default_max_ivars
14
+ Reek::Smells::TooManyInstanceVariables::DEFAULT_MAX_IVARS
15
+ end
16
+
17
+ def too_many_ivars
18
+ default_max_ivars + 1
19
+ end
20
+
21
+ def ivar_sequence(count: default_max_ivars, alphabet: ('a'..'z').to_a)
22
+ alphabet.first(count).map do |name|
23
+ "@#{name}=#{rand}"
24
+ end.join(',')
25
+ end
26
+
13
27
  context 'counting instance variables' do
14
- it 'should not report 9 ivars' do
28
+ it 'should not report for non-excessive ivars' do
15
29
  src = <<-EOS
16
30
  class Empty
17
31
  def ivars
18
- @aa=@ab=@ac=@ad=@ae=@af=@ag=@ah=@ai=4
32
+ #{ivar_sequence}
19
33
  end
20
34
  end
21
35
  EOS
@@ -26,36 +40,36 @@ RSpec.describe Reek::Smells::TooManyInstanceVariables do
26
40
  src = <<-EOS
27
41
  class Empty
28
42
  def ivars
29
- @aa=@ab=@ac=@ad=@ae=@af=@ag=@ah=@ai=4
30
- @aa=3
43
+ #{ivar_sequence}
44
+ #{ivar_sequence}
31
45
  end
32
46
  end
33
47
  EOS
34
48
  expect(src).not_to reek_of(:TooManyInstanceVariables)
35
49
  end
36
50
 
37
- it 'should report 10 ivars' do
51
+ it 'should report excessive ivars' do
38
52
  src = <<-EOS
39
53
  class Empty
40
54
  def ivars
41
- @aa=@ab=@ac=@ad=@ae=@af=@ag=@ah=@ai=@aj=4
55
+ #{ivar_sequence(count: too_many_ivars)}
42
56
  end
43
57
  end
44
58
  EOS
45
59
  expect(src).to reek_of(:TooManyInstanceVariables)
46
60
  end
47
61
 
48
- it 'should not report 10 ivars in 2 extensions' do
62
+ it 'should not report for ivars in 2 extensions' do
49
63
  src = <<-EOS
50
64
  class Full
51
65
  def ivars_a
52
- @aa=@ab=@ac=@ad=@ae
66
+ #{ivar_sequence}
53
67
  end
54
68
  end
55
69
 
56
70
  class Full
57
71
  def ivars_b
58
- @af=@ag=@ah=@ai=@aj
72
+ #{ivar_sequence}
59
73
  end
60
74
  end
61
75
  EOS
@@ -63,12 +77,12 @@ RSpec.describe Reek::Smells::TooManyInstanceVariables do
63
77
  end
64
78
  end
65
79
 
66
- it 'reports correctly when the class has 10 instance variables' do
80
+ it 'reports correctly for excessive instance variables' do
67
81
  src = <<-EOS
68
82
  # Comment
69
83
  class Empty
70
84
  def ivars
71
- @aa=@ab=@ac=@ad=@ae=@af=@ag=@ah=@ai=@aj=4
85
+ #{ivar_sequence(count: too_many_ivars)}
72
86
  end
73
87
  end
74
88
  EOS
@@ -77,7 +91,7 @@ RSpec.describe Reek::Smells::TooManyInstanceVariables do
77
91
  expect(@warning.source).to eq(@source_name)
78
92
  expect(@warning.smell_category).to eq(Reek::Smells::TooManyInstanceVariables.smell_category)
79
93
  expect(@warning.smell_type).to eq(Reek::Smells::TooManyInstanceVariables.smell_type)
80
- expect(@warning.parameters[:count]).to eq(10)
94
+ expect(@warning.parameters[:count]).to eq(too_many_ivars)
81
95
  expect(@warning.lines).to eq([2])
82
96
  end
83
97
  end
@@ -46,7 +46,7 @@ RSpec.describe Reek::Source::SourceLocator do
46
46
  end
47
47
  end
48
48
 
49
- context 'non-ruby paths' do
49
+ context 'non-Ruby paths' do
50
50
  let(:path) { SAMPLES_PATH.join('source_with_non_ruby_files') }
51
51
  let(:expected_sources) do
52
52
  [SAMPLES_PATH.join('source_with_non_ruby_files/uncommunicative_parameter_name.rb')]
@@ -58,7 +58,7 @@ RSpec.describe Reek::Source::SourceLocator do
58
58
  ]
59
59
  end
60
60
 
61
- it 'does only use ruby source paths' do
61
+ it 'does only use Ruby source paths' do
62
62
  sources = described_class.new([path]).sources
63
63
 
64
64
  expect(sources).not_to include(*paths_that_are_expected_to_be_ignored)
@@ -1,2 +1,13 @@
1
1
  <?xml version='1.0'?>
2
- <checkstyle><file name='/some/path'><error column='0' line='1' message='doesn&apos;t depend on instance state' severity='warning' source='UtilityFunction'/><error column='0' line='1' message='has the parameter name &apos;a&apos;' severity='warning' source='UncommunicativeParameterName'/></file></checkstyle>
2
+ <checkstyle>
3
+ <file name='spec/samples/two_smelly_files/dirty_one.rb'>
4
+ <error column='0' line='5' message='has the variable name &apos;@s&apos;' severity='warning' source='UncommunicativeVariableName'/>
5
+ <error column='0' line='4' message='calls @s.title 2 times' severity='warning' source='DuplicateMethodCall'/>
6
+ <error column='0' line='6' message='calls @s.title 2 times' severity='warning' source='DuplicateMethodCall'/>
7
+ <error column='0' line='4' message='calls puts(@s.title) 2 times' severity='warning' source='DuplicateMethodCall'/>
8
+ <error column='0' line='6' message='calls puts(@s.title) 2 times' severity='warning' source='DuplicateMethodCall'/>
9
+ <error column='0' line='5' message='contains iterators nested 2 deep' severity='warning' source='NestedIterators'/>
10
+ <error column='0' line='3' message='has the name &apos;a&apos;' severity='warning' source='UncommunicativeMethodName'/>
11
+ <error column='0' line='5' message='has the variable name &apos;x&apos;' severity='warning' source='UncommunicativeVariableName'/>
12
+ </file>
13
+ </checkstyle>
@@ -1,4 +1,5 @@
1
1
  require 'pathname'
2
+ require_relative '../lib/reek'
2
3
  require_relative '../lib/reek/spec'
3
4
  require_relative '../lib/reek/ast/ast_node_class_map'
4
5
  require_relative '../lib/reek/configuration/app_configuration'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reek
3
3
  version: !ruby/object:Gem::Version
4
- version: '3.1'
4
+ version: '3.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Rutherford
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-07-21 00:00:00.000000000 Z
13
+ date: 2015-08-17 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parser
@@ -26,6 +26,20 @@ dependencies:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
28
  version: 2.2.2.5
29
+ - !ruby/object:Gem::Dependency
30
+ name: private_attr
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - "~>"
34
+ - !ruby/object:Gem::Version
35
+ version: '1.1'
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '1.1'
29
43
  - !ruby/object:Gem::Dependency
30
44
  name: rainbow
31
45
  requirement: !ruby/object:Gem::Requirement
@@ -74,14 +88,14 @@ dependencies:
74
88
  requirements:
75
89
  - - "~>"
76
90
  - !ruby/object:Gem::Version
77
- version: 0.7.2
91
+ version: 0.8.0
78
92
  type: :development
79
93
  prerelease: false
80
94
  version_requirements: !ruby/object:Gem::Requirement
81
95
  requirements:
82
96
  - - "~>"
83
97
  - !ruby/object:Gem::Version
84
- version: 0.7.2
98
+ version: 0.8.0
85
99
  - !ruby/object:Gem::Dependency
86
100
  name: ataru
87
101
  requirement: !ruby/object:Gem::Requirement
@@ -189,14 +203,14 @@ executables:
189
203
  - reek
190
204
  extensions: []
191
205
  extra_rdoc_files:
192
- - CHANGELOG
206
+ - CHANGELOG.md
193
207
  - License.txt
194
208
  files:
195
209
  - ".gitignore"
196
210
  - ".rubocop.yml"
197
211
  - ".travis.yml"
198
212
  - ".yardopts"
199
- - CHANGELOG
213
+ - CHANGELOG.md
200
214
  - CONTRIBUTING.md
201
215
  - Gemfile
202
216
  - License.txt
@@ -429,7 +443,6 @@ files:
429
443
  - spec/samples/three_clean_files/clean_two.rb
430
444
  - spec/samples/two_smelly_files/dirty_one.rb
431
445
  - spec/samples/two_smelly_files/dirty_two.rb
432
- - spec/samples/unusual_syntax.rb
433
446
  - spec/spec_helper.rb
434
447
  - tasks/develop.rake
435
448
  - tasks/reek.rake