reek 1.1.3 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. data/History.txt +44 -4
  2. data/License.txt +20 -0
  3. data/README.rdoc +83 -0
  4. data/Rakefile +0 -1
  5. data/bin/reek +3 -11
  6. data/config/defaults.reek +20 -1
  7. data/features/masking_smells.feature +111 -0
  8. data/features/options.feature +49 -0
  9. data/features/reports.feature +90 -0
  10. data/features/samples.feature +284 -0
  11. data/features/stdin.feature +43 -0
  12. data/features/step_definitions/reek_steps.rb +35 -0
  13. data/features/support/env.rb +38 -0
  14. data/lib/reek.rb +1 -1
  15. data/lib/reek/adapters/application.rb +47 -0
  16. data/lib/reek/adapters/config_file.rb +31 -0
  17. data/lib/reek/adapters/core_extras.rb +72 -0
  18. data/lib/reek/{object_source.rb → adapters/object_source.rb} +15 -19
  19. data/lib/reek/{rake_task.rb → adapters/rake_task.rb} +2 -2
  20. data/lib/reek/adapters/report.rb +91 -0
  21. data/lib/reek/adapters/source.rb +53 -0
  22. data/lib/reek/{spec.rb → adapters/spec.rb} +45 -60
  23. data/lib/reek/block_context.rb +1 -1
  24. data/lib/reek/class_context.rb +26 -6
  25. data/lib/reek/code_context.rb +8 -0
  26. data/lib/reek/code_parser.rb +82 -39
  27. data/lib/reek/command_line.rb +85 -0
  28. data/lib/reek/configuration.rb +51 -0
  29. data/lib/reek/detector_stack.rb +39 -0
  30. data/lib/reek/exceptions.reek +8 -1
  31. data/lib/reek/method_context.rb +53 -11
  32. data/lib/reek/module_context.rb +1 -2
  33. data/lib/reek/name.rb +8 -2
  34. data/lib/reek/sexp_formatter.rb +2 -0
  35. data/lib/reek/smell_warning.rb +26 -8
  36. data/lib/reek/smells/control_couple.rb +8 -4
  37. data/lib/reek/smells/data_clump.rb +88 -0
  38. data/lib/reek/smells/duplication.rb +11 -9
  39. data/lib/reek/smells/feature_envy.rb +3 -4
  40. data/lib/reek/smells/large_class.rb +17 -17
  41. data/lib/reek/smells/long_method.rb +10 -8
  42. data/lib/reek/smells/long_parameter_list.rb +16 -10
  43. data/lib/reek/smells/long_yield_list.rb +1 -1
  44. data/lib/reek/smells/nested_iterators.rb +3 -3
  45. data/lib/reek/smells/simulated_polymorphism.rb +58 -0
  46. data/lib/reek/smells/smell_detector.rb +94 -27
  47. data/lib/reek/smells/uncommunicative_name.rb +23 -23
  48. data/lib/reek/smells/utility_function.rb +27 -11
  49. data/lib/reek/sniffer.rb +183 -0
  50. data/reek.gemspec +5 -5
  51. data/spec/quality/reek_source_spec.rb +15 -0
  52. data/spec/reek/adapters/report_spec.rb +49 -0
  53. data/spec/reek/adapters/should_reek_of_spec.rb +108 -0
  54. data/spec/reek/adapters/should_reek_only_of_spec.rb +87 -0
  55. data/spec/reek/adapters/should_reek_spec.rb +92 -0
  56. data/spec/reek/block_context_spec.rb +7 -1
  57. data/spec/reek/class_context_spec.rb +39 -16
  58. data/spec/reek/code_context_spec.rb +7 -7
  59. data/spec/reek/code_parser_spec.rb +6 -1
  60. data/spec/reek/config_spec.rb +3 -3
  61. data/spec/reek/configuration_spec.rb +12 -0
  62. data/spec/reek/method_context_spec.rb +2 -2
  63. data/spec/reek/name_spec.rb +24 -0
  64. data/spec/reek/object_source_spec.rb +23 -0
  65. data/spec/reek/singleton_method_context_spec.rb +2 -2
  66. data/spec/reek/smell_warning_spec.rb +53 -0
  67. data/spec/reek/smells/data_clump_spec.rb +87 -0
  68. data/spec/reek/smells/duplication_spec.rb +13 -17
  69. data/spec/reek/smells/feature_envy_spec.rb +23 -28
  70. data/spec/reek/smells/large_class_spec.rb +109 -34
  71. data/spec/reek/smells/long_method_spec.rb +140 -3
  72. data/spec/reek/smells/long_parameter_list_spec.rb +1 -2
  73. data/spec/reek/smells/simulated_polymorphism_spec.rb +50 -0
  74. data/spec/reek/smells/smell_detector_spec.rb +53 -0
  75. data/spec/reek/smells/uncommunicative_name_spec.rb +20 -7
  76. data/spec/reek/smells/utility_function_spec.rb +76 -67
  77. data/spec/reek/sniffer_spec.rb +10 -0
  78. data/spec/samples/all_but_one_masked/clean_one.rb +6 -0
  79. data/spec/samples/all_but_one_masked/dirty.rb +7 -0
  80. data/spec/samples/all_but_one_masked/masked.reek +5 -0
  81. data/spec/samples/clean_due_to_masking/clean_one.rb +6 -0
  82. data/spec/samples/clean_due_to_masking/clean_three.rb +6 -0
  83. data/spec/samples/clean_due_to_masking/clean_two.rb +6 -0
  84. data/spec/samples/clean_due_to_masking/dirty_one.rb +7 -0
  85. data/spec/samples/clean_due_to_masking/dirty_two.rb +7 -0
  86. data/spec/samples/clean_due_to_masking/masked.reek +7 -0
  87. data/spec/samples/corrupt_config_file/corrupt.reek +1 -0
  88. data/spec/samples/corrupt_config_file/dirty.rb +7 -0
  89. data/spec/samples/empty_config_file/dirty.rb +7 -0
  90. data/spec/samples/empty_config_file/empty.reek +0 -0
  91. data/spec/samples/exceptions.reek +4 -0
  92. data/spec/{slow/samples → samples}/inline.rb +0 -0
  93. data/spec/samples/masked/dirty.rb +7 -0
  94. data/spec/samples/masked/masked.reek +3 -0
  95. data/spec/samples/mixed_results/clean_one.rb +6 -0
  96. data/spec/samples/mixed_results/clean_three.rb +6 -0
  97. data/spec/samples/mixed_results/clean_two.rb +6 -0
  98. data/spec/samples/mixed_results/dirty_one.rb +7 -0
  99. data/spec/samples/mixed_results/dirty_two.rb +7 -0
  100. data/spec/samples/not_quite_masked/dirty.rb +8 -0
  101. data/spec/samples/not_quite_masked/masked.reek +5 -0
  102. data/spec/{slow/samples → samples}/optparse.rb +0 -0
  103. data/spec/samples/overrides/masked/dirty.rb +7 -0
  104. data/spec/samples/overrides/masked/lower.reek +5 -0
  105. data/spec/samples/overrides/upper.reek +5 -0
  106. data/spec/{slow/samples → samples}/redcloth.rb +0 -0
  107. data/spec/samples/three_clean_files/clean_one.rb +6 -0
  108. data/spec/samples/three_clean_files/clean_three.rb +6 -0
  109. data/spec/samples/three_clean_files/clean_two.rb +6 -0
  110. data/spec/samples/two_smelly_files/dirty_one.rb +7 -0
  111. data/spec/samples/two_smelly_files/dirty_two.rb +7 -0
  112. data/spec/spec.opts +1 -1
  113. data/spec/spec_helper.rb +4 -4
  114. data/tasks/reek.rake +8 -5
  115. data/tasks/test.rake +51 -0
  116. metadata +75 -25
  117. data/README.txt +0 -6
  118. data/lib/reek/options.rb +0 -92
  119. data/lib/reek/report.rb +0 -81
  120. data/lib/reek/smells/smells.rb +0 -81
  121. data/lib/reek/source.rb +0 -127
  122. data/spec/reek/options_spec.rb +0 -13
  123. data/spec/reek/report_spec.rb +0 -48
  124. data/spec/reek/smells/smell_spec.rb +0 -24
  125. data/spec/slow/inline_spec.rb +0 -43
  126. data/spec/slow/optparse_spec.rb +0 -108
  127. data/spec/slow/redcloth_spec.rb +0 -101
  128. data/spec/slow/reek_source_spec.rb +0 -20
  129. data/spec/slow/script_spec.rb +0 -55
  130. data/spec/slow/source_list_spec.rb +0 -40
  131. data/tasks/rspec.rake +0 -21
