reek 4.0.2 → 4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 72d27c8901d22ffc65492d565e6c037d71f9f1e0
4
- data.tar.gz: e358a34395daae66652468724f1794f4a8719d0a
3
+ metadata.gz: 71c1d52a08d1ce16364812f297d6a072109b406b
4
+ data.tar.gz: f0ea4129036dde1687ad6656c603d63e8a6ddaf2
5
5
  SHA512:
6
- metadata.gz: d6ef752ab64fb5db0d0038e4a41405c261c1f9e6b9174e3b9b2b50062892fe78bcd5d1467ca0d392590e00a63ca33b25e1c6376cb59a2d37f989e12284e79951
7
- data.tar.gz: 7daf1e81235a889917a06a737bab16996f0e2c51fbd3ab278869c7405c985821088e8d6071a0c79f573f725dd84bebd49b358327ea825314eee5769aca618a1d
6
+ metadata.gz: 1228e4b9dc1f5673e7f474af1c6f5eb16d30eac8df72d4aecb4684b2ff2aa7796e62defe53a903ff9853444fe112187e3d7de7f40bd8c619c75d459d11273d7d
7
+ data.tar.gz: fb720491aa22c267bdccdfdb7296f9f89a216ab7da89d8e66f903c63bf401ee8beff14256a0b052bf284df93f81d27f9c050f1db1af3b15714f6b7a23565c425
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Change log
2
2
 
3
+ ## 4.0.3 (2016-05-23)
4
+
5
+ * (mvz) Include default exclusions in generated TODO file
6
+ * (mvz) Avoid generating duplicate context entries in exclusions
7
+
3
8
  ## 4.0.2 (2016-04-23)
4
9
 
5
10
  * (mvz) Stop UnusedPrivateMethod getting confused by nested classes
data/README.md CHANGED
@@ -2,8 +2,37 @@
2
2
 
3
3
  # Code smell detector for Ruby
4
4
 
