reek 1.2.7.3 → 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 (76) hide show
  1. data/History.txt +17 -0
  2. data/README.md +32 -48
  3. data/config/defaults.reek +7 -1
  4. data/features/api.feature +20 -0
  5. data/features/masking_smells.feature +41 -0
  6. data/features/options.feature +4 -0
  7. data/features/rake_task.feature +14 -0
  8. data/features/yaml.feature +8 -8
  9. data/lib/reek.rb +1 -1
  10. data/lib/reek/cli/command_line.rb +9 -2
  11. data/lib/reek/cli/reek_command.rb +5 -4
  12. data/lib/reek/cli/yaml_command.rb +2 -2
  13. data/lib/reek/core/code_context.rb +10 -1
  14. data/lib/reek/core/method_context.rb +2 -2
  15. data/lib/reek/core/sniffer.rb +3 -1
  16. data/lib/reek/core/stop_context.rb +4 -0
  17. data/lib/reek/examiner.rb +2 -2
  18. data/lib/reek/rake/task.rb +16 -0
  19. data/lib/reek/smell_warning.rb +3 -2
  20. data/lib/reek/smells/attribute.rb +13 -9
  21. data/lib/reek/smells/boolean_parameter.rb +14 -9
  22. data/lib/reek/smells/class_variable.rb +16 -5
  23. data/lib/reek/smells/control_couple.rb +11 -6
  24. data/lib/reek/smells/data_clump.rb +33 -30
  25. data/lib/reek/smells/duplication.rb +39 -8
  26. data/lib/reek/smells/feature_envy.rb +7 -8
  27. data/lib/reek/smells/irresponsible_module.rb +12 -3
  28. data/lib/reek/smells/large_class.rb +31 -15
  29. data/lib/reek/smells/long_method.rb +15 -5
  30. data/lib/reek/smells/long_parameter_list.rb +14 -7
  31. data/lib/reek/smells/long_yield_list.rb +12 -9
  32. data/lib/reek/smells/nested_iterators.rb +46 -11
  33. data/lib/reek/smells/simulated_polymorphism.rb +16 -8
  34. data/lib/reek/smells/smell_detector.rb +13 -13
  35. data/lib/reek/smells/uncommunicative_method_name.rb +12 -20
  36. data/lib/reek/smells/uncommunicative_module_name.rb +17 -19
  37. data/lib/reek/smells/uncommunicative_parameter_name.rb +22 -15
  38. data/lib/reek/smells/uncommunicative_variable_name.rb +24 -18
  39. data/lib/reek/smells/utility_function.rb +6 -6
  40. data/lib/reek/source/code_comment.rb +19 -1
  41. data/lib/reek/source/tree_dresser.rb +40 -22
  42. data/reek.gemspec +6 -4
  43. data/spec/matchers/smell_of_matcher.rb +58 -0
  44. data/spec/reek/core/code_context_spec.rb +4 -2
  45. data/spec/reek/core/code_parser_spec.rb +2 -1
  46. data/spec/reek/core/method_context_spec.rb +5 -5
  47. data/spec/reek/smells/attribute_spec.rb +2 -4
  48. data/spec/reek/smells/boolean_parameter_spec.rb +32 -42
  49. data/spec/reek/smells/class_variable_spec.rb +22 -6
  50. data/spec/reek/smells/control_couple_spec.rb +15 -14
  51. data/spec/reek/smells/data_clump_spec.rb +29 -111
  52. data/spec/reek/smells/duplication_spec.rb +79 -49
  53. data/spec/reek/smells/feature_envy_spec.rb +1 -2
  54. data/spec/reek/smells/irresponsible_module_spec.rb +43 -22
  55. data/spec/reek/smells/large_class_spec.rb +34 -59
  56. data/spec/reek/smells/long_method_spec.rb +15 -10
  57. data/spec/reek/smells/long_parameter_list_spec.rb +24 -24
  58. data/spec/reek/smells/long_yield_list_spec.rb +13 -14
  59. data/spec/reek/smells/nested_iterators_spec.rb +93 -76
  60. data/spec/reek/smells/smell_detector_shared.rb +4 -2
  61. data/spec/reek/smells/uncommunicative_method_name_spec.rb +10 -27
  62. data/spec/reek/smells/uncommunicative_module_name_spec.rb +22 -23
  63. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +36 -26
  64. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +45 -48
  65. data/spec/reek/smells/utility_function_spec.rb +14 -13
  66. data/spec/reek/source/code_comment_spec.rb +61 -3
  67. data/spec/reek/source/tree_dresser_spec.rb +96 -1
  68. data/spec/samples/config/allow_duplication.reek +3 -0
  69. data/spec/samples/config/deeper_nested_iterators.reek +3 -0
  70. data/spec/samples/demo/demo.rb +8 -0
  71. data/spec/samples/inline_config/dirty.rb +16 -0
  72. data/spec/samples/inline_config/masked.reek +7 -0
  73. data/spec/samples/mask_some/dirty.rb +8 -0
  74. data/spec/samples/mask_some/some.reek +8 -0
  75. data/spec/spec_helper.rb +2 -0
  76. metadata +15 -5
