reek 1.2.6 → 1.2.8

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 (209) hide show
  1. data/.yardopts +10 -0
  2. data/History.txt +62 -0
  3. data/README.md +74 -0
  4. data/bin/reek +2 -2
  5. data/config/defaults.reek +44 -5
  6. data/features/api.feature +20 -0
  7. data/features/masking_smells.feature +60 -42
  8. data/features/options.feature +7 -2
  9. data/features/rake_task.feature +29 -22
  10. data/features/reports.feature +9 -41
  11. data/features/samples.feature +184 -196
  12. data/features/stdin.feature +5 -8
  13. data/features/step_definitions/reek_steps.rb +8 -4
  14. data/features/support/env.rb +2 -3
  15. data/features/yaml.feature +85 -0
  16. data/lib/reek/cli/application.rb +46 -0
  17. data/lib/reek/cli/command_line.rb +108 -0
  18. data/lib/reek/cli/help_command.rb +18 -0
  19. data/lib/reek/cli/reek_command.rb +37 -0
  20. data/lib/reek/cli/report.rb +58 -0
  21. data/lib/reek/cli/version_command.rb +19 -0
  22. data/lib/reek/cli/yaml_command.rb +32 -0
  23. data/lib/reek/core/code_context.rb +64 -0
  24. data/lib/reek/core/code_parser.rb +166 -0
  25. data/lib/reek/core/method_context.rb +84 -0
  26. data/lib/reek/core/module_context.rb +20 -0
  27. data/lib/reek/core/object_refs.rb +51 -0
  28. data/lib/reek/core/singleton_method_context.rb +20 -0
  29. data/lib/reek/core/smell_configuration.rb +62 -0
  30. data/lib/reek/core/sniffer.rb +105 -0
  31. data/lib/reek/core/stop_context.rb +30 -0
  32. data/lib/reek/core/warning_collector.rb +27 -0
  33. data/lib/reek/examiner.rb +104 -0
  34. data/lib/reek/rake/task.rb +142 -0
  35. data/lib/reek/smell_warning.rb +73 -23
  36. data/lib/reek/smells/attribute.rb +26 -21
  37. data/lib/reek/smells/boolean_parameter.rb +38 -0
  38. data/lib/reek/smells/class_variable.rb +22 -9
  39. data/lib/reek/smells/control_couple.rb +40 -16
  40. data/lib/reek/smells/data_clump.rb +114 -23
  41. data/lib/reek/smells/duplication.rb +55 -15
  42. data/lib/reek/smells/feature_envy.rb +16 -7
  43. data/lib/reek/smells/irresponsible_module.rb +37 -0
  44. data/lib/reek/smells/large_class.rb +37 -19
  45. data/lib/reek/smells/long_method.rb +20 -9
  46. data/lib/reek/smells/long_parameter_list.rb +22 -10
  47. data/lib/reek/smells/long_yield_list.rb +43 -7
  48. data/lib/reek/smells/nested_iterators.rb +68 -8
  49. data/lib/reek/smells/simulated_polymorphism.rb +26 -15
  50. data/lib/reek/smells/smell_detector.rb +29 -51
  51. data/lib/reek/smells/uncommunicative_method_name.rb +74 -0
  52. data/lib/reek/smells/uncommunicative_module_name.rb +74 -0
  53. data/lib/reek/smells/uncommunicative_parameter_name.rb +79 -0
  54. data/lib/reek/smells/uncommunicative_variable_name.rb +89 -0
  55. data/lib/reek/smells/utility_function.rb +51 -12
  56. data/lib/reek/smells.rb +29 -0
  57. data/lib/reek/source/code_comment.rb +37 -0
  58. data/lib/reek/source/config_file.rb +72 -0
  59. data/lib/reek/source/core_extras.rb +46 -0
  60. data/lib/reek/source/reference_collector.rb +28 -0
  61. data/lib/reek/source/sexp_formatter.rb +17 -0
  62. data/lib/reek/source/source_code.rb +44 -0
  63. data/lib/reek/source/source_file.rb +32 -0
  64. data/lib/reek/source/source_locator.rb +42 -0
  65. data/lib/reek/source/tree_dresser.rb +204 -0
  66. data/lib/reek/source.rb +18 -0
  67. data/lib/reek/spec/should_reek.rb +31 -0
  68. data/lib/reek/spec/should_reek_of.rb +37 -0
  69. data/lib/reek/spec/should_reek_only_of.rb +37 -0
  70. data/lib/reek/spec.rb +51 -0
  71. data/lib/reek.rb +8 -4
  72. data/reek.gemspec +9 -7
  73. data/spec/matchers/smell_of_matcher.rb +58 -0
  74. data/spec/reek/{help_command_spec.rb → cli/help_command_spec.rb} +3 -4
  75. data/spec/reek/cli/reek_command_spec.rb +46 -0
  76. data/spec/reek/cli/report_spec.rb +30 -0
  77. data/spec/reek/{version_command_spec.rb → cli/version_command_spec.rb} +3 -3
  78. data/spec/reek/cli/yaml_command_spec.rb +47 -0
  79. data/spec/reek/core/code_context_spec.rb +145 -0
  80. data/spec/reek/{code_parser_spec.rb → core/code_parser_spec.rb} +7 -6
  81. data/spec/reek/{config_spec.rb → core/config_spec.rb} +2 -6
  82. data/spec/reek/{method_context_spec.rb → core/method_context_spec.rb} +16 -36
  83. data/spec/reek/core/module_context_spec.rb +27 -0
  84. data/spec/reek/{object_refs_spec.rb → core/object_refs_spec.rb} +5 -6
  85. data/spec/reek/core/singleton_method_context_spec.rb +9 -0
  86. data/spec/reek/core/smell_configuration_spec.rb +11 -0
  87. data/spec/reek/core/stop_context_spec.rb +17 -0
  88. data/spec/reek/core/warning_collector_spec.rb +27 -0
  89. data/spec/reek/examiner_spec.rb +103 -0
  90. data/spec/reek/smell_warning_spec.rb +74 -82
  91. data/spec/reek/smells/attribute_spec.rb +42 -23
  92. data/spec/reek/smells/behaves_like_variable_detector.rb +2 -2
  93. data/spec/reek/smells/boolean_parameter_spec.rb +66 -0
  94. data/spec/reek/smells/class_variable_spec.rb +60 -75
  95. data/spec/reek/smells/control_couple_spec.rb +37 -32
  96. data/spec/reek/smells/data_clump_spec.rb +63 -24
  97. data/spec/reek/smells/duplication_spec.rb +106 -57
  98. data/spec/reek/smells/feature_envy_spec.rb +113 -92
  99. data/spec/reek/smells/irresponsible_module_spec.rb +58 -0
  100. data/spec/reek/smells/large_class_spec.rb +67 -57
  101. data/spec/reek/smells/long_method_spec.rb +40 -10
  102. data/spec/reek/smells/long_parameter_list_spec.rb +50 -28
  103. data/spec/reek/smells/long_yield_list_spec.rb +57 -0
  104. data/spec/reek/smells/nested_iterators_spec.rb +115 -7
  105. data/spec/reek/smells/simulated_polymorphism_spec.rb +56 -20
  106. data/spec/reek/smells/smell_detector_shared.rb +42 -0
  107. data/spec/reek/smells/uncommunicative_method_name_spec.rb +42 -0
  108. data/spec/reek/smells/uncommunicative_module_name_spec.rb +66 -0
  109. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +71 -0
  110. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +120 -0
  111. data/spec/reek/smells/utility_function_spec.rb +50 -4
  112. data/spec/reek/source/code_comment_spec.rb +82 -0
  113. data/spec/reek/source/object_source_spec.rb +20 -0
  114. data/spec/reek/source/reference_collector_spec.rb +53 -0
  115. data/spec/reek/{adapters/source_spec.rb → source/source_code_spec.rb} +7 -8
  116. data/spec/reek/source/tree_dresser_spec.rb +270 -0
  117. data/spec/reek/spec/should_reek_of_spec.rb +76 -0
  118. data/spec/reek/spec/should_reek_only_of_spec.rb +89 -0
  119. data/spec/reek/{adapters → spec}/should_reek_spec.rb +8 -32
  120. data/spec/samples/all_but_one_masked/clean_one.rb +1 -0
  121. data/spec/samples/all_but_one_masked/dirty.rb +1 -0
  122. data/spec/samples/all_but_one_masked/masked.reek +5 -1
  123. data/spec/samples/clean_due_to_masking/clean_one.rb +1 -0
  124. data/spec/samples/clean_due_to_masking/clean_three.rb +1 -0
  125. data/spec/samples/clean_due_to_masking/clean_two.rb +1 -0
  126. data/spec/samples/clean_due_to_masking/dirty_one.rb +1 -1
  127. data/spec/samples/clean_due_to_masking/dirty_two.rb +1 -1
  128. data/spec/samples/clean_due_to_masking/masked.reek +5 -1
  129. data/spec/samples/config/allow_duplication.reek +3 -0
  130. data/spec/samples/config/deeper_nested_iterators.reek +3 -0
  131. data/spec/samples/corrupt_config_file/dirty.rb +1 -1
  132. data/spec/samples/demo/demo.rb +8 -0
  133. data/spec/samples/empty_config_file/dirty.rb +2 -1
  134. data/spec/samples/exceptions.reek +1 -1
  135. data/spec/samples/inline_config/dirty.rb +16 -0
  136. data/spec/samples/inline_config/masked.reek +7 -0
  137. data/spec/samples/mask_some/dirty.rb +8 -0
  138. data/spec/samples/mask_some/some.reek +8 -0
  139. data/spec/samples/masked/dirty.rb +2 -1
  140. data/spec/samples/masked/masked.reek +3 -1
  141. data/spec/samples/mixed_results/clean_one.rb +1 -0
  142. data/spec/samples/mixed_results/clean_three.rb +1 -0
  143. data/spec/samples/mixed_results/clean_two.rb +1 -0
  144. data/spec/samples/mixed_results/dirty_one.rb +1 -0
  145. data/spec/samples/mixed_results/dirty_two.rb +1 -0
  146. data/spec/samples/not_quite_masked/dirty.rb +2 -1
  147. data/spec/samples/not_quite_masked/masked.reek +1 -1
  148. data/spec/samples/overrides/masked/dirty.rb +2 -1
  149. data/spec/samples/overrides/masked/lower.reek +3 -1
  150. data/spec/samples/three_clean_files/clean_one.rb +1 -0
  151. data/spec/samples/three_clean_files/clean_three.rb +1 -0
  152. data/spec/samples/three_clean_files/clean_two.rb +1 -0
  153. data/spec/samples/two_smelly_files/dirty_one.rb +2 -1
  154. data/spec/samples/two_smelly_files/dirty_two.rb +2 -1
  155. data/spec/spec_helper.rb +10 -2
  156. data/tasks/reek.rake +2 -2
  157. data/tasks/test.rake +12 -3
  158. metadata +121 -79
  159. data/README.rdoc +0 -84
  160. data/features/profile.feature +0 -34
  161. data/lib/reek/adapters/application.rb +0 -46
  162. data/lib/reek/adapters/command_line.rb +0 -77
  163. data/lib/reek/adapters/config_file.rb +0 -31
  164. data/lib/reek/adapters/core_extras.rb +0 -64
  165. data/lib/reek/adapters/rake_task.rb +0 -121
  166. data/lib/reek/adapters/report.rb +0 -86
  167. data/lib/reek/adapters/source.rb +0 -72
  168. data/lib/reek/adapters/spec.rb +0 -133
  169. data/lib/reek/block_context.rb +0 -62
  170. data/lib/reek/class_context.rb +0 -41
  171. data/lib/reek/code_context.rb +0 -68
  172. data/lib/reek/code_parser.rb +0 -203
  173. data/lib/reek/configuration.rb +0 -57
  174. data/lib/reek/detector_stack.rb +0 -37
  175. data/lib/reek/help_command.rb +0 -14
  176. data/lib/reek/if_context.rb +0 -18
  177. data/lib/reek/masking_collection.rb +0 -33
  178. data/lib/reek/method_context.rb +0 -138
  179. data/lib/reek/module_context.rb +0 -49
  180. data/lib/reek/name.rb +0 -57
  181. data/lib/reek/object_refs.rb +0 -49
  182. data/lib/reek/reek_command.rb +0 -28
  183. data/lib/reek/sexp_formatter.rb +0 -10
  184. data/lib/reek/singleton_method_context.rb +0 -26
  185. data/lib/reek/smells/uncommunicative_name.rb +0 -84
  186. data/lib/reek/sniffer.rb +0 -177
  187. data/lib/reek/stop_context.rb +0 -35
  188. data/lib/reek/tree_dresser.rb +0 -82
  189. data/lib/reek/version_command.rb +0 -14
  190. data/lib/reek/yield_call_context.rb +0 -12
  191. data/spec/reek/adapters/report_spec.rb +0 -31
  192. data/spec/reek/adapters/should_reek_of_spec.rb +0 -138
  193. data/spec/reek/adapters/should_reek_only_of_spec.rb +0 -87
  194. data/spec/reek/block_context_spec.rb +0 -65
  195. data/spec/reek/class_context_spec.rb +0 -161
  196. data/spec/reek/code_context_spec.rb +0 -182
  197. data/spec/reek/configuration_spec.rb +0 -12
  198. data/spec/reek/if_context_spec.rb +0 -17
  199. data/spec/reek/masking_collection_spec.rb +0 -236
  200. data/spec/reek/module_context_spec.rb +0 -46
  201. data/spec/reek/name_spec.rb +0 -37
  202. data/spec/reek/object_source_spec.rb +0 -23
  203. data/spec/reek/reek_command_spec.rb +0 -45
  204. data/spec/reek/singleton_method_context_spec.rb +0 -16
  205. data/spec/reek/smells/smell_detector_spec.rb +0 -36
  206. data/spec/reek/smells/uncommunicative_name_spec.rb +0 -146
  207. data/spec/reek/sniffer_spec.rb +0 -11
  208. data/spec/reek/stop_context_spec.rb +0 -33
  209. data/spec/reek/tree_dresser_spec.rb +0 -20