@@ -0,0 +1,284 @@
1
+ @samples
2
+ Feature: Basic smell detection
3
+ In order to write better software
4
+ As a developer
5
+ I want to detect the smels in my Ruby code
6
+
7
+ Scenario: Correct smells from inline.rb
8
+ When I run reek spec/samples/inline.rb
9
+ Then it fails with exit status 2
10
+ And it reports:
11
+ """
12
+ spec/samples/inline.rb -- 36 warnings (+1 masked):
13
+ Inline::C has at least 13 instance variables (Large Class)
14
+ Inline::C takes parameters [options, src] to 5 methods (Data Clump)
15
+ Inline::C tests $DEBUG at least 7 times (Simulated Polymorphism)
16
+ Inline::C tests $TESTING at least 4 times (Simulated Polymorphism)
17
+ Inline::C tests @@type_map.has_key?(type) at least 3 times (Simulated Polymorphism)
18
+ Inline::C#build calls ($? == 0) twice (Duplication)
19
+ Inline::C#build calls Inline.directory 5 times (Duplication)
20
+ Inline::C#build calls io.puts 6 times (Duplication)
21
+ Inline::C#build calls io.puts("#endif") twice (Duplication)
22
+ Inline::C#build calls io.puts("#ifdef __cplusplus") twice (Duplication)
23
+ Inline::C#build calls module_name twice (Duplication)
24
+ Inline::C#build calls warn("Output:\n#{result}") twice (Duplication)
25
+ Inline::C#build has approx 60 statements (Long Method)
26
+ Inline::C#build has the variable name 't' (Uncommunicative Name)
27
+ Inline::C#build/block/block has the variable name 'n' (Uncommunicative Name)
28
+ Inline::C#build/block/block is nested (Nested Iterators)
29
+ Inline::C#c has the name 'c' (Uncommunicative Name)
30
+ Inline::C#crap_for_windoze calls Config::CONFIG["libdir"] twice (Duplication)
31
+ Inline::C#generate calls result.sub!(/\A\n/, "") twice (Duplication)
32
+ Inline::C#generate calls signature["args"] twice (Duplication)
33
+ Inline::C#generate calls signature["args"].map twice (Duplication)
34
+ Inline::C#generate has approx 32 statements (Long Method)
35
+ Inline::C#initialize calls stack.empty? twice (Duplication)
36
+ Inline::C#load calls so_name twice (Duplication)
37
+ Inline::C#module_name/block has the variable name 'm' (Uncommunicative Name)
38
+ Inline::C#module_name/block has the variable name 'x' (Uncommunicative Name)
39
+ Inline::C#parse_signature has approx 15 statements (Long Method)
40
+ Inline::C#parse_signature is controlled by argument raw (Control Couple)
41
+ Inline::C#parse_signature/block has the variable name 'x' (Uncommunicative Name)
42
+ Inline::C#strip_comments doesn't depend on instance state (Utility Function)
43
+ Inline::C#strip_comments refers to src more than self (Feature Envy)
44
+ Inline::self.rootdir calls env.nil? twice (Duplication)
45
+ Inline::self.rootdir has approx 8 statements (Long Method)
46
+ Module#inline calls Inline.const_get(lang) twice (Duplication)
47
+ Module#inline has approx 11 statements (Long Method)
48
+ Module#inline is controlled by argument options (Control Couple)
49
+
50
+ """
51
+
52
+ Scenario: Correct smells from optparse.rb
53
+ When I run reek spec/samples/optparse.rb
54
+ Then it fails with exit status 2
55
+ And it reports:
56
+ """
57
+ spec/samples/optparse.rb -- 121 warnings:
58
+ OptionParser has at least 59 methods (Large Class)
59
+ OptionParser tests ((argv.size == 1) and Array.===(argv[0])) at least 3 times (Simulated Polymorphism)
60
+ OptionParser tests a at least 7 times (Simulated Polymorphism)
61
+ OptionParser tests default_pattern at least 7 times (Simulated Polymorphism)
62
+ OptionParser tests not_style at least 3 times (Simulated Polymorphism)
63
+ OptionParser tests s at least 7 times (Simulated Polymorphism)
64
+ OptionParser#CompletingHash#match/block/block is nested (Nested Iterators)
65
+ OptionParser#Completion::complete calls candidates.size twice (Duplication)
66
+ OptionParser#Completion::complete calls k.id2name twice (Duplication)
67
+ OptionParser#Completion::complete has approx 22 statements (Long Method)
68
+ OptionParser#Completion::complete has the variable name 'k' (Uncommunicative Name)
69
+ OptionParser#Completion::complete has the variable name 'v' (Uncommunicative Name)
70
+ OptionParser#Completion::complete refers to candidates more than self (Feature Envy)
71
+ OptionParser#Completion::complete/block has the variable name 'k' (Uncommunicative Name)
72
+ OptionParser#Completion::complete/block has the variable name 'v' (Uncommunicative Name)
73
+ OptionParser#List#accept has the variable name 't' (Uncommunicative Name)
74
+ OptionParser#List#accept is controlled by argument pat (Control Couple)
75
+ OptionParser#List#accept refers to pat more than self (Feature Envy)
76
+ OptionParser#List#add_banner refers to opt more than self (Feature Envy)
77
+ OptionParser#List#complete has 4 parameters (Long Parameter List)
78
+ OptionParser#List#reject has the variable name 't' (Uncommunicative Name)
79
+ OptionParser#List#summarize refers to opt more than self (Feature Envy)
80
+ OptionParser#List#update has 5 parameters (Long Parameter List)
81
+ OptionParser#List#update has approx 6 statements (Long Method)
82
+ OptionParser#List#update has the variable name 'o' (Uncommunicative Name)
83
+ OptionParser#List#update is controlled by argument lopts (Control Couple)
84
+ OptionParser#List#update is controlled by argument sopts (Control Couple)
85
+ OptionParser#List#update/block has the variable name 'o' (Uncommunicative Name)
86
+ OptionParser#ParseError#set_option is controlled by argument eq (Control Couple)
87
+ OptionParser#Switch#NoArgument#parse is controlled by argument arg (Control Couple)
88
+ OptionParser#Switch#OptionalArgument#parse is controlled by argument arg (Control Couple)
89
+ OptionParser#Switch#PlacedArgument#parse has approx 6 statements (Long Method)
90
+ OptionParser#Switch#RequiredArgument#parse is controlled by argument arg (Control Couple)
91
+ OptionParser#Switch#add_banner has the variable name 's' (Uncommunicative Name)
92
+ OptionParser#Switch#conv_arg calls conv twice (Duplication)
93
+ OptionParser#Switch#initialize has 7 parameters (Long Parameter List)
94
+ OptionParser#Switch#parse_arg calls pattern twice (Duplication)
95
+ OptionParser#Switch#parse_arg calls s.length twice (Duplication)
96
+ OptionParser#Switch#parse_arg has approx 11 statements (Long Method)
97
+ OptionParser#Switch#parse_arg has the variable name 'm' (Uncommunicative Name)
98
+ OptionParser#Switch#parse_arg has the variable name 's' (Uncommunicative Name)
99
+ OptionParser#Switch#self.guess has the variable name 't' (Uncommunicative Name)
100
+ OptionParser#Switch#self.incompatible_argument_styles has the variable name 't' (Uncommunicative Name)
101
+ OptionParser#Switch#summarize calls (indent + l) twice (Duplication)
102
+ OptionParser#Switch#summarize calls arg 4 times (Duplication)
103
+ OptionParser#Switch#summarize calls left.collect twice (Duplication)
104
+ OptionParser#Switch#summarize calls left.collect { |s| s.length }.max twice (Duplication)
105
+ OptionParser#Switch#summarize calls left.collect { |s| s.length }.max.to_i twice (Duplication)
106
+ OptionParser#Switch#summarize calls left.shift twice (Duplication)
107
+ OptionParser#Switch#summarize calls left[-1] 3 times (Duplication)
108
+ OptionParser#Switch#summarize calls s.length 3 times (Duplication)
109
+ OptionParser#Switch#summarize has 5 parameters (Long Parameter List)
110
+ OptionParser#Switch#summarize has approx 25 statements (Long Method)
111
+ OptionParser#Switch#summarize has the variable name 'l' (Uncommunicative Name)
112
+ OptionParser#Switch#summarize has the variable name 'r' (Uncommunicative Name)
113
+ OptionParser#Switch#summarize has the variable name 's' (Uncommunicative Name)
114
+ OptionParser#Switch#summarize/block has the variable name 's' (Uncommunicative Name)
115
+ OptionParser#Switch#summarize/block/block is nested (Nested Iterators)
116
+ OptionParser#block has the variable name 'f' (Uncommunicative Name)
117
+ OptionParser#block has the variable name 'k' (Uncommunicative Name)
118
+ OptionParser#block has the variable name 'o' (Uncommunicative Name)
119
+ OptionParser#block has the variable name 's' (Uncommunicative Name)
120
+ OptionParser#block is controlled by argument o (Control Couple)
121
+ OptionParser#block is controlled by argument s (Control Couple)
122
+ OptionParser#block/block has the variable name 's' (Uncommunicative Name)
123
+ OptionParser#block/block has the variable name 'v' (Uncommunicative Name)
124
+ OptionParser#block/block is controlled by argument pkg (Control Couple)
125
+ OptionParser#block/block is nested (Nested Iterators)
126
+ OptionParser#complete has 4 parameters (Long Parameter List)
127
+ OptionParser#complete/block/block is nested (Nested Iterators)
128
+ OptionParser#getopts calls result[opt] = false twice (Duplication)
129
+ OptionParser#getopts has approx 17 statements (Long Method)
130
+ OptionParser#getopts/block is controlled by argument val (Control Couple)
131
+ OptionParser#load/block has the variable name 's' (Uncommunicative Name)
132
+ OptionParser#make_switch calls (long << o = q.downcase) twice (Duplication)
133
+ OptionParser#make_switch calls (sdesc << "-#{q}") twice (Duplication)
134
+ OptionParser#make_switch calls default_style.guess(arg = a) 4 times (Duplication)
135
+ OptionParser#make_switch calls notwice(NilClass, klass, "type") twice (Duplication)
136
+ OptionParser#make_switch calls notwice(a ? (Object) : (TrueClass), klass, "type") twice (Duplication)
137
+ OptionParser#make_switch calls pattern.method(:convert) twice (Duplication)
138
+ OptionParser#make_switch calls pattern.method(:convert).to_proc twice (Duplication)
139
+ OptionParser#make_switch calls pattern.respond_to?(:convert) twice (Duplication)
140
+ OptionParser#make_switch calls q.downcase 3 times (Duplication)
141
+ OptionParser#make_switch calls search(:atype, FalseClass) twice (Duplication)
142
+ OptionParser#make_switch calls search(:atype, o) 6 times (Duplication)
143
+ OptionParser#make_switch has approx 68 statements (Long Method)
144
+ OptionParser#make_switch has the variable name 'a' (Uncommunicative Name)
145
+ OptionParser#make_switch has the variable name 'n' (Uncommunicative Name)
146
+ OptionParser#make_switch has the variable name 'o' (Uncommunicative Name)
147
+ OptionParser#make_switch has the variable name 'q' (Uncommunicative Name)
148
+ OptionParser#make_switch has the variable name 's' (Uncommunicative Name)
149
+ OptionParser#make_switch/block has the variable name 'a' (Uncommunicative Name)
150
+ OptionParser#make_switch/block has the variable name 'o' (Uncommunicative Name)
151
+ OptionParser#make_switch/block has the variable name 'q' (Uncommunicative Name)
152
+ OptionParser#make_switch/block/block has the variable name 'c' (Uncommunicative Name)
153
+ OptionParser#make_switch/block/block has the variable name 'o' (Uncommunicative Name)
154
+ OptionParser#make_switch/block/block has the variable name 'v' (Uncommunicative Name)
155
+ OptionParser#make_switch/block/block is nested (Nested Iterators)
156
+ OptionParser#make_switch/block/block/block is nested (Nested Iterators)
157
+ OptionParser#order calls argv[0] twice (Duplication)
158
+ OptionParser#order refers to argv more than self (Feature Envy)
159
+ OptionParser#parse calls argv[0] twice (Duplication)
160
+ OptionParser#parse refers to argv more than self (Feature Envy)
161
+ OptionParser#parse_in_order calls $!.set_option(arg, true) twice (Duplication)
162
+ OptionParser#parse_in_order calls cb.call(val) twice (Duplication)
163
+ OptionParser#parse_in_order calls raise($!.set_option(arg, true)) twice (Duplication)
164
+ OptionParser#parse_in_order calls raise(*exc) twice (Duplication)
165
+ OptionParser#parse_in_order calls setter.call(sw.switch_name, val) twice (Duplication)
166
+ OptionParser#parse_in_order calls sw.block twice (Duplication)
167
+ OptionParser#parse_in_order calls sw.switch_name twice (Duplication)
168
+ OptionParser#parse_in_order has approx 28 statements (Long Method)
169
+ OptionParser#parse_in_order/block is controlled by argument setter (Control Couple)
170
+ OptionParser#parse_in_order/block/block is nested (Nested Iterators)
171
+ OptionParser#parse_in_order/block/block/block is nested (Nested Iterators)
172
+ OptionParser#permute calls argv[0] twice (Duplication)
173
+ OptionParser#permute refers to argv more than self (Feature Envy)
174
+ OptionParser#search/block has the variable name 'k' (Uncommunicative Name)
175
+ OptionParser#summarize has 4 parameters (Long Parameter List)
176
+ OptionParser#summarize/block has the variable name 'l' (Uncommunicative Name)
177
+ OptionParser#ver has the variable name 'v' (Uncommunicative Name)
178
+ block has the variable name 'q' (Uncommunicative Name)
179
+
180
+ """
181
+
182
+ Scenario: Correct smells from redcloth.rb
183
+ When I run reek spec/samples/redcloth.rb
184
+ Then it fails with exit status 2
185
+ And it reports:
186
+ """
187
+ spec/samples/redcloth.rb -- 95 warnings:
188
+ RedCloth has at least 44 methods (Large Class)
189
+ RedCloth takes parameters [atts, cite, content, tag] to 3 methods (Data Clump)
190
+ RedCloth tests atts at least 6 times (Simulated Polymorphism)
191
+ RedCloth tests codepre.zero? at least 3 times (Simulated Polymorphism)
192
+ RedCloth tests href at least 3 times (Simulated Polymorphism)
193
+ RedCloth tests title at least 4 times (Simulated Polymorphism)
194
+ RedCloth#block has the variable name 'a' (Uncommunicative Name)
195
+ RedCloth#block has the variable name 'b' (Uncommunicative Name)
196
+ RedCloth#block_markdown_atx refers to text more than self (Feature Envy)
197
+ RedCloth#block_markdown_bq has approx 6 statements (Long Method)
198
+ RedCloth#block_markdown_rule refers to text more than self (Feature Envy)
199
+ RedCloth#block_markdown_setext refers to text more than self (Feature Envy)
200
+ RedCloth#block_textile_lists calls (line_id - 1) twice (Duplication)
201
+ RedCloth#block_textile_lists calls depth.last 5 times (Duplication)
202
+ RedCloth#block_textile_lists calls depth.last.length twice (Duplication)
203
+ RedCloth#block_textile_lists calls depth[i] twice (Duplication)
204
+ RedCloth#block_textile_lists calls lines[(line_id - 1)] twice (Duplication)
205
+ RedCloth#block_textile_lists calls tl.length 3 times (Duplication)
206
+ RedCloth#block_textile_lists has approx 20 statements (Long Method)
207
+ RedCloth#block_textile_lists refers to depth more than self (Feature Envy)
208
+ RedCloth#block_textile_lists/block/block is nested (Nested Iterators)
209
+ RedCloth#block_textile_lists/block/block/block has the variable name 'i' (Uncommunicative Name)
210
+ RedCloth#block_textile_lists/block/block/block has the variable name 'v' (Uncommunicative Name)
211
+ RedCloth#block_textile_lists/block/block/block is nested (Nested Iterators)
212
+ RedCloth#block_textile_table has approx 18 statements (Long Method)
213
+ RedCloth#block_textile_table/block/block has the variable name 'x' (Uncommunicative Name)
214
+ RedCloth#block_textile_table/block/block is nested (Nested Iterators)
215
+ RedCloth#block_textile_table/block/block/block is nested (Nested Iterators)
216
+ RedCloth#blocks has approx 18 statements (Long Method)
217
+ RedCloth#blocks/block is controlled by argument deep_code (Control Couple)
218
+ RedCloth#blocks/block/block is nested (Nested Iterators)
219
+ RedCloth#check_refs is controlled by argument text (Control Couple)
220
+ RedCloth#clean_html calls tags[tag] twice (Duplication)
221
+ RedCloth#clean_html doesn't depend on instance state (Utility Function)
222
+ RedCloth#clean_html has approx 14 statements (Long Method)
223
+ RedCloth#clean_html refers to raw more than self (Feature Envy)
224
+ RedCloth#clean_html refers to tags more than self (Feature Envy)
225
+ RedCloth#clean_html/block/block is nested (Nested Iterators)
226
+ RedCloth#clean_html/block/block/block has the variable name 'q' (Uncommunicative Name)
227
+ RedCloth#clean_html/block/block/block has the variable name 'q2' (Uncommunicative Name)
228
+ RedCloth#clean_html/block/block/block is nested (Nested Iterators)
229
+ RedCloth#clean_white_space has approx 7 statements (Long Method)
230
+ RedCloth#clean_white_space refers to text more than self (Feature Envy)
231
+ RedCloth#flush_left doesn't depend on instance state (Utility Function)
232
+ RedCloth#flush_left refers to indt more than self (Feature Envy)
233
+ RedCloth#flush_left refers to text more than self (Feature Envy)
234
+ RedCloth#footnote_ref refers to text more than self (Feature Envy)
235
+ RedCloth#glyphs_textile has approx 10 statements (Long Method)
236
+ RedCloth#htmlesc doesn't depend on instance state (Utility Function)
237
+ RedCloth#htmlesc refers to str more than self (Feature Envy)
238
+ RedCloth#incoming_entities refers to text more than self (Feature Envy)
239
+ RedCloth#initialize/block has the variable name 'r' (Uncommunicative Name)
240
+ RedCloth#inline/block/block is nested (Nested Iterators)
241
+ RedCloth#inline_markdown_link has approx 6 statements (Long Method)
242
+ RedCloth#inline_markdown_link/block has the variable name 'm' (Uncommunicative Name)
243
+ RedCloth#inline_markdown_reflink has approx 8 statements (Long Method)
244
+ RedCloth#inline_markdown_reflink/block has the variable name 'm' (Uncommunicative Name)
245
+ RedCloth#inline_textile_code/block has the variable name 'm' (Uncommunicative Name)
246
+ RedCloth#inline_textile_image has approx 17 statements (Long Method)
247
+ RedCloth#inline_textile_image/block has the variable name 'href_a1' (Uncommunicative Name)
248
+ RedCloth#inline_textile_image/block has the variable name 'href_a2' (Uncommunicative Name)
249
+ RedCloth#inline_textile_image/block has the variable name 'm' (Uncommunicative Name)
250
+ RedCloth#inline_textile_link has approx 9 statements (Long Method)
251
+ RedCloth#inline_textile_link/block has the variable name 'm' (Uncommunicative Name)
252
+ RedCloth#inline_textile_span has approx 8 statements (Long Method)
253
+ RedCloth#inline_textile_span/block/block has the variable name 'm' (Uncommunicative Name)
254
+ RedCloth#inline_textile_span/block/block is nested (Nested Iterators)
255
+ RedCloth#no_textile doesn't depend on instance state (Utility Function)
256
+ RedCloth#no_textile refers to text more than self (Feature Envy)
257
+ RedCloth#pba calls $1.length twice (Duplication)
258
+ RedCloth#pba has approx 21 statements (Long Method)
259
+ RedCloth#pba is controlled by argument text_in (Control Couple)
260
+ RedCloth#pba refers to style more than self (Feature Envy)
261
+ RedCloth#pba refers to text more than self (Feature Envy)
262
+ RedCloth#refs_markdown/block has the variable name 'm' (Uncommunicative Name)
263
+ RedCloth#refs_textile/block has the variable name 'm' (Uncommunicative Name)
264
+ RedCloth#retrieve/block has the variable name 'i' (Uncommunicative Name)
265
+ RedCloth#retrieve/block has the variable name 'r' (Uncommunicative Name)
266
+ RedCloth#rip_offtags calls ((codepre - used_offtags.length) > 0) twice (Duplication)
267
+ RedCloth#rip_offtags calls (@pre_list.last << line) twice (Duplication)
268
+ RedCloth#rip_offtags calls (codepre - used_offtags.length) twice (Duplication)
269
+ RedCloth#rip_offtags calls @pre_list.last twice (Duplication)
270
+ RedCloth#rip_offtags calls codepre.zero? twice (Duplication)
271
+ RedCloth#rip_offtags calls htmlesc(line, :NoQuotes) twice (Duplication)
272
+ RedCloth#rip_offtags calls used_offtags.length twice (Duplication)
273
+ RedCloth#rip_offtags calls used_offtags["notextile"] 3 times (Duplication)
274
+ RedCloth#rip_offtags has approx 18 statements (Long Method)
275
+ RedCloth#textile_bq has 4 parameters (Long Parameter List)
276
+ RedCloth#textile_bq is controlled by argument atts (Control Couple)
277
+ RedCloth#textile_bq is controlled by argument cite (Control Couple)
278
+ RedCloth#textile_fn_ has 5 parameters (Long Parameter List)
279
+ RedCloth#textile_fn_ is controlled by argument atts (Control Couple)
280
+ RedCloth#textile_p has 4 parameters (Long Parameter List)
281
+ RedCloth#textile_p is controlled by argument atts (Control Couple)
282
+ RedCloth#to_html has approx 24 statements (Long Method)
283
+
284
+ """
@@ -0,0 +1,43 @@
1
+ @stdin
2
+ Feature: Reek reads from $stdin when no files are given
3
+ In order to use reek with pipelines
4
+ As a developer
5
+ I want to pipe source code on stdin
6
+
7
+ Scenario: return zero status with no smells
8
+ When I pass "def simple() @fred = 3 end" to reek
9
+ Then it succeeds
10
+ And it reports:
11
+ """
12
+ $stdin -- 0 warnings
13
+
14
+ """
15
+
16
+ Scenario: outputs header only on empty stdin
17
+ When I pass "" to reek
18
+ Then it succeeds
19
+ And it reports:
20
+ """
21
+ $stdin -- 0 warnings
22
+
23
+ """
24
+
25
+ Scenario: outputs nothing on empty stdin in quiet mode
26
+ When I pass "" to reek --quiet
27
+ Then it succeeds
28
+ And it reports:
29
+ """
30
+
31
+
32
+ """
33
+
34
+ Scenario: return non-zero status when there are smells
35
+ When I pass "class Turn; def y() @x = 3; end end" to reek
36
+ Then it fails with exit status 2
37
+ And it reports:
38
+ """
39
+ $stdin -- 2 warnings:
40
+ Turn has the variable name '@x' (Uncommunicative Name)
41
+ Turn#y has the name 'y' (Uncommunicative Name)
42
+
43
+ """
@@ -0,0 +1,35 @@
1
+ When /^I run reek (.*)$/ do |args|
2
+ run args
3
+ end
4
+
5
+ When /^I pass "([^\"]*)" to reek *(.*)$/ do |stdin, args|
6
+ run_with_pipe(stdin, args)
7
+ end
8
+
9
+ When /^I run rake reek$/ do
10
+ rake
11
+ end
12
+
13
+ Then /^stdout equals "([^\"]*)"$/ do |report|
14
+ @last_stdout.should == report
15
+ end
16
+
17
+ Then /^it succeeds$/ do
18
+ @last_exit_status.should == 0
19
+ end
20
+
21
+ Then /^it fails with exit status (\d+)$/ do |status|
22
+ @last_exit_status.should == status.to_i
23
+ end
24
+
25
+ Then /^it reports:$/ do |report|
26
+ @last_stdout.should == report
27
+ end
28
+
29
+ Then /^it reports the error ['"](.*)['"]$/ do |string|
30
+ @last_stderr.chomp.should == string
31
+ end
32
+
33
+ Then /^it reports the current version$/ do
34
+ @last_stdout.chomp.should == "reek #{Reek::VERSION}"
35
+ end
@@ -0,0 +1,38 @@
1
+ $:.unshift 'lib'
2
+
3
+ require 'rubygems'
4
+ require 'tempfile'
5
+ require 'spec/expectations'
6
+ require 'fileutils'
7
+ require 'reek'
8
+
9
+ class CucumberWorld
10
+
11
+ def run(args)
12
+ stderr_file = Tempfile.new('cucumber')
13
+ stderr_file.close
14
+ @last_stdout = `ruby -Ilib bin/reek #{args} 2> #{stderr_file.path}`
15
+ @last_exit_status = $?.exitstatus
16
+ @last_stderr = IO.read(stderr_file.path)
17
+ end
18
+
19
+ def run_with_pipe(stdin, args)
20
+ stderr_file = Tempfile.new('cucumber')
21
+ stderr_file.close
22
+ @last_stdout = `echo \"#{stdin}\" | ruby -Ilib bin/reek #{args} 2> #{stderr_file.path}`
23
+ @last_exit_status = $?.exitstatus
24
+ @last_stderr = IO.read(stderr_file.path)
25
+ end
26
+
27
+ def rake
28
+ stderr_file = Tempfile.new('cucumber')
29
+ stderr_file.close
30
+ @last_stdout = `rake reek 2> #{stderr_file.path}`
31
+ @last_exit_status = $?.exitstatus
32
+ @last_stderr = IO.read(stderr_file.path)
33
+ end
34
+ end
35
+
36
+ World do
37
+ CucumberWorld.new
38
+ end
data/lib/reek.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
 
3
3
  module Reek # :doc:
4
- VERSION = '1.1.3'
4
+ VERSION = '1.2.0'
5
5
  end
@@ -0,0 +1,47 @@
1
+ require 'reek/command_line'
2
+ require 'reek/adapters/source'
3
+ require 'reek/adapters/core_extras'
4
+ require 'reek/adapters/report'
5
+
6
+ module Reek
7
+ #
8
+ # Represents an instance of a Reek application.
9
+ # This is the entry point for all invocations of Reek from the
10
+ # command line.
11
+ #
12
+ class Application
13
+ def initialize(argv)
14
+ @argv = argv
15
+ end
16
+
17
+ def examine_sources
18
+ # SMELL: Greedy Method
19
+ # Options.parse executes the -v and -h commands and throws a SystemExit
20
+ args = Options.new(@argv).parse
21
+ if args.length > 0
22
+ @sniffer = args.sniff
23
+ else
24
+ @sniffer = Reek::Sniffer.new($stdin.to_reek_source('$stdin'))
25
+ end
26
+ end
27
+
28
+ def reek
29
+ examine_sources
30
+ # SMELL:
31
+ # This should use the actual type of report selected by the user's options
32
+ puts Report.new(@sniffer.sniffers).full_report
33
+ return @sniffer.smelly? ? 2 : 0
34
+ end
35
+
36
+ def execute
37
+ begin
38
+ return reek
39
+ rescue SystemExit => ex
40
+ return ex.status
41
+ rescue Exception => error
42
+ $stderr.puts "Error: #{error}"
43
+ return 1
44
+ end
45
+ end
46
+ end
47
+ end