@@ -19,12 +19,16 @@ module Reek
19
19
  #
20
20
  class UncommunicativeParameterName < SmellDetector
21
21
 
22
+ SMELL_CLASS = 'UncommunicativeName'
23
+ SMELL_SUBCLASS = self.name.split(/::/)[-1]
24
+ PARAMETER_NAME_KEY = 'parameter_name'
25
+
22
26
  # The name of the config field that lists the regexps of
23
27
  # smelly names to be reported.
24
28
  REJECT_KEY = 'reject'
25
29
 
26
30
  DEFAULT_REJECT_SET = [/^.$/, /[0-9]$/, /[A-Z]/]
27
-
31
+
28
32
  # The name of the config field that lists the specific names that are
29
33
  # to be treated as exceptions; these names will not be reported as
30
34
  # uncommunicative.
@@ -34,8 +38,8 @@ module Reek
34
38
 
35
39
  def self.default_config
36
40
  super.adopt(
37
- REJECT_KEY => DEFAULT_REJECT_SET,
38
- ACCEPT_KEY => DEFAULT_ACCEPT_SET
41
+ REJECT_KEY => DEFAULT_REJECT_SET,
42
+ ACCEPT_KEY => DEFAULT_ACCEPT_SET
39
43
  )
40
44
  end
41
45
 
@@ -49,23 +53,26 @@ module Reek
49
53
 
50
54
  #
51
55
  # Checks the given +context+ for uncommunicative names.
52
- # Remembers any smells found.
53
56
  #
54
- def examine_context(context)
55
- context.exp.parameter_names.each do |name|
56
- next unless is_bad_name?(name, context)
57
- smell = SmellWarning.new('UncommunicativeName', context.full_name, [context.exp.line],
58
- "has the parameter name '#{name}'",
59
- @source, 'UncommunicativeParameterName', {'parameter_name' => name.to_s})
60
- @smells_found << smell
61
- #SMELL: serious duplication
57
+ # @return [Array<SmellWarning>]
58
+ #
59
+ def examine_context(ctx)
60
+ @reject_names = value(REJECT_KEY, ctx, DEFAULT_REJECT_SET)
61
+ @accept_names = value(ACCEPT_KEY, ctx, DEFAULT_ACCEPT_SET)
62
+ ctx.exp.parameter_names.select do |name|
63
+ is_bad_name?(name, ctx)
64
+ end.map do |name|
65
+ smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
66
+ "has the parameter name '#{name}'",
67
+ @source, SMELL_SUBCLASS, {PARAMETER_NAME_KEY => name.to_s})
68
+ smell
62
69
  end
63
70
  end
64
71
 
65
- def is_bad_name?(name, context) # :nodoc:
72
+ def is_bad_name?(name, ctx)
66
73
  var = name.to_s.gsub(/^[@\*\&]*/, '')
67
- return false if var == '*' or value(ACCEPT_KEY, context, DEFAULT_ACCEPT_SET).include?(var)
68
- value(REJECT_KEY, context, DEFAULT_REJECT_SET).detect {|patt| patt === var}
74
+ return false if var == '*' or @accept_names.include?(var)
75
+ @reject_names.detect {|patt| patt === var}
69
76
  end
70
77
  end
71
78
  end
@@ -19,12 +19,16 @@ module Reek
19
19
  #
20
20
  class UncommunicativeVariableName < SmellDetector
21
21
 
22
+ SMELL_CLASS = 'UncommunicativeName'
23
+ SMELL_SUBCLASS = self.name.split(/::/)[-1]
24
+ VARIABLE_NAME_KEY = 'variable_name'
25
+
22
26
  # The name of the config field that lists the regexps of
23
27
  # smelly names to be reported.
24
28
  REJECT_KEY = 'reject'
25
29
 
26
30
  DEFAULT_REJECT_SET = [/^.$/, /[0-9]$/, /[A-Z]/]
27
-
31
+
28
32
  # The name of the config field that lists the specific names that are
29
33
  # to be treated as exceptions; these names will not be reported as
30
34
  # uncommunicative.
@@ -34,8 +38,8 @@ module Reek
34
38
 
35
39
  def self.default_config
36
40
  super.adopt(
37
- REJECT_KEY => DEFAULT_REJECT_SET,
38
- ACCEPT_KEY => DEFAULT_ACCEPT_SET
41
+ REJECT_KEY => DEFAULT_REJECT_SET,
42
+ ACCEPT_KEY => DEFAULT_ACCEPT_SET
39
43
  )
40
44
  end
41
45
 
@@ -49,32 +53,34 @@ module Reek
49
53
 
50
54
  #