@@ -1,33 +1,10 @@
1
- require File.dirname(__FILE__) + '/../spec_helper.rb'
2
-
3
- require 'reek/smell_warning'
4
- require 'reek/smells/feature_envy'
1
+ require File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'spec_helper')
2
+ require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'lib', 'reek', 'smell_warning')
5
3
 
6
4
  include Reek
7
5
 
8
6
  describe SmellWarning do
9
7
  context 'sort order' do
10
- context 'smells differing only by masking' do
11
- before :each do
12
- @first = SmellWarning.new(Smells::FeatureEnvy.new, "self", 27, "self", true)
13
- @second = SmellWarning.new(Smells::FeatureEnvy.new, "self", 27, "self", false)
14
- end
15
-
16
- it 'should hash equal when the smell is the same' do
17
- @first.hash.should == @second.hash
18
- end
19
- it 'should compare equal when the smell is the same' do
20
- @first.should == @second
21
- end
22
- it 'should compare equal when using <=>' do
23
- (@first <=> @second).should == 0
24
- end
25
- it 'matches using eql?' do
26
- @first.should eql(@second)
27
- @second.should eql(@first)
28
- end
29
- end
30
-
31
8
  shared_examples_for 'first sorts ahead of second' do
32
9
  it 'hash differently' do