5
- ## Overview
5
+ **Table of Contents**
6
+
7
+ - [Overview](#overview)
8
+ - [Quickstart](#quickstart)
9
+ - [Example](#example)
10
+ - [Supported rubies](#supported-rubies)
11
+ - [Fixing Smell Warnings](#fixing-smell-warnings)
12
+ - [Sources](#sources)
13
+ - [Code smells](#code-smells)
14
+ - [Configuration](#configuration)
15
+ - [Command-line interface](#command-line-interface)
16
+ - [Configuration file](#configuration-file)
17
+ - [Configuration loading](#configuration-loading)
18
+ - [Configuration options](#configuration-options)
19
+ - [Source code comments](#source-code-comments)
20
+ - [Generating a 'todo' list](#generating-a-todo-list)
21
+ - [Usage](#usage)
22
+ - [Developing Reek / Contributing](#developing-reek--contributing)
23
+ - [Output formats](#output-formats)
24
+ - [Working with Rails](#working-with-rails)
25
+ - [Integrations](#integrations)
26
+ - [Editor integrations](#editor-integrations)
27
+ - [Projects that use or support us](#projects-that-use-or-support-us)
28
+ - [Misc](#misc)
29
+ - [Brothers and sisters](#brothers-and-sisters)
30
+ - [Contributors](#contributors)
31
+ - [Additional resources](#additional-resources)
32
+ - [Miscellaneous](#miscellaneous)
33
+ - [More information](#more-information)
6
34
 
35
+ ## Overview
7
36
 
8
37
  [![Build Status](https://secure.travis-ci.org/troessner/reek.svg?branch=master)](https://travis-ci.org/troessner/reek?branch=master)
9
38
  [![Gem Version](https://badge.fury.io/rb/reek.svg)](https://badge.fury.io/rb/reek)
@@ -19,7 +48,7 @@ Reek is a tool that examines Ruby classes, modules and methods and reports any
19
48
 
20
49
  For an excellent introduction to
21
50
  [Code Smells](docs/Code-Smells.md) and Reek check out [this blog post](https://blog.codeship.com/how-to-find-ruby-code-smells-with-reek/)
22
- or [that one](https://troessner.wordpress.com/2016/01/01/the-latest-and-greatest-additions-to-reek/). There is also [this talk](https://www.youtube.com/watch?v=ZzqOuHI5MkA) from the [RubyConf Portugal](http://rubyconf.pt/).
51
+ or [that one](https://troessner.svbtle.com/the-latest-and-greatest-additions-to-reek). There is also [this talk](https://www.youtube.com/watch?v=ZzqOuHI5MkA) from the [RubyConf Portugal](http://rubyconf.pt/).
23
52
 
24
53
  Install it via rubygems:
25
54
 
@@ -461,6 +490,7 @@ Be careful though, Reek does not merge your configuration entries, so if you alr
461
490
  * [TextMate Bundle](https://github.com/peeyush1234/reek.tmbundle)
462
491
  * [Atom plugin](https://atom.io/packages/linter-reek)
463
492
  * [SublimeLinter plugin](https://packagecontrol.io/packages/SublimeLinter-contrib-reek)
493
+ * [Emacs plugin](https://github.com/hanmoi-choi/reek-emacs)
464
494
 
465
495
  ### Projects that use or support us
466
496
 
@@ -118,6 +118,14 @@ Given(/^a configuration file masking some duplication smells called 'config.reek
118
118
  EOS
119
119
  end
120
120
 
121
+ Given(/^a configuration file disabling DuplicateMethodCall called 'config.reek'$/) do
122
+ write_file('config.reek', <<-EOS.strip_heredoc)
123
+ ---
124
+ DuplicateMethodCall:
125
+ enabled: false
126
+ EOS
127
+ end
128
+
121
129
  When(/^I run "reek (.*?)" in the subdirectory$/) do |args|
122
130
  cd 'subdir'
123
131
  reek(args)
@@ -9,41 +9,42 @@ Feature:
9
9
  - fix them step by step
10
10
  - get rid of the todo file
11
11
 
12
- Background:
13
- Given a directory 'lib' with one clean file 'clean.rb' and one dirty file 'dirty.rb'
14
- And a directory 'superclean' with one clean file 'clean.rb'
15
-
16
12
  Scenario: Generate a proper todo file that disables all found smells
17
- When I run reek lib
13
+ Given a smelly file called 'smelly.rb'
14
+ When I run reek smelly.rb
18
15
  Then the exit status indicates smells
19
16
  And it reports:
20
17
  """
21
- lib/dirty.rb -- 3 warnings:
22
- [1]:IrresponsibleModule: Dirty has no descriptive comment [https://github.com/troessner/reek/blob/master/docs/Irresponsible-Module.md]
23
- [2]:UncommunicativeMethodName: Dirty#a has the name 'a' [https://github.com/troessner/reek/blob/master/docs/Uncommunicative-Method-Name.md]
24
- [3]:UncommunicativeMethodName: Dirty#b has the name 'b' [https://github.com/troessner/reek/blob/master/docs/Uncommunicative-Method-Name.md]
25
- 3 total warnings
18
+ smelly.rb -- 3 warnings:
19
+ [4, 5]:DuplicateMethodCall: Smelly#m calls @foo.bar 2 times [https://github.com/troessner/reek/blob/master/docs/Duplicate-Method-Call.md]
20
+ [4, 5]:DuplicateMethodCall: Smelly#m calls puts @foo.bar 2 times [https://github.com/troessner/reek/blob/master/docs/Duplicate-Method-Call.md]
21
+ [3]:UncommunicativeMethodName: Smelly#m has the name 'm' [https://github.com/troessner/reek/blob/master/docs/Uncommunicative-Method-Name.md]
26
22
  """
27
- When I run reek --todo lib
23
+ When I run reek --todo smelly.rb
28
24
  Then it succeeds
25
+ And it reports:
26
+ """
27
+
28
+ '.todo.reek' generated! You can now use this as a starting point for your configuration.
29
+ """
29
30
  And a file named ".todo.reek" should exist
30
31
  And the file ".todo.reek" should contain:
31
32
  """
32
33
  ---
33
- IrresponsibleModule:
34
+ DuplicateMethodCall:
34
35
  exclude:
35
- - Dirty
36
+ - Smelly#m
36
37
  UncommunicativeMethodName:
37
38
  exclude:
38
- - Dirty#a
39
- - Dirty#b
39
+ - Smelly#m
40
40
  """
41
- When I run reek -c .todo.reek lib
41
+ When I run reek -c .todo.reek smelly.rb
42
42
  Then it succeeds
43
43
 
44
- Scenario: Respects an configuration file
45
- Given a configuration file 'config.reek' that partially masks 'dirty.rb'
46
- When I run reek -c config.reek --todo lib
44
+ Scenario: Respects a configuration file
45
+ Given a smelly file called 'smelly.rb'
46
+ And a configuration file disabling DuplicateMethodCall called 'config.reek'
47
+ When I run reek -c config.reek --todo smelly.rb
47
48
  Then it succeeds
48
49
  And a file named ".todo.reek" should exist
49
50
  And the file ".todo.reek" should contain:
@@ -51,19 +52,12 @@ Feature:
51
52
  ---
52
53
  UncommunicativeMethodName:
53
54
  exclude:
54
- - Dirty#a
55
- """
56
-
57
- Scenario: Print out a helpful message that explains to the user what to do next
58
- When I run reek --todo lib
59
- Then it reports:
60
- """
61
-
62
- '.todo.reek' generated! You can now use this as a starting point for your configuration.
55
+ - Smelly#m
63
56
  """
64
57
 
65
58
  Scenario: Reacts appropiately when there are no smells
66
- When I run reek --todo superclean/
59
+ Given the clean file 'clean.rb'
60
+ When I run reek --todo clean.rb
67
61
  Then a file named ".todo.reek" should not exist
68
62
  And it reports:
69
63
  """
@@ -36,13 +36,13 @@ module Reek
36
36
  end
37
37
 
38
38
  def groups_for(smells)
39
- @groups ||= begin
40
- Hash[
41
- smells.group_by(&:smell_type).map do |smell_type, smells_for_type|
42
- [smell_type, { 'exclude' => smells_for_type.map(&:context) }]
39
+ @groups ||=
40
+ begin
41
+ todos = smells.group_by(&:smell_class).map do |smell_class, smells_for_class|
42
+ smell_class.todo_configuration_for(smells_for_class)
43
43
  end
44
- ]
45
- end
44
+ todos.inject(&:merge)
45
+ end
46
46
  end
47
47
  end
48
48
  end
@@ -55,6 +55,12 @@ module Reek
55
55
  context.matches?(value(EXCLUDE_KEY, context, DEFAULT_EXCLUDE_SET))
56
56
  end
57
57
 
58
+ def self.todo_configuration_for(smells)
59
+ default_exclusions = default_config.fetch 'exclude'
60
+ exclusions = default_exclusions + smells.map(&:context)
61
+ { smell_type => { 'exclude' => exclusions.uniq } }
62
+ end
63
+
58
64
  private
59
65
 
60
66
  attr_accessor :smells_found
@@ -63,6 +63,10 @@ module Reek
63
63
  "#{smell_type}: #{context} #{message}"
64
64
  end
65
65
 
66
+ def smell_class
67
+ smell_detector.class
68
+ end
69
+
66
70
  protected
67
71
 
68
72
  def sort_key
data/lib/reek/version.rb CHANGED
@@ -7,6 +7,6 @@ module Reek
7
7
  # @public
8
8
  module Version
9
9
  # @public
10
- STRING = '4.0.2'.freeze
10
+ STRING = '4.0.3'.freeze
11
11
  end
12
12
  end
@@ -3,6 +3,11 @@ require_lib 'reek/cli/command/todo_list_command'
3
3
  require_lib 'reek/cli/options'
4
4
 
5
5
  RSpec.describe Reek::CLI::Command::TodoListCommand do
6
+ let(:nil_check) { build :smell_detector, smell_type: :NilCheck }
7
+ let(:feature_envy) { build :smell_detector, smell_type: :FeatureEnvy }
8
+ let(:nested_iterators) { build :smell_detector, smell_type: :NestedIterators }
9
+ let(:too_many_statements) { build :smell_detector, smell_type: :TooManyStatements }
10
+
6
11
  describe '#execute' do
7
12
  let(:options) { Reek::CLI::Options.new [] }
8
13
  let(:configuration) { double 'configuration' }
@@ -24,7 +29,7 @@ RSpec.describe Reek::CLI::Command::TodoListCommand do
24
29
 
25
30
  context 'smells found' do
26
31
  before do
27
- smells = [FactoryGirl.build(:smell_warning)]
32
+ smells = [build(:smell_warning, context: 'Foo#bar')]
28
33
  allow(command).to receive(:scan_for_smells).and_return(smells)
29
34
  end
30
35
 
@@ -37,6 +42,61 @@ RSpec.describe Reek::CLI::Command::TodoListCommand do
37
42
  result = command.execute
38
43
  expect(result).to eq(Reek::CLI::Options::DEFAULT_SUCCESS_EXIT_CODE)
39
44
  end
45
+
46
+ it 'writes a todo file' do
47
+ command.execute
48
+ expected_yaml = { 'FeatureEnvy' => { 'exclude' => ['Foo#bar'] } }.to_yaml
49
+ expect(File).to have_received(:write).with(described_class::FILE_NAME, expected_yaml)
50
+ end
51
+ end
52
+
53
+ context 'smells with duplicate context found' do
54
+ before do
55
+ smells = [
56
+ build(:smell_warning, context: 'Foo#bar', smell_detector: feature_envy),
57
+ build(:smell_warning, context: 'Foo#bar', smell_detector: feature_envy)
58
+ ]
59
+ allow(command).to receive(:scan_for_smells).and_return(smells)
60
+ end
61
+
62
+ it 'writes the context into the todo file once' do
63
+ command.execute
64
+ expected_yaml = { 'FeatureEnvy' => { 'exclude' => ['Foo#bar'] } }.to_yaml
65
+ expect(File).to have_received(:write).with(described_class::FILE_NAME, expected_yaml)
66
+ end
67
+ end
68
+
69
+ context 'smells with default exclusions found' do
70
+ let(:smell) { build :smell_warning, smell_detector: too_many_statements, context: 'Foo#bar' }
71
+
72
+ before do
73
+ allow(command).to receive(:scan_for_smells).and_return [smell]
74
+ end
75
+
76
+ it 'includes the default exclusions in the generated yaml' do
77
+ command.execute
78
+ expected_yaml = { 'TooManyStatements' => { 'exclude' => ['initialize', 'Foo#bar'] } }.to_yaml
79
+ expect(File).to have_received(:write).with(described_class::FILE_NAME, expected_yaml)
80
+ end
81
+ end
82
+
83
+ context 'smells of different types found' do
84
+ before do
85
+ smells = [
86
+ build(:smell_warning, context: 'Foo#bar', smell_detector: nil_check),
87
+ build(:smell_warning, context: 'Bar#baz', smell_detector: nested_iterators)
88
+ ]
89
+ allow(command).to receive(:scan_for_smells).and_return(smells)
90
+ end
91
+
92
+ it 'writes the context into the todo file once' do
93
+ command.execute
94
+ expected_yaml = {
95
+ 'NilCheck' => { 'exclude' => ['Foo#bar'] },
96
+ 'NestedIterators' => { 'exclude' => ['Bar#baz'] }
97
+ }.to_yaml
98
+ expect(File).to have_received(:write).with(described_class::FILE_NAME, expected_yaml)
99
+ end
40
100
  end
41
101
 
42
102
  context 'no smells found' do
@@ -53,13 +113,10 @@ RSpec.describe Reek::CLI::Command::TodoListCommand do
53
113
  result = command.execute
54
114
  expect(result).to eq Reek::CLI::Options::DEFAULT_SUCCESS_EXIT_CODE
55
115
  end
56
- end
57
116
 
58
- describe 'groups_for' do
59
- it 'returns a proper hash representation of the smells found' do
60
- smells = [FactoryGirl.build(:smell_warning)]
61
- expected = { 'FeatureEnvy' => { 'exclude' => ['self'] } }
62
- expect(command.send(:groups_for, smells)).to eq(expected)
117
+ it 'does not write a todo file' do
118
+ command.execute
119
+ expect(File).not_to have_received(:write)
63
120
  end
64
121
  end
65
122
  end
@@ -0,0 +1,36 @@
1
+ require_relative '../../spec_helper'
2
+ require_lib 'reek/smells/smell_detector'
3
+
4
+ RSpec.describe Reek::Smells::SmellDetector do
5
+ describe '.todo_configuration_for' do
6
+ it 'returns exclusion configuration for the given smells' do
7
+ detector = described_class.new
8
+ smell = create(:smell_warning, smell_detector: detector, context: 'Foo#bar')
9
+ result = described_class.todo_configuration_for([smell])
10
+ expect(result).to eq('SmellDetector' => { 'exclude' => ['Foo#bar'] })
11
+ end
12
+
13
+ it 'merges identical contexts' do
14
+ detector = described_class.new
15
+ smell = create(:smell_warning, smell_detector: detector, context: 'Foo#bar')
16
+ result = described_class.todo_configuration_for([smell, smell])
17
+ expect(result).to eq('SmellDetector' => { 'exclude' => ['Foo#bar'] })
18
+ end
19
+
20
+ context 'with default exclusions present' do
21
+ let(:subclass) { Reek::Smells::TooManyStatements }
22
+
23
+ before do
24
+ expect(subclass.default_config['exclude']).to eq ['initialize']
25
+ end
26
+
27
+ it 'includes default exclusions' do
28
+ detector = subclass.new
29
+ smell = create(:smell_warning, smell_detector: detector, context: 'Foo#bar')
30
+ result = subclass.todo_configuration_for([smell])
31
+
32
+ expect(result).to eq('TooManyStatements' => { 'exclude' => ['initialize', 'Foo#bar'] })
33
+ end
34
+ end
35
+ end
36
+ end
@@ -5,6 +5,7 @@ RSpec.describe Reek::Smells::SmellWarning do
5
5
  let(:duplication_detector) { build(:smell_detector, smell_type: 'DuplicateMethodCall') }
6
6
  let(:feature_envy_detector) { build(:smell_detector, smell_type: 'FeatureEnvy') }
7
7
  let(:utility_function_detector) { build(:smell_detector, smell_type: 'UtilityFunction') }
8
+ let(:uncommunicative_name_detector) { build(:smell_detector, smell_type: 'UncommunicativeVariableName') }
8
9
 
9
10
  context 'sort order' do
10
11
  shared_examples_for 'first sorts ahead of second' do
@@ -65,16 +66,12 @@ RSpec.describe Reek::Smells::SmellWarning do
65
66
 
66
67
  context 'smells differing everywhere' do
67
68
  let(:first) do
68
- duplication_detector = build(:smell_detector,
69
- smell_type: 'DuplicateMethodCall')
70
69
  build(:smell_warning, smell_detector: duplication_detector,
71
70
  context: 'Dirty#a',
72
71
  message: 'calls @s.title twice')
73
72
  end
74
73
 
75
74
  let(:second) do
76
- uncommunicative_name_detector = build(:smell_detector,
77
- smell_type: 'UncommunicativeVariableName')
78
75
  build(:smell_warning, smell_detector: uncommunicative_name_detector,
79
76
  context: 'Dirty',
80
77
  message: "has the variable name '@s'")
@@ -84,6 +81,13 @@ RSpec.describe Reek::Smells::SmellWarning do
84
81
  end
85
82
  end
86
83
 
84
+ describe '#smell_class' do
85
+ it "returns the dectector's class" do
86
+ warning = build(:smell_warning, smell_detector: duplication_detector)
87
+ expect(warning.smell_class).to eq duplication_detector.class
88
+ end
89
+ end
90
+
87
91
  context '#yaml_hash' do
88
92
  let(:class) { 'FeatureEnvy' }
89
93
  let(:context_name) { 'Module::Class#method/block' }
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: 4.0.2
4
+ version: 4.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Rutherford
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2016-04-23 00:00:00.000000000 Z
14
+ date: 2016-05-23 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: codeclimate-engine-rb
@@ -159,7 +159,6 @@ files:
159
159
  - features/step_definitions/.rubocop.yml
160
160
  - features/step_definitions/reek_steps.rb
161
161
  - features/step_definitions/sample_file_steps.rb
162
- - features/step_definitions/todo_list_steps.rb
163
162
  - features/support/env.rb
164
163
  - features/todo_list.feature
165
164
  - lib/reek.rb
@@ -319,6 +318,7 @@ files:
319
318
  - spec/reek/smells/repeated_conditional_spec.rb
320
319
  - spec/reek/smells/smell_configuration_spec.rb
321
320
  - spec/reek/smells/smell_detector_shared.rb
321
+ - spec/reek/smells/smell_detector_spec.rb
322
322
  - spec/reek/smells/smell_repository_spec.rb
323
323
  - spec/reek/smells/smell_warning_spec.rb
324
324
  - spec/reek/smells/too_many_instance_variables_spec.rb
@@ -1,40 +0,0 @@
1
- Given(/^a directory 'lib' with one clean file 'clean\.rb' and one dirty file 'dirty\.rb'$/) do
2
- write_file('lib/clean.rb', <<-EOS.strip_heredoc)
3
- # clean class for testing purposes
4
- class Clean
5
- def super_clean
6
- puts @janitor.name
7
- end
8
- end
9
- EOS
10
-
11
- write_file('lib/dirty.rb', <<-EOS.strip_heredoc)
12
- class Dirty
13
- def a; end
14
- def b; end
15
- end
16
- EOS
17
- end
18
-
19
- Given(/^a configuration file 'config\.reek' that partially masks 'dirty\.rb'$/) do
20
- write_file('config.reek', <<-EOS.strip_heredoc)
21
- ---
22
- IrresponsibleModule:
23
- exclude:
24
- - Dirty
25
- UncommunicativeMethodName:
26
- exclude:
27
- - Dirty#b
28
- EOS
29
- end
30
-
31
- Given(/^a directory 'superclean' with one clean file 'clean\.rb'$/) do
32
- write_file('superclean/clean.rb', <<-EOS.strip_heredoc)
33
- # clean class for testing purposes
34
- class Clean
35
- def super_clean
36
- puts @janitor.name
37
- end
38
- end
39
- EOS
40
- end