51
55
  # Checks the given +context+ for uncommunicative names.
52
- # Remembers any smells found.
53
56
  #
54
- def examine_context(context)
55
- variable_names(context.exp).each do |name, lines|
56
- next unless is_bad_name?(name, context)
57
- smell = SmellWarning.new('UncommunicativeName', context.full_name, lines,
58
- "has the variable name '#{name}'",
59
- @source, 'UncommunicativeVariableName', {'variable_name' => name.to_s})
60
- @smells_found << smell
61
- #SMELL: serious duplication
57
+ # @return [Array<SmellWarning>]
58
+ #
59
+ def examine_context(ctx)
60
+ @reject_names = value(REJECT_KEY, ctx, DEFAULT_REJECT_SET)
61
+ @accept_names = value(ACCEPT_KEY, ctx, DEFAULT_ACCEPT_SET)
62
+ variable_names(ctx.exp).select do |name, lines|
63
+ is_bad_name?(name, ctx)
64
+ end.map do |name, lines|
65
+ SmellWarning.new(SMELL_CLASS, ctx.full_name, lines,
66
+ "has the variable name '#{name}'",
67
+ @source, SMELL_SUBCLASS, {VARIABLE_NAME_KEY => name.to_s})
62
68
  end
63
69
  end
64
70
 
65
- def is_bad_name?(name, context) # :nodoc:
71
+ def is_bad_name?(name, ctx)
66
72
  var = name.to_s.gsub(/^[@\*\&]*/, '')
67
- return false if value(ACCEPT_KEY, context, DEFAULT_ACCEPT_SET).include?(var)
68
- value(REJECT_KEY, context, DEFAULT_REJECT_SET).detect {|patt| patt === var}
73
+ return false if @accept_names.include?(var)
74
+ @reject_names.detect {|patt| patt === var}
69
75
  end
70
76
 
71
77
  def variable_names(exp)
72
78
  assignment_nodes = exp.each_node(:lasgn, [:class, :module, :defs, :defn])
73
79
  case exp.first
74
- when :class, :module
75
- assignment_nodes += exp.each_node(:iasgn, [:class, :module])
80
+ when :class, :module
81
+ assignment_nodes += exp.each_node(:iasgn, [:class, :module])
76
82
  end
77
- result = Hash.new {|hash,key| hash[key] = []}
83
+ result = Hash.new {|hash, key| hash[key] = []}
78
84
  assignment_nodes.each {|asgn| result[asgn[1]].push(asgn.line) }
79
85
  result
80
86
  end
@@ -61,18 +61,18 @@ module Reek
61
61
 
62
62
  #
63
63
  # Checks whether the given +method+ is a utility function.
64
- # Remembers any smells found.
64
+ #
65
+ # @return [Array<SmellWarning>]
65
66
  #
66
67
  def examine_context(method_ctx)
67
- return false if method_ctx.num_statements == 0
68
- return false if depends_on_instance?(method_ctx.exp)
69
- return false if num_helper_methods(method_ctx) <= value(HELPER_CALLS_LIMIT_KEY, method_ctx, DEFAULT_HELPER_CALLS_LIMIT)
68
+ return [] if method_ctx.num_statements == 0
69
+ return [] if depends_on_instance?(method_ctx.exp)
70
+ return [] if num_helper_methods(method_ctx) <= value(HELPER_CALLS_LIMIT_KEY, method_ctx, DEFAULT_HELPER_CALLS_LIMIT)
70
71
  # SMELL: loads of calls to value{} with the above pattern
71
72
  smell = SmellWarning.new(SMELL_CLASS, method_ctx.full_name, [method_ctx.exp.line],
72
73
  "doesn't depend on instance state",
73
74
  @source, SMELL_SUBCLASS)
74
- @smells_found << smell
75
- #SMELL: serious duplication
75
+ [smell]
76
76
  end
77
77
 
78
78
  private
@@ -7,13 +7,31 @@ module Reek
7
7
  # module, class and method definitions.
8
8
  #
9
9
  class CodeComment
10
+ CONFIG_REGEX = /:reek:(\w+)(:\s*\{.*?\})?/
10
11
 
11
12
  def initialize(text)