33
10
  @first.hash.should_not == @second.hash
@@ -46,8 +23,8 @@ describe SmellWarning do
46
23
 
47
24
  context 'smells differing only by detector' do
48
25
  before :each do
49
- @first = SmellWarning.new(Smells::Duplication.new, "self", 27, "self", false)
50
- @second = SmellWarning.new(Smells::FeatureEnvy.new, "self", 27, "self", true)
26
+ @first = SmellWarning.new('Duplication', "self", 27, "self", false)
27
+ @second = SmellWarning.new('FeatureEnvy', "self", 27, "self", true)
51
28
  end
52
29
 
53
30
  it_should_behave_like 'first sorts ahead of second'
@@ -55,8 +32,8 @@ describe SmellWarning do
55
32
 
56
33
  context 'smells differing only by context' do
57
34
  before :each do
58
- @first = SmellWarning.new(Smells::FeatureEnvy.new, "first", 27, "self", true)
59
- @second = SmellWarning.new(Smells::FeatureEnvy.new, "second", 27, "self", false)
35
+ @first = SmellWarning.new('FeatureEnvy', "first", 27, "self", true)
36
+ @second = SmellWarning.new('FeatureEnvy', "second", 27, "self", false)
60
37
  end
61
38
 
62
39
  it_should_behave_like 'first sorts ahead of second'
