reek 1.2.6 → 1.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. data/.yardopts +10 -0
  2. data/History.txt +20 -0
  3. data/README.md +90 -0
  4. data/bin/reek +2 -2
  5. data/config/defaults.reek +34 -4
  6. data/features/masking_smells.feature +35 -15
  7. data/features/options.feature +2 -0
  8. data/features/rake_task.feature +11 -18
  9. data/features/reports.feature +13 -15
  10. data/features/samples.feature +90 -105
  11. data/features/stdin.feature +3 -6
  12. data/features/step_definitions/reek_steps.rb +8 -4
  13. data/features/support/env.rb +2 -3
  14. data/features/yaml.feature +124 -0
  15. data/lib/reek.rb +8 -4
  16. data/lib/reek/cli/application.rb +46 -0
  17. data/lib/reek/cli/command_line.rb +106 -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 +91 -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/block_context.rb +18 -0
  24. data/lib/reek/core/class_context.rb +23 -0
  25. data/lib/reek/core/code_context.rb +72 -0
  26. data/lib/reek/core/code_parser.rb +192 -0
  27. data/lib/reek/core/detector_stack.rb +29 -0
  28. data/lib/reek/core/masking_collection.rb +46 -0
  29. data/lib/reek/core/method_context.rb +132 -0
  30. data/lib/reek/core/module_context.rb +64 -0
  31. data/lib/reek/{object_refs.rb → core/object_refs.rb} +8 -6
  32. data/lib/reek/{singleton_method_context.rb → core/singleton_method_context.rb} +10 -5
  33. data/lib/reek/core/smell_configuration.rb +66 -0
  34. data/lib/reek/core/sniffer.rb +110 -0
  35. data/lib/reek/core/stop_context.rb +26 -0
  36. data/lib/reek/examiner.rb +88 -0
  37. data/lib/reek/rake/task.rb +124 -0
  38. data/lib/reek/smell_warning.rb +69 -13
  39. data/lib/reek/smells.rb +29 -0
  40. data/lib/reek/smells/attribute.rb +13 -14
  41. data/lib/reek/smells/boolean_parameter.rb +33 -0
  42. data/lib/reek/smells/class_variable.rb +8 -6
  43. data/lib/reek/smells/control_couple.rb +33 -17
  44. data/lib/reek/smells/data_clump.rb +10 -6
  45. data/lib/reek/smells/duplication.rb +24 -14
  46. data/lib/reek/smells/feature_envy.rb +11 -6
  47. data/lib/reek/smells/irresponsible_module.rb +28 -0
  48. data/lib/reek/smells/large_class.rb +9 -7
  49. data/lib/reek/smells/long_method.rb +6 -5
  50. data/lib/reek/smells/long_parameter_list.rb +11 -9
  51. data/lib/reek/smells/long_yield_list.rb +37 -7
  52. data/lib/reek/smells/nested_iterators.rb +34 -9
  53. data/lib/reek/smells/simulated_polymorphism.rb +15 -11
  54. data/lib/reek/smells/smell_detector.rb +24 -12
  55. data/lib/reek/smells/uncommunicative_method_name.rb +76 -0
  56. data/lib/reek/smells/uncommunicative_module_name.rb +76 -0
  57. data/lib/reek/smells/{uncommunicative_name.rb → uncommunicative_parameter_name.rb} +14 -26
  58. data/lib/reek/smells/uncommunicative_variable_name.rb +90 -0
  59. data/lib/reek/smells/utility_function.rb +33 -9
  60. data/lib/reek/source.rb +18 -0
  61. data/lib/reek/source/code_comment.rb +19 -0
  62. data/lib/reek/source/config_file.rb +72 -0
  63. data/lib/reek/source/core_extras.rb +46 -0
  64. data/lib/reek/source/sexp_formatter.rb +16 -0
  65. data/lib/reek/source/source_code.rb +44 -0
  66. data/lib/reek/source/source_file.rb +32 -0
  67. data/lib/reek/source/source_locator.rb +36 -0
  68. data/lib/reek/source/tree_dresser.rb +128 -0
  69. data/lib/reek/spec.rb +51 -0
  70. data/lib/reek/spec/should_reek.rb +34 -0
  71. data/lib/reek/spec/should_reek_of.rb +37 -0
  72. data/lib/reek/spec/should_reek_only_of.rb +36 -0
  73. data/reek.gemspec +5 -5
  74. data/spec/reek/{help_command_spec.rb → cli/help_command_spec.rb} +3 -4
  75. data/spec/reek/{reek_command_spec.rb → cli/reek_command_spec.rb} +8 -7
  76. data/spec/reek/cli/report_spec.rb +26 -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/block_context_spec.rb +26 -0
  80. data/spec/reek/core/class_context_spec.rb +53 -0
  81. data/spec/reek/{code_context_spec.rb → core/code_context_spec.rb} +15 -37
  82. data/spec/reek/{code_parser_spec.rb → core/code_parser_spec.rb} +5 -5
  83. data/spec/reek/{config_spec.rb → core/config_spec.rb} +2 -6
  84. data/spec/reek/{masking_collection_spec.rb → core/masking_collection_spec.rb} +3 -4
  85. data/spec/reek/{method_context_spec.rb → core/method_context_spec.rb} +6 -7
  86. data/spec/reek/core/module_context_spec.rb +42 -0
  87. data/spec/reek/{object_refs_spec.rb → core/object_refs_spec.rb} +5 -6
  88. data/spec/reek/core/singleton_method_context_spec.rb +15 -0
  89. data/spec/reek/core/smell_configuration_spec.rb +11 -0
  90. data/spec/reek/core/stop_context_spec.rb +17 -0
  91. data/spec/reek/examiner_spec.rb +42 -0
  92. data/spec/reek/smell_warning_spec.rb +82 -33
  93. data/spec/reek/smells/attribute_spec.rb +33 -7
  94. data/spec/reek/smells/boolean_parameter_spec.rb +76 -0
  95. data/spec/reek/smells/class_variable_spec.rb +15 -6
  96. data/spec/reek/smells/control_couple_spec.rb +40 -29
  97. data/spec/reek/smells/data_clump_spec.rb +28 -7
  98. data/spec/reek/smells/duplication_spec.rb +47 -41
  99. data/spec/reek/smells/feature_envy_spec.rb +76 -18
  100. data/spec/reek/smells/irresponsible_module_spec.rb +37 -0
  101. data/spec/reek/smells/large_class_spec.rb +91 -56
  102. data/spec/reek/smells/long_method_spec.rb +32 -7
  103. data/spec/reek/smells/long_parameter_list_spec.rb +42 -13
  104. data/spec/reek/smells/long_yield_list_spec.rb +65 -0
  105. data/spec/reek/smells/nested_iterators_spec.rb +94 -3
  106. data/spec/reek/smells/simulated_polymorphism_spec.rb +48 -20
  107. data/spec/reek/smells/smell_detector_shared.rb +28 -0
  108. data/spec/reek/smells/uncommunicative_method_name_spec.rb +57 -0
  109. data/spec/reek/smells/uncommunicative_module_name_spec.rb +67 -0
  110. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +61 -0
  111. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +124 -0
  112. data/spec/reek/smells/utility_function_spec.rb +45 -3
  113. data/spec/reek/source/code_comment_spec.rb +24 -0
  114. data/spec/reek/source/object_source_spec.rb +20 -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 +165 -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/corrupt_config_file/dirty.rb +1 -1
  130. data/spec/samples/empty_config_file/dirty.rb +2 -1
  131. data/spec/samples/exceptions.reek +1 -1
  132. data/spec/samples/masked/dirty.rb +2 -1
  133. data/spec/samples/masked/masked.reek +3 -1
  134. data/spec/samples/mixed_results/clean_one.rb +1 -0
  135. data/spec/samples/mixed_results/clean_three.rb +1 -0
  136. data/spec/samples/mixed_results/clean_two.rb +1 -0
  137. data/spec/samples/mixed_results/dirty_one.rb +1 -0
  138. data/spec/samples/mixed_results/dirty_two.rb +1 -0
  139. data/spec/samples/not_quite_masked/dirty.rb +2 -1
  140. data/spec/samples/not_quite_masked/masked.reek +1 -1
  141. data/spec/samples/overrides/masked/dirty.rb +2 -1
  142. data/spec/samples/overrides/masked/lower.reek +3 -1
  143. data/spec/samples/three_clean_files/clean_one.rb +1 -0
  144. data/spec/samples/three_clean_files/clean_three.rb +1 -0
  145. data/spec/samples/three_clean_files/clean_two.rb +1 -0
  146. data/spec/samples/two_smelly_files/dirty_one.rb +2 -1
  147. data/spec/samples/two_smelly_files/dirty_two.rb +2 -1
  148. data/spec/spec_helper.rb +1 -2
  149. data/tasks/reek.rake +2 -2
  150. data/tasks/test.rake +12 -3
  151. metadata +81 -62
  152. data/README.rdoc +0 -84
  153. data/lib/reek/adapters/application.rb +0 -46
  154. data/lib/reek/adapters/command_line.rb +0 -77
  155. data/lib/reek/adapters/config_file.rb +0 -31
  156. data/lib/reek/adapters/core_extras.rb +0 -64
  157. data/lib/reek/adapters/rake_task.rb +0 -121
  158. data/lib/reek/adapters/report.rb +0 -86
  159. data/lib/reek/adapters/source.rb +0 -72
  160. data/lib/reek/adapters/spec.rb +0 -133
  161. data/lib/reek/block_context.rb +0 -62
  162. data/lib/reek/class_context.rb +0 -41
  163. data/lib/reek/code_context.rb +0 -68
  164. data/lib/reek/code_parser.rb +0 -203
  165. data/lib/reek/configuration.rb +0 -57
  166. data/lib/reek/detector_stack.rb +0 -37
  167. data/lib/reek/help_command.rb +0 -14
  168. data/lib/reek/if_context.rb +0 -18
  169. data/lib/reek/masking_collection.rb +0 -33
  170. data/lib/reek/method_context.rb +0 -138
  171. data/lib/reek/module_context.rb +0 -49
  172. data/lib/reek/name.rb +0 -57
  173. data/lib/reek/reek_command.rb +0 -28
  174. data/lib/reek/sexp_formatter.rb +0 -10
  175. data/lib/reek/sniffer.rb +0 -177
  176. data/lib/reek/stop_context.rb +0 -35
  177. data/lib/reek/tree_dresser.rb +0 -82
  178. data/lib/reek/version_command.rb +0 -14
  179. data/lib/reek/yield_call_context.rb +0 -12
  180. data/spec/reek/adapters/report_spec.rb +0 -31
  181. data/spec/reek/adapters/should_reek_of_spec.rb +0 -138
  182. data/spec/reek/adapters/should_reek_only_of_spec.rb +0 -87
  183. data/spec/reek/block_context_spec.rb +0 -65
  184. data/spec/reek/class_context_spec.rb +0 -161
  185. data/spec/reek/configuration_spec.rb +0 -12
  186. data/spec/reek/if_context_spec.rb +0 -17
  187. data/spec/reek/module_context_spec.rb +0 -46
  188. data/spec/reek/name_spec.rb +0 -37
  189. data/spec/reek/object_source_spec.rb +0 -23
  190. data/spec/reek/singleton_method_context_spec.rb +0 -16
  191. data/spec/reek/smells/smell_detector_spec.rb +0 -36
  192. data/spec/reek/smells/uncommunicative_name_spec.rb +0 -146
  193. data/spec/reek/sniffer_spec.rb +0 -11
  194. data/spec/reek/stop_context_spec.rb +0 -33
  195. data/spec/reek/tree_dresser_spec.rb +0 -20