12
- @text = text.gsub(/#/, '').gsub(/\n/, '').strip
13
+ @config = Hash.new { |hash,key| hash[key] = {} }
14
+ @text = text.gsub(CONFIG_REGEX) do |m|
15
+ add_to_config($1, $2)
16
+ ''
17
+ end.gsub(/#/, '').gsub(/\n/, '').strip
13
18
  end
19
+
20
+ def config
21
+ @config
22
+ end
23
+
14
24
  def is_descriptive?
15
25
  @text.split(/\s+/).length >= 2
16
26
  end
27
+
28
+ protected
29
+ def add_to_config(smell, options)
30
+ options ||= ': { enabled: false }'
31
+ @config.merge! YAML.load(smell.gsub(/(?:^|_)(.)/) { $1.upcase } + options)
32
+ # extend this to all configs --------------------------^
33
+ # extend to allow configuration of whole smell class, not just subclass
34
+ end
17
35
  end
18
36
  end
19
37
  end
@@ -6,6 +6,17 @@ module Reek
6
6
  # syntax tree more easily.
7
7
  #
8
8
  module SexpNode
9
+ def self.format(expr)
10
+ case expr
11
+ when Sexp then expr.format_ruby
12
+ else expr.to_s
13
+ end
14
+ end
15
+
16
+ def hash
17
+ self.inspect.hash
18
+ end
19
+
9
20
  def is_language_node?
10
21
  first.class == Symbol
11
22
  end
@@ -37,7 +48,7 @@ module Reek
37
48
  end
38
49
  blk.call(self) if first == target_type
39
50
  end
40
- def format
51
+ def format_ruby
41
52
  return self[0].to_s unless Array === self
42
53
  Ruby2Ruby.new.process(deep_copy)
43
54
  end
@@ -64,15 +75,6 @@ module Reek
64
75
  end
65
76
  end
66
77
 
67
- module ClassNode
68
- def name() self[1] end
69
- def superclass() self[2] end
70
- def full_name(outer)
71
- prefix = outer == '' ? '' : "#{outer}::"
72
- "#{prefix}#{name}"
73
- end
74
- end
75
-
76
78
  module CvarNode
77
79
  def name() self[1] end
78
80
  end
@@ -80,24 +82,29 @@ module Reek
80
82
  CvasgnNode = CvarNode
81
83
  CvdeclNode = CvarNode
82
84
 
83
- module DefnNode
84
- def name() self[1] end
85
+ module MethodNode
85
86
  def arg_names
86
87
  unless @args
87
- @args = self[2][1..-1].reject {|param| Sexp === param or param.to_s =~ /^&/}
88
+ @args = argslist[1..-1].reject {|param| Sexp === param or param.to_s =~ /^&/}
88
89
  end
89
90
  @args
90
91
  end
91
92
  def parameters()
92
93
  unless @params
93
- @params = self[2].reject {|param| Sexp === param}
94
+ @params = argslist.reject {|param| Sexp === param}
94
95
  end
95
96
  @params
96
97
  end
97
98
  def parameter_names
98
99
  parameters[1..-1]
99
100
  end
101
+ end
102
+
103
+ module DefnNode
104
+ def name() self[1] end
105
+ def argslist() self[2] end
100
106
  def body() self[3] end
107
+ include MethodNode
101
108
  def full_name(outer)
102
109
  prefix = outer == '' ? '' : "#{outer}#"
103
110
  "#{prefix}#{name}"
@@ -107,16 +114,12 @@ module Reek
107
114
  module DefsNode
108
115
  def receiver() self[1] end
109
116
  def name() self[2] end
110
- def parameters
111
- self[3].reject {|param| Sexp === param}
112
- end
113
- def parameter_names
114
- parameters[1..-1]
115
- end
117
+ def argslist() self[3] end
116
118
  def body() self[4] end
119
+ include MethodNode
117
120
  def full_name(outer)
118
121
  prefix = outer == '' ? '' : "#{outer}#"
119
- "#{prefix}#{receiver.format}.#{name}"
122
+ "#{prefix}#{SexpNode.format(receiver)}.#{name}"
120
123
  end
121
124
  end
122
125
 
@@ -148,12 +151,27 @@ module Reek
148
151
 
149
152
  module ModuleNode
150
153
  def name() self[1] end
154
+ def simple_name
155
+ expr = name
156
+ while Sexp === expr and expr[0] == :colon2
157
+ expr = expr[2]
158
+ end
159
+ expr
160
+ end
151
161
  def full_name(outer)
152
162
  prefix = outer == '' ? '' : "#{outer}::"
153
- "#{prefix}#{name}"
163
+ "#{prefix}#{text_name}"
164
+ end
165
+ def text_name
166
+ SexpNode.format(name)
154
167
  end
155
168
  end
156
169
 
170
+ module ClassNode
171
+ include ModuleNode
172
+ def superclass() self[2] end
173
+ end
174
+
157
175
  module YieldNode
158
176
  def args() self[1..-1] end
159
177
  def arg_names
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{reek}
5
- s.version = "1.2.7.3"
5
+ s.version = "1.2.8"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Kevin Rutherford"]
9
- s.date = %q{2010-03-29}
9
+ s.date = %q{2010-04-26}
10
10
  s.default_executable = %q{reek}
11
11
  s.description = %q{Reek is a tool that examines Ruby classes, modules and methods
12
12
  and reports any code smells it finds.
@@ -14,10 +14,12 @@ and reports any code smells it finds.
14
14
  s.email = ["kevin@rutherford-software.com"]
15
15
  s.executables = ["reek"]
16
16
  s.extra_rdoc_files = ["History.txt", "License.txt"]
17
- s.files = [".yardopts", "History.txt", "License.txt", "README.md", "Rakefile", "bin/reek", "config/defaults.reek", "features/masking_smells.feature", "features/options.feature", "features/rake_task.feature", "features/reports.feature", "features/samples.feature", "features/stdin.feature", "features/step_definitions/reek_steps.rb", "features/support/env.rb", "features/yaml.feature", "lib/reek.rb", "lib/reek/cli/application.rb", "lib/reek/cli/command_line.rb", "lib/reek/cli/help_command.rb", "lib/reek/cli/reek_command.rb", "lib/reek/cli/report.rb", "lib/reek/cli/version_command.rb", "lib/reek/cli/yaml_command.rb", "lib/reek/core/code_context.rb", "lib/reek/core/code_parser.rb", "lib/reek/core/method_context.rb", "lib/reek/core/module_context.rb", "lib/reek/core/object_refs.rb", "lib/reek/core/singleton_method_context.rb", "lib/reek/core/smell_configuration.rb", "lib/reek/core/sniffer.rb", "lib/reek/core/stop_context.rb", "lib/reek/core/warning_collector.rb", "lib/reek/examiner.rb", "lib/reek/rake/task.rb", "lib/reek/smell_warning.rb", "lib/reek/smells.rb", "lib/reek/smells/attribute.rb", "lib/reek/smells/boolean_parameter.rb", "lib/reek/smells/class_variable.rb", "lib/reek/smells/control_couple.rb", "lib/reek/smells/data_clump.rb", "lib/reek/smells/duplication.rb", "lib/reek/smells/feature_envy.rb", "lib/reek/smells/irresponsible_module.rb", "lib/reek/smells/large_class.rb", "lib/reek/smells/long_method.rb", "lib/reek/smells/long_parameter_list.rb", "lib/reek/smells/long_yield_list.rb", "lib/reek/smells/nested_iterators.rb", "lib/reek/smells/simulated_polymorphism.rb", "lib/reek/smells/smell_detector.rb", "lib/reek/smells/uncommunicative_method_name.rb", "lib/reek/smells/uncommunicative_module_name.rb", "lib/reek/smells/uncommunicative_parameter_name.rb", "lib/reek/smells/uncommunicative_variable_name.rb", "lib/reek/smells/utility_function.rb", "lib/reek/source.rb", "lib/reek/source/code_comment.rb", "lib/reek/source/config_file.rb", "lib/reek/source/core_extras.rb", "lib/reek/source/reference_collector.rb", "lib/reek/source/sexp_formatter.rb", "lib/reek/source/source_code.rb", "lib/reek/source/source_file.rb", "lib/reek/source/source_locator.rb", "lib/reek/source/tree_dresser.rb", "lib/reek/spec.rb", "lib/reek/spec/should_reek.rb", "lib/reek/spec/should_reek_of.rb", "lib/reek/spec/should_reek_only_of.rb", "reek.gemspec", "spec/reek/cli/help_command_spec.rb", "spec/reek/cli/reek_command_spec.rb", "spec/reek/cli/report_spec.rb", "spec/reek/cli/version_command_spec.rb", "spec/reek/cli/yaml_command_spec.rb", "spec/reek/core/code_context_spec.rb", "spec/reek/core/code_parser_spec.rb", "spec/reek/core/config_spec.rb", "spec/reek/core/method_context_spec.rb", "spec/reek/core/module_context_spec.rb", "spec/reek/core/object_refs_spec.rb", "spec/reek/core/singleton_method_context_spec.rb", "spec/reek/core/smell_configuration_spec.rb", "spec/reek/core/stop_context_spec.rb", "spec/reek/core/warning_collector_spec.rb", "spec/reek/examiner_spec.rb", "spec/reek/smell_warning_spec.rb", "spec/reek/smells/attribute_spec.rb", "spec/reek/smells/behaves_like_variable_detector.rb", "spec/reek/smells/boolean_parameter_spec.rb", "spec/reek/smells/class_variable_spec.rb", "spec/reek/smells/control_couple_spec.rb", "spec/reek/smells/data_clump_spec.rb", "spec/reek/smells/duplication_spec.rb", "spec/reek/smells/feature_envy_spec.rb", "spec/reek/smells/irresponsible_module_spec.rb", "spec/reek/smells/large_class_spec.rb", "spec/reek/smells/long_method_spec.rb", "spec/reek/smells/long_parameter_list_spec.rb", "spec/reek/smells/long_yield_list_spec.rb", "spec/reek/smells/nested_iterators_spec.rb", "spec/reek/smells/simulated_polymorphism_spec.rb", "spec/reek/smells/smell_detector_shared.rb", "spec/reek/smells/uncommunicative_method_name_spec.rb", "spec/reek/smells/uncommunicative_module_name_spec.rb", "spec/reek/smells/uncommunicative_parameter_name_spec.rb", "spec/reek/smells/uncommunicative_variable_name_spec.rb", "spec/reek/smells/utility_function_spec.rb", "spec/reek/source/code_comment_spec.rb", "spec/reek/source/object_source_spec.rb", "spec/reek/source/reference_collector_spec.rb", "spec/reek/source/source_code_spec.rb", "spec/reek/source/tree_dresser_spec.rb", "spec/reek/spec/should_reek_of_spec.rb", "spec/reek/spec/should_reek_only_of_spec.rb", "spec/reek/spec/should_reek_spec.rb", "spec/samples/all_but_one_masked/clean_one.rb", "spec/samples/all_but_one_masked/dirty.rb", "spec/samples/all_but_one_masked/masked.reek", "spec/samples/clean_due_to_masking/clean_one.rb", "spec/samples/clean_due_to_masking/clean_three.rb", "spec/samples/clean_due_to_masking/clean_two.rb", "spec/samples/clean_due_to_masking/dirty_one.rb", "spec/samples/clean_due_to_masking/dirty_two.rb", "spec/samples/clean_due_to_masking/masked.reek", "spec/samples/corrupt_config_file/corrupt.reek", "spec/samples/corrupt_config_file/dirty.rb", "spec/samples/empty_config_file/dirty.rb", "spec/samples/empty_config_file/empty.reek", "spec/samples/exceptions.reek", "spec/samples/inline.rb", "spec/samples/masked/dirty.rb", "spec/samples/masked/masked.reek", "spec/samples/mixed_results/clean_one.rb", "spec/samples/mixed_results/clean_three.rb", "spec/samples/mixed_results/clean_two.rb", "spec/samples/mixed_results/dirty_one.rb", "spec/samples/mixed_results/dirty_two.rb", "spec/samples/not_quite_masked/dirty.rb", "spec/samples/not_quite_masked/masked.reek", "spec/samples/optparse.rb", "spec/samples/overrides/masked/dirty.rb", "spec/samples/overrides/masked/lower.reek", "spec/samples/overrides/upper.reek", "spec/samples/redcloth.rb", "spec/samples/three_clean_files/clean_one.rb", "spec/samples/three_clean_files/clean_three.rb", "spec/samples/three_clean_files/clean_two.rb", "spec/samples/two_smelly_files/dirty_one.rb", "spec/samples/two_smelly_files/dirty_two.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/reek.rake", "tasks/test.rake"]
17
+ s.files = [".yardopts", "History.txt", "License.txt", "README.md", "Rakefile", "bin/reek", "config/defaults.reek", "features/api.feature", "features/masking_smells.feature", "features/options.feature", "features/rake_task.feature", "features/reports.feature", "features/samples.feature", "features/stdin.feature", "features/step_definitions/reek_steps.rb", "features/support/env.rb", "features/yaml.feature", "lib/reek.rb", "lib/reek/cli/application.rb", "lib/reek/cli/command_line.rb", "lib/reek/cli/help_command.rb", "lib/reek/cli/reek_command.rb", "lib/reek/cli/report.rb", "lib/reek/cli/version_command.rb", "lib/reek/cli/yaml_command.rb", "lib/reek/core/code_context.rb", "lib/reek/core/code_parser.rb", "lib/reek/core/method_context.rb", "lib/reek/core/module_context.rb", "lib/reek/core/object_refs.rb", "lib/reek/core/singleton_method_context.rb", "lib/reek/core/smell_configuration.rb", "lib/reek/core/sniffer.rb", "lib/reek/core/stop_context.rb", "lib/reek/core/warning_collector.rb", "lib/reek/examiner.rb", "lib/reek/rake/task.rb", "lib/reek/smell_warning.rb", "lib/reek/smells.rb", "lib/reek/smells/attribute.rb", "lib/reek/smells/boolean_parameter.rb", "lib/reek/smells/class_variable.rb", "lib/reek/smells/control_couple.rb", "lib/reek/smells/data_clump.rb", "lib/reek/smells/duplication.rb", "lib/reek/smells/feature_envy.rb", "lib/reek/smells/irresponsible_module.rb", "lib/reek/smells/large_class.rb", "lib/reek/smells/long_method.rb", "lib/reek/smells/long_parameter_list.rb", "lib/reek/smells/long_yield_list.rb", "lib/reek/smells/nested_iterators.rb", "lib/reek/smells/simulated_polymorphism.rb", "lib/reek/smells/smell_detector.rb", "lib/reek/smells/uncommunicative_method_name.rb", "lib/reek/smells/uncommunicative_module_name.rb", "lib/reek/smells/uncommunicative_parameter_name.rb", "lib/reek/smells/uncommunicative_variable_name.rb", "lib/reek/smells/utility_function.rb", "lib/reek/source.rb", "lib/reek/source/code_comment.rb", "lib/reek/source/config_file.rb", "lib/reek/source/core_extras.rb", "lib/reek/source/reference_collector.rb", "lib/reek/source/sexp_formatter.rb", "lib/reek/source/source_code.rb", "lib/reek/source/source_file.rb", "lib/reek/source/source_locator.rb", "lib/reek/source/tree_dresser.rb", "lib/reek/spec.rb", "lib/reek/spec/should_reek.rb", "lib/reek/spec/should_reek_of.rb", "lib/reek/spec/should_reek_only_of.rb", "reek.gemspec", "spec/matchers/smell_of_matcher.rb", "spec/reek/cli/help_command_spec.rb", "spec/reek/cli/reek_command_spec.rb", "spec/reek/cli/report_spec.rb", "spec/reek/cli/version_command_spec.rb", "spec/reek/cli/yaml_command_spec.rb", "spec/reek/core/code_context_spec.rb", "spec/reek/core/code_parser_spec.rb", "spec/reek/core/config_spec.rb", "spec/reek/core/method_context_spec.rb", "spec/reek/core/module_context_spec.rb", "spec/reek/core/object_refs_spec.rb", "spec/reek/core/singleton_method_context_spec.rb", "spec/reek/core/smell_configuration_spec.rb", "spec/reek/core/stop_context_spec.rb", "spec/reek/core/warning_collector_spec.rb", "spec/reek/examiner_spec.rb", "spec/reek/smell_warning_spec.rb", "spec/reek/smells/attribute_spec.rb", "spec/reek/smells/behaves_like_variable_detector.rb", "spec/reek/smells/boolean_parameter_spec.rb", "spec/reek/smells/class_variable_spec.rb", "spec/reek/smells/control_couple_spec.rb", "spec/reek/smells/data_clump_spec.rb", "spec/reek/smells/duplication_spec.rb", "spec/reek/smells/feature_envy_spec.rb", "spec/reek/smells/irresponsible_module_spec.rb", "spec/reek/smells/large_class_spec.rb", "spec/reek/smells/long_method_spec.rb", "spec/reek/smells/long_parameter_list_spec.rb", "spec/reek/smells/long_yield_list_spec.rb", "spec/reek/smells/nested_iterators_spec.rb", "spec/reek/smells/simulated_polymorphism_spec.rb", "spec/reek/smells/smell_detector_shared.rb", "spec/reek/smells/uncommunicative_method_name_spec.rb", "spec/reek/smells/uncommunicative_module_name_spec.rb", "spec/reek/smells/uncommunicative_parameter_name_spec.rb", "spec/reek/smells/uncommunicative_variable_name_spec.rb", "spec/reek/smells/utility_function_spec.rb", "spec/reek/source/code_comment_spec.rb", "spec/reek/source/object_source_spec.rb", "spec/reek/source/reference_collector_spec.rb", "spec/reek/source/source_code_spec.rb", "spec/reek/source/tree_dresser_spec.rb", "spec/reek/spec/should_reek_of_spec.rb", "spec/reek/spec/should_reek_only_of_spec.rb", "spec/reek/spec/should_reek_spec.rb", "spec/samples/all_but_one_masked/clean_one.rb", "spec/samples/all_but_one_masked/dirty.rb", "spec/samples/all_but_one_masked/masked.reek", "spec/samples/clean_due_to_masking/clean_one.rb", "spec/samples/clean_due_to_masking/clean_three.rb", "spec/samples/clean_due_to_masking/clean_two.rb", "spec/samples/clean_due_to_masking/dirty_one.rb", "spec/samples/clean_due_to_masking/dirty_two.rb", "spec/samples/clean_due_to_masking/masked.reek", "spec/samples/config/allow_duplication.reek", "spec/samples/config/deeper_nested_iterators.reek", "spec/samples/corrupt_config_file/corrupt.reek", "spec/samples/corrupt_config_file/dirty.rb", "spec/samples/demo/demo.rb", "spec/samples/empty_config_file/dirty.rb", "spec/samples/empty_config_file/empty.reek", "spec/samples/exceptions.reek", "spec/samples/inline_config/dirty.rb", "spec/samples/inline_config/masked.reek", "spec/samples/inline.rb", "spec/samples/mask_some/dirty.rb", "spec/samples/mask_some/some.reek", "spec/samples/masked/dirty.rb", "spec/samples/masked/masked.reek", "spec/samples/mixed_results/clean_one.rb", "spec/samples/mixed_results/clean_three.rb", "spec/samples/mixed_results/clean_two.rb", "spec/samples/mixed_results/dirty_one.rb", "spec/samples/mixed_results/dirty_two.rb", "spec/samples/not_quite_masked/dirty.rb", "spec/samples/not_quite_masked/masked.reek", "spec/samples/optparse.rb", "spec/samples/overrides/masked/dirty.rb", "spec/samples/overrides/masked/lower.reek", "spec/samples/overrides/upper.reek", "spec/samples/redcloth.rb", "spec/samples/three_clean_files/clean_one.rb", "spec/samples/three_clean_files/clean_three.rb", "spec/samples/three_clean_files/clean_two.rb", "spec/samples/two_smelly_files/dirty_one.rb", "spec/samples/two_smelly_files/dirty_two.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/reek.rake", "tasks/test.rake"]
18
18
  s.homepage = %q{http://wiki.github.com/kevinrutherford/reek}
19
19
  s.post_install_message = %q{
20
- For more information on reek, see http://wiki.github.com/kevinrutherford/reek
20
+ Thank you for downloading Reek. For info:
21
+ - see the reek wiki http://wiki.github.com/kevinrutherford/reek
22
+ - follow @rubyreek on twitter
21
23
  }
22
24
  s.rdoc_options = ["--main", "README.md"]
23
25
  s.require_paths = ["lib"]
@@ -0,0 +1,58 @@
1
+ module SmellOfMatcher
2
+ class SmellOf
3
+ def initialize(klass, *expected_smells)
4
+ @klass = klass
5
+ @expected_smells = expected_smells
6
+ @config = {}
7
+ end
8
+
9
+ def failure_message_for_should
10
+ "Expected #{@source.desc} to smell of #{@klass}, but it didn't: #{@reason}"
11
+ end
12
+
13
+ def failure_message_for_should_not
14
+ "Expected #{@source.desc} not to smell of #{@klass}, but it did"
15
+ end
16
+
17
+ def matches?(src)
18
+ @source = src.to_reek_source
19
+ ctx = MethodContext.new(nil, @source.syntax_tree)
20
+ detector = @klass.new(@source.desc, @klass.default_config.merge(@config))
21
+ detector.examine(ctx)
22
+ actual_smells = detector.smells_found.to_a
23
+ if actual_smells.empty?
24
+ @reason = 'no smells found by detector'
25
+ return false
26
+ end
27
+ return false if actual_smells.any? do |expected_smell|
28
+ @reason = "Found #{expected_smell.smell_class}/#{expected_smell.subclass}" &&
29
+ expected_smell.smell_class != @klass::SMELL_CLASS &&
30
+ expected_smell.subclass != @klass::SMELL_SUBCLASS
31
+ end
32
+ return actual_smells.length == 1 if @expected_smells.empty?
33
+ return false unless @expected_smells.length == actual_smells.length
34
+ @expected_smells.each_with_index do |expected_smell,index|
35
+ expected_smell.each do |(key,value)|
36
+ if actual_smells[index].smell[key] != value
37
+ @reason = "#{key} != #{value}"
38
+ return false
39
+ end
40
+ end
41
+ end
42
+ true
43
+ end
44
+
45
+ def with_config(options)
46
+ @config = options
47
+ self
48
+ end
49
+ end
50
+
51
+ def smell_of(klass, *smells)
52
+ SmellOf.new(klass, *smells)
53
+ end
54
+ end
55
+
56
+ Spec::Runner.configure do |config|
57
+ config.include(SmellOfMatcher)
58
+ end
@@ -13,6 +13,7 @@ describe CodeContext do
13
13
  @exp = mock('exp')
14
14
  @exp.should_receive(:name).any_number_of_times.and_return(@exp_name)
15
15
  @exp.should_receive(:full_name).any_number_of_times.and_return(@full_name)
16
+ @exp.should_receive(:comments).any_number_of_times.and_return('')
16
17
  @ctx = CodeContext.new(nil, @exp)
17
18
  end
18
19
  it 'gets its short name from the exp' do
@@ -36,6 +37,7 @@ describe CodeContext do
36
37
  @outer_name = 'another_random sting'
37
38
  outer = mock('outer')
38
39
  outer.should_receive(:full_name).at_least(:once).and_return(@outer_name)
40
+ outer.should_receive(:config).and_return({})
39
41
  @ctx = CodeContext.new(outer, @exp)
40
42
  end
41
43
  it 'creates the correct full name' do
@@ -54,8 +56,8 @@ describe CodeContext do
54
56
  it 'should pass unknown method calls down the stack' do
55
57
  stop = StopContext.new
56
58
  def stop.bananas(arg1, arg2) arg1 + arg2 + 43 end
57
- element = ModuleContext.new(stop, 'mod', s(:module, :mod, nil))
58
- element = MethodContext.new(element, [0, :bad])
59
+ element = ModuleContext.new(stop, 'mod', ast(:module, :mod, nil))
60
+ element = MethodContext.new(element, ast(:defn, :bad))
59
61
  element.bananas(17, -5).should == 55
60
62
  end
61
63
  end
@@ -15,7 +15,8 @@ end
15
15
 
16
16
  describe CodeParser, 'with a global method definition' do
17
17
  it 'reports no problems for simple method' do
18
- 'def Outermost::fred() true; end'.should_not reek
18
+ src = 'def Outermost::fred() true; end'
19
+ src.should_not reek
19
20
  end
20
21
  end
21
22