@@ -64,8 +41,8 @@ describe SmellWarning do
64
41
 
65
42
  context 'smells differing only by message' do
66
43
  before :each do
67
- @first = SmellWarning.new(Smells::FeatureEnvy.new, "context", 27, "first", true)
68
- @second = SmellWarning.new(Smells::FeatureEnvy.new, "context", 27, "second", false)
44
+ @first = SmellWarning.new('FeatureEnvy', "context", 27, "first", true)
45
+ @second = SmellWarning.new('FeatureEnvy', "context", 27, "second", false)
69
46
  end
70
47
 
71
48
  it_should_behave_like 'first sorts ahead of second'
@@ -73,8 +50,8 @@ describe SmellWarning do
73
50
 
74
51
  context 'message takes precedence over smell name' do
75
52
  before :each do
76
- @first = SmellWarning.new(Smells::UtilityFunction.new, "context", 27, "first", true)
77
- @second = SmellWarning.new(Smells::FeatureEnvy.new, "context", 27, "second", false)
53
+ @first = SmellWarning.new('UtilityFunction', "context", 27, "first", true)
54
+ @second = SmellWarning.new('FeatureEnvy', "context", 27, "second", false)
78
55
  end
79
56
 
80
57
  it_should_behave_like 'first sorts ahead of second'
@@ -82,70 +59,85 @@ describe SmellWarning do
82
59
 
83
60
  context 'smells differing everywhere' do
84
61
  before :each do
85
- @first = SmellWarning.new(Smells::UncommunicativeName.new, "Dirty", 27, "has the variable name '@s'", true)
86
- @second = SmellWarning.new(Smells::Duplication.new, 'Dirty#a', 27, "calls @s.title twice", false)
62
+ @first = SmellWarning.new('UncommunicativeName', "Dirty", 27, "has the variable name '@s'", true)
63
+ @second = SmellWarning.new('Duplication', 'Dirty#a', 27, "calls @s.title twice", false)
87
64
  end
88
65
 
89
66
  it_should_behave_like 'first sorts ahead of second'
90
67
  end
91
68
  end
92
69
 
93
- context 'masked reporting' do
94
- class CountingReport
95
- attr_reader :masked, :non_masked
96
- def initialize
97
- @masked = @non_masked = 0
70
+ context 'YAML representation' do
71
+ before :each do
72
+ @message = 'test message'
73
+ @lines = [24, 513]
74
+ @class = 'FeatureEnvy'
75
+ @context_name = 'Module::Class#method/block'
76
+ # Use a random string and a random bool
77
+ end
78
+
79
+ shared_examples_for 'common fields' do
80
+ it 'includes the smell class' do
81
+ @yaml.should match(/class:\s*FeatureEnvy/)
98
82
  end
