reek 1.2.7.1 → 1.2.7.2

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 (68) hide show
  1. data/History.txt +13 -1
  2. data/config/defaults.reek +4 -1
  3. data/features/masking_smells.feature +7 -7
  4. data/features/rake_task.feature +2 -2
  5. data/features/reports.feature +3 -3
  6. data/features/samples.feature +5 -2
  7. data/features/yaml.feature +0 -39
  8. data/lib/reek.rb +1 -1
  9. data/lib/reek/cli/command_line.rb +3 -3
  10. data/lib/reek/cli/reek_command.rb +5 -6
  11. data/lib/reek/cli/report.rb +9 -20
  12. data/lib/reek/cli/yaml_command.rb +1 -1
  13. data/lib/reek/core/class_context.rb +1 -2
  14. data/lib/reek/core/code_context.rb +10 -27
  15. data/lib/reek/core/code_parser.rb +1 -18
  16. data/lib/reek/core/detector_stack.rb +4 -0
  17. data/lib/reek/core/masking_collection.rb +6 -0
  18. data/lib/reek/core/method_context.rb +8 -56
  19. data/lib/reek/core/module_context.rb +6 -32
  20. data/lib/reek/core/object_refs.rb +36 -36
  21. data/lib/reek/core/singleton_method_context.rb +10 -21
  22. data/lib/reek/core/sniffer.rb +3 -2
  23. data/lib/reek/examiner.rb +39 -31
  24. data/lib/reek/smell_warning.rb +8 -0
  25. data/lib/reek/smells/attribute.rb +4 -2
  26. data/lib/reek/smells/class_variable.rb +3 -3
  27. data/lib/reek/smells/control_couple.rb +1 -2
  28. data/lib/reek/smells/data_clump.rb +86 -9
  29. data/lib/reek/smells/duplication.rb +2 -3
  30. data/lib/reek/smells/feature_envy.rb +9 -4
  31. data/lib/reek/smells/simulated_polymorphism.rb +1 -2
  32. data/lib/reek/smells/smell_detector.rb +0 -6
  33. data/lib/reek/smells/uncommunicative_method_name.rb +8 -2
  34. data/lib/reek/smells/uncommunicative_parameter_name.rb +1 -1
  35. data/lib/reek/smells/uncommunicative_variable_name.rb +1 -1
  36. data/lib/reek/smells/utility_function.rb +17 -5
  37. data/lib/reek/source/reference_collector.rb +21 -0
  38. data/lib/reek/source/sexp_formatter.rb +1 -0
  39. data/lib/reek/source/tree_dresser.rb +67 -9
  40. data/lib/reek/spec/should_reek.rb +1 -1
  41. data/lib/reek/spec/should_reek_of.rb +1 -1
  42. data/lib/reek/spec/should_reek_only_of.rb +1 -1
  43. data/reek.gemspec +3 -3
  44. data/spec/reek/cli/reek_command_spec.rb +3 -2
  45. data/spec/reek/cli/report_spec.rb +2 -2
  46. data/spec/reek/cli/yaml_command_spec.rb +2 -2
  47. data/spec/reek/core/code_context_spec.rb +39 -54
  48. data/spec/reek/core/method_context_spec.rb +7 -26
  49. data/spec/reek/core/module_context_spec.rb +0 -15
  50. data/spec/reek/core/singleton_method_context_spec.rb +0 -6
  51. data/spec/reek/examiner_spec.rb +6 -6
  52. data/spec/reek/smells/attribute_spec.rb +30 -32
  53. data/spec/reek/smells/class_variable_spec.rb +15 -18
  54. data/spec/reek/smells/data_clump_spec.rb +22 -6
  55. data/spec/reek/smells/duplication_spec.rb +33 -19
  56. data/spec/reek/smells/feature_envy_spec.rb +82 -88
  57. data/spec/reek/smells/large_class_spec.rb +1 -1
  58. data/spec/reek/smells/smell_detector_shared.rb +1 -1
  59. data/spec/reek/smells/uncommunicative_method_name_spec.rb +37 -35
  60. data/spec/reek/smells/utility_function_spec.rb +7 -0
  61. data/spec/reek/source/reference_collector_spec.rb +53 -0
  62. data/spec/reek/source/tree_dresser_spec.rb +10 -0
  63. data/spec/reek/spec/should_reek_only_of_spec.rb +1 -1
  64. data/spec/spec_helper.rb +7 -0
  65. metadata +4 -5
  66. data/features/profile.feature +0 -34
  67. data/lib/reek/core/block_context.rb +0 -18
  68. data/spec/reek/core/block_context_spec.rb +0 -26