@@ -1,5 +1,9 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
- module Reek # :doc:
4
- VERSION = '1.2.6'
1
+ #
2
+ # Reek's core functionality
3
+ #
4
+ module Reek
5
+ VERSION = '1.2.7'
5
6
  end
7
+
8
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'reek', 'examiner')
9
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'reek', 'smell_warning')
@@ -0,0 +1,46 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'command_line')
2
+
3
+ module Reek
4
+ module Cli
5
+
6
+ #
7
+ # Represents an instance of a Reek application.
8
+ # This is the entry point for all invocations of Reek from the
9
+ # command line.
10
+ #
11
+ class Application
12
+
13
+ STATUS_SUCCESS = 0
14
+ STATUS_ERROR = 1
15
+ STATUS_SMELLS = 2
16
+
17
+ def initialize(argv)
18
+ @options = Options.new(argv)
19
+ @status = STATUS_SUCCESS
20
+ end
21
+
22
+ def execute
23
+ begin
24
+ cmd = @options.parse
25
+ cmd.execute(self)
26
+ rescue Exception => error
27
+ $stderr.puts "Error: #{error}"
28
+ @status = STATUS_ERROR
29
+ end
30
+ return @status
31
+ end
32
+
33
+ def output(text)
34
+ print text
35
+ end
36
+
37
+ def report_success
38
+ @status = STATUS_SUCCESS
39
+ end
40
+
41
+ def report_smells
42
+ @status = STATUS_SMELLS
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,106 @@
1
+ require 'optparse'
2
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'report')
3
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'reek_command')
4
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'help_command')
5
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'version_command')
6
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'yaml_command')
7
+ require File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'source')
8
+
9
+ module Reek
10
+ module Cli
11
+
12
+ #
13
+ # Parses the command line
14
+ #
15
+ class Options
16
+
17
+ def initialize(argv)
18
+ @argv = argv
19
+ @parser = OptionParser.new
20
+ @report_class = VerboseReport
21
+ @show_all = false
22
+ @command_class = ReekCommand
23
+ set_options
24
+ end
25
+
26
+ def banner
27
+ progname = @parser.program_name
28
+ # SMELL:
29
+ # The following banner isn't really correct. Help, Version and Reek
30
+ # are really sub-commands (in the git/svn sense) and so the usage
31
+ # banner should show three different command-lines. The other
32
+ # options are all flags for the Reek sub-command.
33
+ #
34
+ # reek -h|--help Display a help message
35
+ #
36
+ # reek -v|--version Output the tool's version number
37
+ #
38
+ # reek [options] files List the smells in the given files
39
+ # -a|--[no-]show-all Report masked smells
40
+ # -q|-[no-]quiet Only list files that have smells
41
+ # files Names of files or dirs to be checked
42
+ #
43
+ return <<EOB
44
+ Usage: #{progname} [options] [files]
45
+
46
+ Examples:
47
+
48
+ #{progname} lib/*.rb
49
+ #{progname} -q -a lib
50
+ cat my_class.rb | #{progname}
51
+
52
+ See http://wiki.github.com/kevinrutherford/reek for detailed help.
53
+
54
+ EOB
55
+ end
56
+
57
+ def set_options
58
+ @parser.banner = banner
59
+ @parser.separator "Common options:"
60
+ @parser.on("-h", "--help", "Show this message") do
61
+ @command_class = HelpCommand
62
+ end
63
+ @parser.on("-v", "--version", "Show version") do
64
+ @command_class = VersionCommand
65
+ end
66
+
67
+ @parser.separator "\nReport formatting:"
68
+ @parser.on("-a", "--[no-]show-all", "Show all smells, including those masked by config settings") do |opt|
69
+ @show_all = opt
70
+ end
71
+ @parser.on("-q", "--[no-]quiet", "Suppress headings for smell-free source files") do |opt|
72
+ @report_class = opt ? QuietReport : VerboseReport
73
+ end
74
+ @parser.on("-y", "--yaml", "Report smells in YAML format") do
75
+ @command_class = YamlCommand
76
+ # SMELL: the args passed to the command should be tested, because it may
77
+ # turn out that they are passed too soon, ie. before the files have been
78
+ # separated out from the options
79
+ end
80
+ end
81
+
82
+ def parse
83
+ @parser.parse!(@argv)
84
+ if @command_class == HelpCommand
85
+ HelpCommand.new(@parser)
86
+ elsif @command_class == VersionCommand
87
+ VersionCommand.new(@parser.program_name)
88
+ elsif @command_class == YamlCommand
89
+ sources = get_sources
90
+ YamlCommand.create(sources)
91
+ else
92
+ sources = get_sources
93
+ ReekCommand.create(sources, @report_class, @show_all)
94
+ end
95
+ end
96
+
97
+ def get_sources
98
+ if @argv.empty?
99
+ return [$stdin.to_reek_source('$stdin')]
100
+ else
101
+ return Source::SourceLocator.new(@argv).all_sources
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,18 @@
1
+
2
+ module Reek
3
+ module Cli
4
+
5
+ #
6
+ # A command to display usage information for this application.
7
+ #
8
+ class HelpCommand
9
+ def initialize(parser)
10
+ @parser = parser
11
+ end
12
+ def execute(view)
13
+ view.output(@parser.to_s)
14
+ view.report_success
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,37 @@
1
+ require File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'examiner')
2
+
3
+ module Reek
4
+ module Cli
5
+
6
+ #
7
+ # A command to collect smells from a set of sources and write them out in
8
+ # text report format.
9
+ #
10
+ class ReekCommand
11
+ def self.create(sources, report_class, show_all)
12
+ examiners = sources.map {|src| Examiner.new(src) }
13
+ new(examiners, report_class, show_all)
14
+ end
15
+
16
+ def initialize(examiners, report_class, show_all)
17
+ @examiners = examiners
18
+ @report_class = report_class
19
+ @show_all = show_all #SMELL: boolean parameter
20
+ end
21
+
22
+ def execute(view)
23
+ had_smells = false
24
+ @examiners.each do |examiner|
25
+ rpt = @report_class.new(examiner, @show_all)
26
+ had_smells ||= examiner.smelly?
27
+ view.output(rpt.report)
28
+ end
29
+ if had_smells
30
+ view.report_smells
31
+ else
32
+ view.report_success
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,91 @@
1
+ module Reek
2
+ module Cli
3
+
4
+ #
5
+ # A section of a text report; has a heading that identifies the source
6
+ # and summarises the smell counts, and a body listing details of all
7
+ # smells found.
8
+ #
9
+ class ReportSection
10
+
11
+ SMELL_FORMAT = '%m%c %w (%s)'
12
+
13
+ def initialize(examiner, display_masked_warnings)
14
+ @examiner = examiner
15
+ @display_masked_warnings = display_masked_warnings # SMELL: Control Couple
16
+ end
17
+
18
+ # Creates a formatted report of all the +Smells::SmellWarning+ objects recorded in
19
+ # this report, with a heading.
20
+ def verbose_report
21
+ result = header
22
+ result += ":\n#{smell_list}" if should_report
23
+ result += "\n"
24
+ result
25
+ end
26
+
27
+ def quiet_report
28
+ return '' unless should_report
29
+ # SMELL: duplicate knowledge of the header layout
30
+ "#{header}:\n#{smell_list}\n"
31
+ end
32
+
33
+ def header
34
+ "#{@examiner.description} -- #{visible_header}#{masked_header}"
35
+ end
36
+
37
+ # Creates a formatted report of all the +Smells::SmellWarning+ objects recorded in
38
+ # this report.
39
+ def smell_list
40
+ if @display_masked_warnings
41
+ result = @examiner.all_smells.map {|smell| " #{smell.report(SMELL_FORMAT)}"}
42
+ else
43
+ result = @examiner.all_active_smells.map {|smell| " #{smell.report(SMELL_FORMAT)}"}
44
+ end
45
+ result.join("\n")
46
+ end
47
+
48
+ private
49
+
50
+ def should_report
51
+ @examiner.num_active_smells > 0 or (@display_masked_warnings and @examiner.num_masked_smells > 0)
52
+ end
53
+
54
+ def visible_header
55
+ num_smells = @examiner.all_active_smells.length
56
+ result = "#{num_smells} warning"
57
+ result += 's' unless num_smells == 1
58
+ result
59
+ end
60
+
61
+ def masked_header
62
+ num_masked_warnings = @examiner.num_masked_smells
63
+ num_masked_warnings == 0 ? '' : " (+#{num_masked_warnings} masked)"
64
+ end
65
+ end
66
+
67
+ #
68
+ # A report that lists every source, including those that have no smells.
69
+ #
70
+ class VerboseReport
71
+ def initialize(examiner, display_masked_warnings)
72
+ @reporter = ReportSection.new(examiner, display_masked_warnings)
73
+ end
74
+ def report
75
+ @reporter.verbose_report
76
+ end
77
+ end
78
+
79
+ #
80
+ # A report that lists a section for each source that has smells.
81
+ #
82
+ class QuietReport
83
+ def initialize(examiner, display_masked_warnings)
84
+ @reporter = ReportSection.new(examiner, display_masked_warnings)
85
+ end
86
+ def report
87
+ @reporter.quiet_report
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,19 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'reek')
2
+
3
+ module Reek
4
+ module Cli
5
+
6
+ #
7
+ # A command to report the application's current version number.
8
+ #
9
+ class VersionCommand
10
+ def initialize(progname)
11
+ @progname = progname
12
+ end
13
+ def execute(view)
14
+ view.output("#{@progname} #{Reek::VERSION}\n")
15
+ view.report_success
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ require File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'examiner')
2
+
3
+ module Reek
4
+ module Cli
5
+
6
+ #
7
+ # A command to collect smells from a set of sources and write them out in
8
+ # YAML format.
9
+ #
10
+ class YamlCommand
11
+ def self.create(sources)
12
+ examiners = sources.map {|src| Examiner.new(src) }
13
+ new(examiners)
14
+ end
15
+
16
+ def initialize(examiners)
17
+ @examiners = examiners
18
+ end
19
+
20
+ def execute(view)
21
+ smells = []
22
+ @examiners.each {|examiner| smells += examiner.all_smells}
23
+ if smells.empty?
24
+ view.report_success
25
+ else
26
+ view.output(smells.to_yaml)
27
+ view.report_smells
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,18 @@
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
@@ -0,0 +1,23 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'module_context')
2
+
3
+ module Reek
4
+ module Core
5
+
6
+ #
7
+ # A context wrapper for any class found in a syntax tree.
8
+ #
9
+ class ClassContext < ModuleContext
10
+
11
+ attr_reader :parsed_methods
12
+
13
+ def initialize(outer, name, exp)
14
+ super
15
+ @superclass = exp[2]
16
+ end
17
+
18
+ def is_struct?
19
+ @superclass == [:const, :Struct]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,72 @@
1
+
2
+ #
3
+ # Extensions to +Module+ needed by Reek.
4
+ #
5
+ class Module
6
+ def const_or_nil(sym)
7
+ const_defined?(sym) ? const_get(sym) : nil
8
+ end
9
+ end
10
+
11
+ module Reek
12
+ module Core
13
+
14
+ #
15
+ # Superclass for all types of source code context. Each instance represents
16
+ # a code element of some kind, and each provides behaviour relevant to that
17
+ # code element. CodeContexts form a tree in the same way the code does,
18
+ # with each context holding a reference to a unique outer context.
19
+ #
20
+ class CodeContext
21
+
22
+ attr_reader :name, :exp
23
+
24
+ def initialize(outer, exp)
25
+ @outer = outer
26
+ @exp = exp
27
+ @scope_connector = ''
28
+ end
29
+
30
+ def local_nodes(type, &blk)
31
+ each_node(type, [:class, :module], &blk)
32
+ end
33
+
34
+ def each_node(type, ignoring, &blk)
35
+ if block_given?
36
+ @exp.look_for(type, ignoring, &blk)
37
+ else
38
+ result = []
39
+ @exp.look_for(type, ignoring) {|exp| result << exp}
40
+ result
41
+ end
42
+ end
43
+
44
+ # SMELL: Temporary Field -- @name isn't always initialized
45
+ def matches?(strings)
46
+ me = @name.to_s
47
+ strings.any? do |str|
48
+ re = /#{str}/
49
+ re === me or re === self.full_name
50
+ end
51
+ end
52
+
53
+ #
54
+ # Bounces messages up the context tree to the first enclosing context
55
+ # that knows how to deal with the request.
56
+ #
57
+ def method_missing(method, *args)
58
+ @outer.send(method, *args)
59
+ end
60
+
61
+ def num_methods
62
+ 0
63
+ end
64
+
65
+ def full_name
66
+ outer = @outer ? @outer.full_name : ''
67
+ prefix = outer == '' ? '' : "#{outer}#{@scope_connector}"
68
+ "#{prefix}#{@name}"
69
+ end
70
+ end
71
+ end
72
+ end