99
- def found_smell(sw)
100
- @non_masked += 1
83
+ it 'includes the context' do
84
+ @yaml.should match(/context:\s*#{@context_name}/)
101
85
  end
102
-
103
- def found_masked_smell(sw)
104
- @masked += 1
86
+ it 'includes the message' do
87
+ @yaml.should match(/message:\s*#{@message}/)
88
+ end
89
+ it 'indicates the masking' do
90
+ @yaml.should match(/is_active:\s*true/)
91
+ end
92
+ it 'includes the line numbers' do
93
+ @lines.each do |line|
94
+ @yaml.should match(/lines:[\s\d-]*- #{line}/)
95
+ end
105
96
  end
106
97
  end
107
98
 
108
- before :each do
109
- @masked = SmellWarning.new(Smells::FeatureEnvy.new, 'Fred', 27, "self", true)
110
- @visible = SmellWarning.new(Smells::FeatureEnvy.new, 'Fred', 27, "self", false)
111
- end
99
+ context 'with all details specified' do
100
+ before :each do
101
+ @source = 'a/ruby/source/file.rb'
102
+ @subclass = 'TooManyParties'
103
+ @parameters = {'one' => 34, 'two' => 'second'}
104
+ @warning = SmellWarning.new(@class, @context_name, @lines, @message,
105
+ @source, @subclass, @parameters)
106
+ @yaml = @warning.to_yaml
107
+ end
112
108
 
113
- it 'reports as masked when masked' do
114
- rpt = CountingReport.new
115
- @masked.report_on(rpt)
116
- rpt.masked.should == 1
117
- rpt.non_masked.should == 0
118
- end
109
+ it_should_behave_like 'common fields'
119
110
 
120
- it 'reports as non-masked when non-masked' do
121
- rpt = CountingReport.new
122
- @visible.report_on(rpt)
123
- rpt.masked.should == 0
124
- rpt.non_masked.should == 1
111
+ it 'includes the subclass' do
112
+ @yaml.should match(/subclass:\s*#{@subclass}/)
113
+ end
114
+ it 'includes the source' do
115
+ @yaml.should match(/source:\s*#{@source}/)
116
+ end
117
+ it 'includes the parameters' do
118
+ @parameters.each do |key,value|
119
+ @yaml.should match(/#{key}:\s*#{value}/)
120
+ end
121
+ end
125
122
  end
126
- end
127
123
 
128
- context 'YAML representation' do
129
- before :each do
130
- @message = 'message'
131
- # Use a random string and a random bool
132
- warning = SmellWarning.new(Smells::FeatureEnvy.new, 'Fred', 27, @message, true)
133
- @yaml = warning.to_yaml
134
- end
135
- it 'includes the smell class' do
136
- @yaml.should match(/smell:\s*FeatureEnvy/)
137
- end
138
- it 'includes the context' do
139
- @yaml.should match(/context:\s*Fred/)
140
- end
141
- it 'includes the message' do
142
- @yaml.should match(/message:\s*#{@message}/)
143
- end
144
- it 'indicates the masking' do
145
- @yaml.should match(/is_masked:\s*true/)
146
- end
147
- it 'includes the line number' do
148
- @yaml.should match(/line:\s*27/)
124
+ context 'with all defaults used' do
125
+ before :each do
126
+ warning = SmellWarning.new(@class, @context_name, @lines, @message)
127
+ @yaml = warning.to_yaml
128
+ end
129
+
130
+ it_should_behave_like 'common fields'
131
+
132
+ it 'includes no subclass' do
133
+ @yaml.should match(/subclass:\s*""/)
134
+ end
135
+ it 'includes no source' do
136
+ @yaml.should match(/source:\s*""/)
137
+ end
138
+ it 'includes empty parameters' do
139
+ @yaml.should_not match(/parameter/)
140
+ end
149
141
  end
150
142
  end
151
143
  end
@@ -1,39 +1,58 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper.rb'
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', 'smells', 'attribute')
3
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'module_context')
4
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
2
5
 
3
- require 'reek/smells/attribute'
4
- require 'reek/class_context'
5
-
6
- include Reek
6
+ include Reek::Core
7
7
  include Reek::Smells
8
8
 
9
9
  describe Attribute do
10
10
  before :each do
11
- @detector = Attribute.new
11
+ @source_name = 'ticker'
12
+ @detector = Attribute.new(@source_name)
12
13
  end
14
+
15
+ it_should_behave_like 'SmellDetector'
16
+
13
17
  context 'with no attributes' do
14
- it 'records nothing in the class' do
15
- ctx = ClassContext.from_s('class Fred; end')
16
- @detector.attributes_in(ctx).should be_empty
17
- end
18
18
  it 'records nothing in the module' do
19
- ctx = ModuleContext.from_s('module Fred; end')
20
- @detector.attributes_in(ctx).should be_empty
19
+ src = 'module Fred; end'
20
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
21
+ @detector.examine_context(ctx).should be_empty
21
22
  end
22
23
  end
23
24
 
24
25
  context 'with one attribute' do
26
+ before :each do
27
+ @attr_name = 'super_thing'
28
+ end
29
+
25
30
  shared_examples_for 'one attribute found' do
26
- it 'records the attribute' do
27
- @detector.attributes_in(@ctx).should include(:property)
31
+ before :each do
32
+ ctx = CodeContext.new(nil, @src.to_reek_source.syntax_tree)
33
+ @smells = @detector.examine_context(ctx)
28
34
  end
35
+
29
36
  it 'records only that attribute' do
30
- @detector.attributes_in(@ctx).length.should == 1
37
+ @smells.length.should == 1
38
+ end
39
+ it 'reports the attribute name' do
40
+ @smells[0].smell[Attribute::ATTRIBUTE_KEY].should == @attr_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 == Attribute::SMELL_CLASS
47
+ end
48
+ it 'reports the context fq name' do
49
+ @smells[0].context.should == 'Fred'
31
50
  end
32
51
  end
33
52
 
34
53
  context 'declared in a class' do
35
54
  before :each do
36
- @ctx = ClassContext.from_s('class Fred; attr :property; end')
55
+ @src = "class Fred; attr :#{@attr_name}; end"
37
56
  end
38
57
 
39
58
  it_should_behave_like 'one attribute found'
@@ -41,7 +60,7 @@ describe Attribute do
41
60
 
42
61
  context 'reader in a class' do
43
62
  before :each do
44
- @ctx = ClassContext.from_s('class Fred; attr_reader :property; end')
63
+ @src = "class Fred; attr_reader :#{@attr_name}; end"
45
64
  end
46
65
 
47
66
  it_should_behave_like 'one attribute found'
@@ -49,7 +68,7 @@ describe Attribute do
49
68
 
50
69
  context 'writer in a class' do
51
70
  before :each do
52
- @ctx = ClassContext.from_s('class Fred; attr_writer :property; end')
71
+ @src = "class Fred; attr_writer :#{@attr_name}; end"
53
72
  end
54
73
 
55
74
  it_should_behave_like 'one attribute found'
@@ -57,7 +76,7 @@ describe Attribute do
57
76
 
58
77
  context 'accessor in a class' do
59
78
  before :each do
60
- @ctx = ClassContext.from_s('class Fred; attr_accessor :property; end')
79
+ @src = "class Fred; attr_accessor :#{@attr_name}; end"
61
80
  end
62
81
 
63
82
  it_should_behave_like 'one attribute found'
@@ -65,7 +84,7 @@ describe Attribute do
65
84
 
66
85
  context 'declared in a module' do
67
86
  before :each do
68
- @ctx = ModuleContext.from_s('module Fred; attr :property; end')
87
+ @src = "module Fred; attr :#{@attr_name}; end"
69
88
  end
70
89
 
71
90
  it_should_behave_like 'one attribute found'
@@ -73,7 +92,7 @@ describe Attribute do
73
92
 
74
93
  context 'reader in a module' do
75
94
  before :each do
76
- @ctx = ModuleContext.from_s('module Fred; attr_reader :property; end')
95
+ @src = "module Fred; attr_reader :#{@attr_name}; end"
77
96
  end
78
97
 
79
98
  it_should_behave_like 'one attribute found'
@@ -81,7 +100,7 @@ describe Attribute do
81
100
 
82
101
  context 'writer in a module' do
83
102
  before :each do
84
- @ctx = ModuleContext.from_s('module Fred; attr_writer :property; end')
103
+ @src = "module Fred; attr_writer :#{@attr_name}; end"
85
104
  end
86
105
 
87
106
  it_should_behave_like 'one attribute found'
@@ -89,7 +108,7 @@ describe Attribute do
89
108
 
90
109
  context 'accessor in a module' do
91
110
  before :each do
92
- @ctx = ModuleContext.from_s('module Fred; attr_accessor :property; end')
111
+ @src = "module Fred; attr_accessor :#{@attr_name}; end"
93
112
  end
94
113
 
95
114
  it_should_behave_like 'one attribute found'
@@ -2,7 +2,7 @@ shared_examples_for 'a variable detector' do
2
2
  context 'with no variables' do
3
3
  it "doesn't record a smell" do
4
4
  @detector.examine_context(@ctx)
5
- @detector.num_smells.should == 0
5
+ @detector.smells_found.length.should == 0
6
6
  end
7
7
  end
8
8
 
@@ -14,7 +14,7 @@ shared_examples_for 'a variable detector' do
14
14
  end
15
15
 
16
16
  it 'records only one smell' do
17
- @detector.num_smells.should == 1
17
+ @detector.smells_found.length.should == 1
18
18
  end
19
19
  it 'mentions the variable name in the report' do
20
20
  @detector.should have_smell([/something/])
@@ -0,0 +1,66 @@
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', 'smells', 'boolean_parameter')
3
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
4
+
5
+ include Reek::Smells
6
+
7
+ describe BooleanParameter do
8
+ context 'parameter defaulted with boolean' do
9
+ context 'in a method' do
10
+ it 'reports a parameter defaulted to true' do
11
+ src = 'def cc(arga = true) end'
12
+ src.should smell_of(BooleanParameter, BooleanParameter::PARAMETER_KEY => 'arga')
13
+ end
14
+ it 'reports a parameter defaulted to false' do
15
+ src = 'def cc(arga = false) end'
16
+ src.should smell_of(BooleanParameter, BooleanParameter::PARAMETER_KEY => 'arga')
17
+ end
18
+ it 'reports two parameters defaulted to booleans' do
19
+ src = 'def cc(nowt, arga = true, argb = false, &blk) end'
20
+ src.should smell_of(BooleanParameter,
21
+ {BooleanParameter::PARAMETER_KEY => 'arga'},
22
+ {BooleanParameter::PARAMETER_KEY => 'argb'})
23
+ end
24
+ end
25
+
26
+ context 'in a singleton method' do
27
+ it 'reports a parameter defaulted to true' do
28
+ src = 'def self.cc(arga = true) end'
29
+ src.should smell_of(BooleanParameter, BooleanParameter::PARAMETER_KEY => 'arga')
30
+ end
31
+ it 'reports a parameter defaulted to false' do
32
+ src = 'def fred.cc(arga = false) end'
33
+ src.should smell_of(BooleanParameter, BooleanParameter::PARAMETER_KEY => 'arga')
34
+ end
35
+ it 'reports two parameters defaulted to booleans' do
36
+ src = 'def Module.cc(nowt, arga = true, argb = false, &blk) end'
37
+ src.should smell_of(BooleanParameter,
38
+ {BooleanParameter::PARAMETER_KEY => 'arga'},
39
+ {BooleanParameter::PARAMETER_KEY => 'argb'})
40
+ end
41
+ end
42
+ end
43
+
44
+ context 'when a smell is reported' do
45
+ before(:each) do
46
+ @source_name = 'smokin'
47
+ @detector = BooleanParameter.new(@source_name)
48
+ end
49
+
50
+ it_should_behave_like 'SmellDetector'
51
+
52
+ it 'reports the fields correctly' do
53
+ src = 'def cc(arga = true) end'
54
+ ctx = MethodContext.new(nil, src.to_reek_source.syntax_tree)
55
+ @detector.examine(ctx)
56
+ smells = @detector.smells_found.to_a
57
+ smells.length.should == 1
58
+ smells[0].smell_class.should == BooleanParameter::SMELL_CLASS
59
+ smells[0].smell[BooleanParameter::PARAMETER_KEY].should == 'arga'
60
+ smells[0].source.should == @source_name
61
+ smells[0].smell_class.should == BooleanParameter::SMELL_CLASS
62
+ smells[0].subclass.should == BooleanParameter::SMELL_SUBCLASS
63
+ smells[0].lines.should == [1]
64
+ end
65
+ end
66
+ end
@@ -1,115 +1,100 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper.rb'
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', 'smells', 'class_variable')
3
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'module_context')
4
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
2
5
 
3
- require 'reek/smells/class_variable'
4
- require 'reek/class_context'
5
-
6
- include Reek
6
+ include Reek::Core
7
7
  include Reek::Smells
8
8
 
9
9
  describe ClassVariable do
10
10
  before :each do
11
- @detector = ClassVariable.new
11
+ @source_name = 'raffles'
12
+ @detector = ClassVariable.new(@source_name)
13
+ @class_variable = '@@things'
12
14
  end
13
15
 
16
+ it_should_behave_like 'SmellDetector'
17
+
14
18
  context 'with no class variables' do
15
19
  it 'records nothing in the class' do
16
- ctx = ClassContext.from_s('class Fred; end')
17
- @detector.class_variables_in(ctx).should be_empty
20
+ exp = ast(:class, :Fred)
21
+ @detector.examine_context(CodeContext.new(nil, exp)).should be_empty
18
22
  end
19
23
  it 'records nothing in the module' do
20
- ctx = ModuleContext.from_s('module Fred; end')
21
- @detector.class_variables_in(ctx).should be_empty
24
+ exp = ast(:module, :Fred)
25
+ @detector.examine_context(CodeContext.new(nil, exp)).should be_empty
22
26
  end
23
27
  end
24
28
 
25
29
  context 'with one class variable' do
26
30
  shared_examples_for 'one variable found' do
27
- it 'records the class variable' do
28
- @detector.class_variables_in(@ctx).should include(:@@tools)
31
+ before :each do
32
+ ast = @src.to_reek_source.syntax_tree
33
+ @smells = @detector.examine_context(CodeContext.new(nil, ast))
29
34
  end
30
35
  it 'records only that class variable' do
31
- @detector.class_variables_in(@ctx).length.should == 1
36
+ @smells.length.should == 1
32
37
  end
33
- end
34
-
35
- context 'declared in a class' do
36
- before :each do
37
- @ctx = ClassContext.from_s('class Fred; @@tools = {}; end')
38
+ it 'records the variable name' do
39
+ @smells[0].smell[ClassVariable::VARIABLE_KEY].should == @class_variable
38
40
  end
39
-
40
- it_should_behave_like 'one variable found'
41
41
  end
42
42
 
43
- context 'used in a class' do
44
- before :each do
45
- @ctx = ClassContext.from_s('class Fred; def jim() @@tools = {}; end; end')
46
- end
43
+ ['class', 'module'].each do |scope|
44
+ context "declared in a #{scope}" do
45
+ before :each do
46
+ @src = "#{scope} Fred; #{@class_variable} = {}; end"
47
+ end
47
48
 
48
- it_should_behave_like 'one variable found'
49
- end
50
-
51
- context 'indexed in a class' do
52
- before :each do
53
- @ctx = ClassContext.from_s('class Fred; def jim() @@tools[mash] = {}; end; end')
49
+ it_should_behave_like 'one variable found'
54
50
  end
55
51
 
56
- it_should_behave_like 'one variable found'
57
- end
52
+ context "used in a #{scope}" do
53
+ before :each do
54
+ @src = "#{scope} Fred; def jim() #{@class_variable} = {}; end; end"
55
+ end
58
56
 
59
- context 'declared and used in a class' do
60
- before :each do
61
- @ctx = ClassContext.from_s('class Fred; @@tools = {}; def jim() @@tools = {}; end; end')
57
+ it_should_behave_like 'one variable found'
62
58
  end
63
59
 
64
- it_should_behave_like 'one variable found'
65
- end
60
+ context "indexed in a #{scope}" do
61
+ before :each do
62
+ @src = "#{scope} Fred; def jim() #{@class_variable}[mash] = {}; end; end"
63
+ end
66
64
 
67
- context 'used twice in a class' do
68
- before :each do
69
- @ctx = ClassContext.from_s('class Fred; def jeff() @@tools = {}; end; def jim() @@tools = {}; end; end')
65
+ it_should_behave_like 'one variable found'
70
66
  end
71
67
 
72
- it_should_behave_like 'one variable found'
73
- end
68
+ context "declared and used in a #{scope}" do
69
+ before :each do
70
+ @src = "#{scope} Fred; #{@class_variable} = {}; def jim() #{@class_variable} = {}; end; end"
71
+ end
74
72
 
75
- context 'declared in a module' do
76
- before :each do
77
- @ctx = ClassContext.from_s('module Fred; @@tools = {}; end')
73
+ it_should_behave_like 'one variable found'
78
74
  end
79
75
 
80
- it_should_behave_like 'one variable found'
81
- end
76
+ context "used twice in a #{scope}" do
77
+ before :each do
78
+ @src = "#{scope} Fred; def jeff() #{@class_variable} = {}; end; def jim() #{@class_variable} = {}; end; end"
79
+ end
82
80
 
83
- context 'used in a module' do
84
- before :each do
85
- @ctx = ClassContext.from_s('module Fred; def jim() @@tools = {}; end; end')
86
- end
87
-
88
- it_should_behave_like 'one variable found'
89
- end
90
-
91
- context 'indexed in a module' do
92
- before :each do
93
- @ctx = ClassContext.from_s('module Fred; def jim() @@tools[mash] = {}; end; end')
94
- end
95
-
96
- it_should_behave_like 'one variable found'
97
- end
98
-
99
- context 'declared and used in a module' do
100
- before :each do
101
- @ctx = ClassContext.from_s('module Fred; @@tools = {}; def jim() @@tools = {}; end; end')
81
+ it_should_behave_like 'one variable found'
102
82
  end
103
-
104
- it_should_behave_like 'one variable found'
105
83
  end
84
+ end
106
85
 
107
- context 'used twice in a module' do
108
- before :each do
109
- @ctx = ClassContext.from_s('module Fred; def jeff() @@tools = {}; end; def jim() @@tools = {}; end; end')
110
- end
111
-
112
- it_should_behave_like 'one variable found'
113
- end
86
+ it 'reports the correct fields' do
87
+ src = <<EOS
88
+ module Fred
89
+ #{@class_variable} = {}
90
+ end
91
+ EOS
92
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
93
+ @warning = @detector.examine_context(ctx)[0]
94
+ @warning.source.should == @source_name
95
+ @warning.smell_class.should == ClassVariable::SMELL_CLASS
96
+ @warning.subclass.should == ClassVariable::SMELL_SUBCLASS
97
+ @warning.smell[ClassVariable::VARIABLE_KEY].should == @class_variable
98
+ @warning.lines.should == [2]
114
99
  end
115
100
  end