@@ -21,7 +21,7 @@ shared_examples_for 'SmellDetector' do
21
21
 
22
22
  context 'configuration' do
23
23
  it 'becomes disabled when disabled' do
24
- @detector.configure({@detector.smell_type => {SmellConfiguration::ENABLED_KEY => false}})
24
+ @detector.configure_with({SmellConfiguration::ENABLED_KEY => false})
25
25
  @detector.should_not be_enabled
26
26
  end
27
27
  end
@@ -15,43 +15,45 @@ describe UncommunicativeMethodName do
15
15
 
16
16
  it_should_behave_like 'SmellDetector'
17
17
 
18
- it 'should not report one-word method name' do
19
- 'def help(fred) basics(17) end'.should_not reek
20
- end
21
- it 'should report one-letter method name' do
22
- 'def x(fred) basics(17) end'.should reek_only_of(:UncommunicativeMethodName, /x/)
23
- end
24
- it 'should report name of the form "x2"' do
25
- 'def x2(fred) basics(17) end'.should reek_only_of(:UncommunicativeMethodName, /x2/)
26
- end
27
- it 'should report long name ending in a number' do
28
- 'def method2(fred) basics(17) end'.should reek_only_of(:UncommunicativeMethodName, /method2/)
18
+ ['help', '+', '-', '/', '*'].each do |method_name|
19
+ it "accepts the method name '#{method_name}'" do
20
+ "def #{method_name}(fred) basics(17) end".should_not reek
21
+ end
29
22
  end
30
23
 
31
- context 'looking at the YAML' do
32
- before :each do
33
- src = 'def bad3() end'
34
- source = src.to_reek_source
35
- sniffer = Core::Sniffer.new(source)
36
- @mctx = Core::CodeParser.new(sniffer).process_defn(source.syntax_tree)
37
- @detector.examine(@mctx)
38
- warning = @detector.smells_found.to_a[0] # SMELL: too cumbersome!
39
- @yaml = warning.to_yaml
40
- end
41
- it 'reports the source' do
42
- @yaml.should match(/source:\s*#{@source_name}/)
43
- end
44
- it 'reports the class' do
45
- @yaml.should match(/\sclass:\s*UncommunicativeName/)
46
- end
47
- it 'reports the subclass' do
48
- @yaml.should match(/subclass:\s*UncommunicativeMethodName/)
49
- end
50
- it 'reports the variable name' do
51
- @yaml.should match(/method_name:\s*bad3/)
52
- end
53
- it 'reports the line number of the method def' do
54
- @yaml.should match(/lines:\s*- 1/)
24
+ ['x', 'x2', 'method2'].each do |method_name|
25
+ context 'with a bad name' do
26
+ before :each do
27
+ @full_name = 'anything you like'
28
+ ctx = mock('method', :null_object => true)
29
+ ctx.should_receive(:name).and_return(method_name)
30
+ ctx.should_receive(:full_name).at_least(:once).and_return(@full_name)
31
+ ctx.should_receive(:exp).and_return(ast(:defn))
32
+ @detector.examine_context(ctx)
33
+ @smells = @detector.smells_found.to_a
34
+ end
35
+
36
+ it 'records only that attribute' do
37
+ @smells.length.should == 1
38
+ end
39
+ it 'reports the attribute name' do
40
+ @smells[0].smell[UncommunicativeMethodName::METHOD_NAME_KEY].should == method_name
41
+ end
42
+ it 'reports the declaration line number' do
43
+ @smells[0].lines.should == [1]
44
+ end
45
+ it 'reports the correct smell class' do
46
+ @smells[0].smell_class.should == UncommunicativeMethodName::SMELL_CLASS
47
+ end
48
+ it 'reports the correct smell subclass' do
49
+ @smells[0].subclass.should == UncommunicativeMethodName::SMELL_SUBCLASS
50
+ end
51
+ it 'reports the context fq name' do
52
+ @smells[0].context.should == @full_name
53
+ end
54
+ it 'reports the source name' do
55
+ @smells[0].source.should == @source_name
56
+ end
55
57
  end
56
58
  end
57
59
  end
@@ -6,6 +6,13 @@ include Reek
6
6
  include Reek::Smells
7
7
 
8
8
  describe UtilityFunction do
9
+ context 'with a singleton method' do
10
+ ['self', 'local_call', '$global'].each do |receiver|
11
+ it 'ignores the receiver' do
12
+ "def #{receiver}.simple(arga) arga.to_s + arga.to_i end".should_not reek
13
+ end
14
+ end
15
+ end
9
16
  context 'with no calls' do
10
17
  it 'does not report empty method' do
11
18
  'def simple(arga) end'.should_not reek
@@ -0,0 +1,53 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
2
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'source', 'reference_collector')
3
+
4
+ include Reek::Source
5
+
6
+ describe ReferenceCollector do
7
+
8
+ context 'counting refs to self' do
9
+ def refs_to_self(src)
10
+ ReferenceCollector.new(src.to_reek_source.syntax_tree).num_refs_to_self
11
+ end
12
+ it 'with no refs to self' do
13
+ refs_to_self('def no_envy(arga) arga.barg end').should == 0
14
+ end
15
+ it 'counts a call to super' do
16
+ refs_to_self('def simple() super; end').should == 1
17
+ end
18
+ it 'counts a local call' do
19
+ refs_to_self('def simple() to_s; end').should == 1
20
+ end
21
+ it 'counts a use of self' do
22
+ refs_to_self('def simple() lv = self; end').should == 1
23
+ end
24
+ it 'counts a call with self as receiver' do
25
+ refs_to_self('def simple() self.to_s; end').should == 1
26
+ end
27
+ it 'counts uses of an ivar' do
28
+ refs_to_self('def no_envy() @item.to_a; @item = 4; @item end').should == 3
29
+ end
30
+ it 'counts an ivar passed to a method' do
31
+ refs_to_self('def no_envy(arga) arga.barg(@item); arga end').should == 1
32
+ end
33
+ it 'ignores global variables' do
34
+ refs_to_self('def no_envy(arga) $s2.to_a; $s2[arga] end').should == 0
35
+ end
36
+ it 'ignores global variables' do
37
+ src = <<EOS
38
+ def accept(t, pat = /.*/nm, &block)
39
+ if pat
40
+ pat.respond_to?(:match) or raise TypeError, "has no `match'"
41
+ else
42
+ pat = t if t.respond_to?(:match)
43
+ end
44
+ unless block
45
+ block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
46
+ end
47
+ @atype[t] = [pat, block]
48
+ end
49
+ EOS
50
+ refs_to_self(src).should == 2
51
+ end
52
+ end
53
+ end
@@ -15,6 +15,16 @@ describe TreeDresser do
15
15
  end
16
16
  end
17
17
 
18
+ describe SexpNode do
19
+ context 'format' do
20
+ it 'formats self' do
21
+ @node = s(:self)
22
+ @node.extend(SexpNode)
23
+ @node.format.should == 'self'
24
+ end
25
+ end
26
+ end
27
+
18
28
  describe SexpExtensions::DefnNode do
19
29
  context 'with no parameters' do
20
30
  before :each do
@@ -10,7 +10,7 @@ describe ShouldReekOnlyOf do
10
10
  @expected_context_name = 'SmellyClass#big_method'
11
11
  @matcher = ShouldReekOnlyOf.new(@expected_smell_class, [/#{@expected_context_name}/])
12
12
  @examiner = mock('examiner', :null_object => true)
13
- @examiner.should_receive(:all_active_smells).and_return {smells}
13
+ @examiner.should_receive(:smells).and_return {smells}
14
14
  @match = @matcher.matches_examiner?(@examiner)
15
15
  end
16
16
 
data/spec/spec_helper.rb CHANGED
@@ -10,5 +10,12 @@ end
10
10
  require 'spec/autorun'
11
11
 
12
12
  require File.join((File.dirname(File.dirname(File.expand_path(__FILE__)))), 'lib', 'reek', 'spec')
13
+ require File.join((File.dirname(File.dirname(File.expand_path(__FILE__)))), 'lib', 'reek', 'source', 'tree_dresser')
13
14
 
14
15
  SAMPLES_DIR = 'spec/samples' unless Object.const_defined?('SAMPLES_DIR')
16
+
17
+ def ast(*args)
18
+ result = Reek::Source::TreeDresser.new.dress(s(*args))
19
+ result.line = 1
20
+ result
21
+ end
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: 1.2.7.1
4
+ version: 1.2.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Rutherford
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-03 00:00:00 +00:00
12
+ date: 2010-03-05 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -65,7 +65,6 @@ files:
65
65
  - config/defaults.reek
66
66
  - features/masking_smells.feature
67
67
  - features/options.feature
68
- - features/profile.feature
69
68
  - features/rake_task.feature
70
69
  - features/reports.feature
71
70
  - features/samples.feature
@@ -81,7 +80,6 @@ files:
81
80
  - lib/reek/cli/report.rb
82
81
  - lib/reek/cli/version_command.rb
83
82
  - lib/reek/cli/yaml_command.rb
84
- - lib/reek/core/block_context.rb
85
83
  - lib/reek/core/class_context.rb
86
84
  - lib/reek/core/code_context.rb
87
85
  - lib/reek/core/code_parser.rb
@@ -122,6 +120,7 @@ files:
122
120
  - lib/reek/source/code_comment.rb
123
121
  - lib/reek/source/config_file.rb
124
122
  - lib/reek/source/core_extras.rb
123
+ - lib/reek/source/reference_collector.rb
125
124
  - lib/reek/source/sexp_formatter.rb
126
125
  - lib/reek/source/source_code.rb
127
126
  - lib/reek/source/source_file.rb
@@ -137,7 +136,6 @@ files:
137
136
  - spec/reek/cli/report_spec.rb
138
137
  - spec/reek/cli/version_command_spec.rb
139
138
  - spec/reek/cli/yaml_command_spec.rb
140
- - spec/reek/core/block_context_spec.rb
141
139
  - spec/reek/core/class_context_spec.rb
142
140
  - spec/reek/core/code_context_spec.rb
143
141
  - spec/reek/core/code_parser_spec.rb
@@ -174,6 +172,7 @@ files:
174
172
  - spec/reek/smells/utility_function_spec.rb
175
173
  - spec/reek/source/code_comment_spec.rb
176
174
  - spec/reek/source/object_source_spec.rb
175
+ - spec/reek/source/reference_collector_spec.rb
177
176
  - spec/reek/source/source_code_spec.rb
178
177
  - spec/reek/source/tree_dresser_spec.rb
179
178
  - spec/reek/spec/should_reek_of_spec.rb
@@ -1,34 +0,0 @@
1
- @profile
2
- Feature: Reek's configuration can be based on any number of canned profiles
3
- The starting point for configuring the smell detectors can be
4
- selected from a list of supplied config files.
5
-
6
- # Scenario: XP profile reveals Attribute smells
7
- # When I run reek --profile xp spec/samples/not_quite_masked/dirty.rb
8
- # Then the exit status indicates smells
9
- # And it reports:
10
- # """
11
- # spec/samples/not_quite_masked/dirty.rb -- 5 warnings (+2 masked):
12
- # Dirty declares the attribute property (Attribute)
13
- # Dirty has the variable name '@s' (Uncommunicative Name)
14
- # Dirty#a calls @s.title twice (Duplication)
15
- # Dirty#a calls puts(@s.title) twice (Duplication)
16
- # Dirty#a has the name 'a' (Uncommunicative Name)
17
- #
18
- # """
19
- #
20
- # Scenario: XP profile works with unmasked smells
21
- # When I run reek --show-all --profile xp spec/samples/not_quite_masked/dirty.rb
22
- # Then the exit status indicates smells
23
- # And it reports:
24
- # """
25
- # spec/samples/not_quite_masked/dirty.rb -- 5 warnings (+2 masked):
26
- # Dirty declares the attribute property (Attribute)
27
- # Dirty has the variable name '@s' (Uncommunicative Name)
28
- # Dirty#a calls @s.title twice (Duplication)
29
- # Dirty#a calls puts(@s.title) twice (Duplication)
30
- # Dirty#a has the name 'a' (Uncommunicative Name)
31
- # (masked) Dirty#a/block has the variable name 'x' (Uncommunicative Name)
32
- # (masked) Dirty#a/block/block is nested (Nested Iterators)
33
- #
34
- # """
@@ -1,18 +0,0 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), 'code_context')
2
-
3
- module Reek
4
- module Core
5
-
6
- #
7
- # A context wrapper for any block found in a syntax tree.
8
- #
9
- class BlockContext < CodeContext
10
-
11
- def initialize(outer, exp)
12
- super
13
- @name = 'block'
14
- @scope_connector = '/'
15
- end
16
- end
17
- end
18
- end
@@ -1,26 +0,0 @@
1
- require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
2
- require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'block_context')
3
- require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'method_context')
4
-
5
- include Reek::Core
6
-
7
- describe BlockContext do
8
- context 'full_name' do
9
- it "reports full context" do
10
- bctx = BlockContext.new(StopContext.new, s(nil, nil))
11
- bctx.full_name.should == 'block'
12
- end
13
- it 'uses / to connect to the class name' do
14
- element = StopContext.new
15
- element = ClassContext.new(element, :Fred, s(:class, :Fred))
16
- element = BlockContext.new(element, s(:iter, nil, s(:lasgn, :x), nil))
17
- element.full_name.should == 'Fred/block'
18
- end
19
- it 'uses / to connect to the module name' do
20
- element = StopContext.new
21
- element = ModuleContext.new(element, :Fred, s(:module, :Fred))
22
- element = BlockContext.new(element, s(:iter, nil, s(:lasgn, :x), nil))
23
- element.full_name.should == 'Fred/block'
24
- end
25
- end
26
- end