reek 1.3.8 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +11 -0
  3. data/README.md +22 -14
  4. data/Rakefile +2 -15
  5. data/assets/html_output.html.erb +103 -0
  6. data/features/command_line_interface/options.feature +3 -0
  7. data/features/command_line_interface/smell_selection.feature +19 -0
  8. data/features/rake_task/rake_task.feature +1 -1
  9. data/features/reports/reports.feature +16 -0
  10. data/features/reports/yaml.feature +26 -23
  11. data/features/samples.feature +2 -1
  12. data/features/step_definitions/reek_steps.rb +15 -15
  13. data/features/support/env.rb +7 -9
  14. data/lib/reek/cli/application.rb +2 -4
  15. data/lib/reek/cli/command.rb +12 -0
  16. data/lib/reek/cli/help_command.rb +3 -6
  17. data/lib/reek/cli/options.rb +147 -0
  18. data/lib/reek/cli/reek_command.rb +18 -14
  19. data/lib/reek/cli/report/formatter.rb +56 -0
  20. data/lib/reek/cli/report/report.rb +106 -0
  21. data/lib/reek/cli/report/strategy.rb +63 -0
  22. data/lib/reek/cli/version_command.rb +3 -6
  23. data/lib/reek/config_file_exception.rb +0 -1
  24. data/lib/reek/core/code_context.rb +1 -3
  25. data/lib/reek/core/code_parser.rb +13 -12
  26. data/lib/reek/core/method_context.rb +13 -2
  27. data/lib/reek/core/module_context.rb +0 -4
  28. data/lib/reek/core/object_refs.rb +2 -3
  29. data/lib/reek/core/singleton_method_context.rb +0 -2
  30. data/lib/reek/core/smell_configuration.rb +3 -5
  31. data/lib/reek/core/smell_repository.rb +7 -8
  32. data/lib/reek/core/sniffer.rb +4 -10
  33. data/lib/reek/core/stop_context.rb +2 -4
  34. data/lib/reek/core/warning_collector.rb +0 -1
  35. data/lib/reek/examiner.rb +19 -17
  36. data/lib/reek/rake/task.rb +7 -10
  37. data/lib/reek/smell_warning.rb +4 -8
  38. data/lib/reek/smells.rb +0 -1
  39. data/lib/reek/smells/attribute.rb +8 -11
  40. data/lib/reek/smells/boolean_parameter.rb +5 -7
  41. data/lib/reek/smells/class_variable.rb +6 -7
  42. data/lib/reek/smells/control_parameter.rb +78 -45
  43. data/lib/reek/smells/data_clump.rb +13 -16
  44. data/lib/reek/smells/duplicate_method_call.rb +13 -11
  45. data/lib/reek/smells/feature_envy.rb +6 -7
  46. data/lib/reek/smells/irresponsible_module.rb +4 -6
  47. data/lib/reek/smells/long_parameter_list.rb +5 -7
  48. data/lib/reek/smells/long_yield_list.rb +2 -4
  49. data/lib/reek/smells/nested_iterators.rb +12 -22
  50. data/lib/reek/smells/nil_check.rb +35 -46
  51. data/lib/reek/smells/prima_donna_method.rb +24 -16
  52. data/lib/reek/smells/repeated_conditional.rb +8 -10
  53. data/lib/reek/smells/smell_detector.rb +9 -7
  54. data/lib/reek/smells/too_many_instance_variables.rb +7 -9
  55. data/lib/reek/smells/too_many_methods.rb +6 -8
  56. data/lib/reek/smells/too_many_statements.rb +4 -6
  57. data/lib/reek/smells/uncommunicative_method_name.rb +5 -7
  58. data/lib/reek/smells/uncommunicative_module_name.rb +5 -7
  59. data/lib/reek/smells/uncommunicative_parameter_name.rb +7 -9
  60. data/lib/reek/smells/uncommunicative_variable_name.rb +15 -18
  61. data/lib/reek/smells/unused_parameters.rb +5 -45
  62. data/lib/reek/smells/utility_function.rb +9 -10
  63. data/lib/reek/source.rb +0 -1
  64. data/lib/reek/source/code_comment.rb +7 -8
  65. data/lib/reek/source/config_file.rb +2 -4
  66. data/lib/reek/source/core_extras.rb +1 -1
  67. data/lib/reek/source/reference_collector.rb +1 -2
  68. data/lib/reek/source/sexp_extensions.rb +93 -10
  69. data/lib/reek/source/sexp_formatter.rb +2 -3
  70. data/lib/reek/source/sexp_node.rb +19 -15
  71. data/lib/reek/source/source_code.rb +4 -14
  72. data/lib/reek/source/source_file.rb +3 -5
  73. data/lib/reek/source/source_locator.rb +5 -6
  74. data/lib/reek/source/source_repository.rb +3 -3
  75. data/lib/reek/source/tree_dresser.rb +2 -2
  76. data/lib/reek/spec.rb +1 -2
  77. data/lib/reek/spec/should_reek.rb +8 -5
  78. data/lib/reek/spec/should_reek_of.rb +6 -4
  79. data/lib/reek/spec/should_reek_only_of.rb +10 -6
  80. data/lib/reek/version.rb +1 -1
  81. data/reek.gemspec +34 -30
  82. data/spec/gem/updates_spec.rb +3 -4
  83. data/spec/gem/yard_spec.rb +1 -2
  84. data/spec/matchers/smell_of_matcher.rb +12 -14
  85. data/spec/quality/reek_source_spec.rb +42 -0
  86. data/spec/reek/cli/help_command_spec.rb +7 -5
  87. data/spec/reek/cli/report_spec.rb +89 -22
  88. data/spec/reek/cli/version_command_spec.rb +8 -6
  89. data/spec/reek/core/code_context_spec.rb +25 -26
  90. data/spec/reek/core/code_parser_spec.rb +6 -6
  91. data/spec/reek/core/method_context_spec.rb +18 -18
  92. data/spec/reek/core/module_context_spec.rb +5 -5
  93. data/spec/reek/core/object_refs_spec.rb +21 -22
  94. data/spec/reek/core/smell_configuration_spec.rb +22 -21
  95. data/spec/reek/core/stop_context_spec.rb +2 -2
  96. data/spec/reek/core/warning_collector_spec.rb +3 -3
  97. data/spec/reek/examiner_spec.rb +9 -9
  98. data/spec/reek/smell_warning_spec.rb +29 -29
  99. data/spec/reek/smells/attribute_spec.rb +6 -6
  100. data/spec/reek/smells/behaves_like_variable_detector.rb +6 -6
  101. data/spec/reek/smells/boolean_parameter_spec.rb +17 -17
  102. data/spec/reek/smells/class_variable_spec.rb +9 -9
  103. data/spec/reek/smells/control_parameter_spec.rb +161 -137
  104. data/spec/reek/smells/data_clump_spec.rb +22 -19
  105. data/spec/reek/smells/duplicate_method_call_spec.rb +71 -27
  106. data/spec/reek/smells/feature_envy_spec.rb +32 -32
  107. data/spec/reek/smells/irresponsible_module_spec.rb +21 -21
  108. data/spec/reek/smells/long_parameter_list_spec.rb +14 -14
  109. data/spec/reek/smells/long_yield_list_spec.rb +6 -6
  110. data/spec/reek/smells/nested_iterators_spec.rb +21 -21
  111. data/spec/reek/smells/nil_check_spec.rb +23 -15
  112. data/spec/reek/smells/prima_donna_method_spec.rb +5 -5
  113. data/spec/reek/smells/repeated_conditional_spec.rb +14 -14
  114. data/spec/reek/smells/smell_detector_shared.rb +9 -9
  115. data/spec/reek/smells/too_many_instance_variables_spec.rb +12 -12
  116. data/spec/reek/smells/too_many_methods_spec.rb +10 -10
  117. data/spec/reek/smells/too_many_statements_spec.rb +41 -41
  118. data/spec/reek/smells/uncommunicative_method_name_spec.rb +4 -4
  119. data/spec/reek/smells/uncommunicative_module_name_spec.rb +12 -12
  120. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +21 -21
  121. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +49 -49
  122. data/spec/reek/smells/unused_parameters_spec.rb +26 -16
  123. data/spec/reek/smells/utility_function_spec.rb +20 -20
  124. data/spec/reek/source/code_comment_spec.rb +37 -37
  125. data/spec/reek/source/object_source_spec.rb +5 -5
  126. data/spec/reek/source/reference_collector_spec.rb +9 -9
  127. data/spec/reek/source/sexp_extensions_spec.rb +73 -52
  128. data/spec/reek/source/sexp_formatter_spec.rb +3 -4
  129. data/spec/reek/source/sexp_node_spec.rb +3 -3
  130. data/spec/reek/source/source_code_spec.rb +16 -15
  131. data/spec/reek/source/tree_dresser_spec.rb +2 -2
  132. data/spec/reek/spec/should_reek_of_spec.rb +11 -11
  133. data/spec/reek/spec/should_reek_only_of_spec.rb +11 -11
  134. data/spec/reek/spec/should_reek_spec.rb +11 -11
  135. data/spec/samples/one_smelly_file/dirty.rb +3 -0
  136. data/spec/spec_helper.rb +0 -6
  137. data/tasks/develop.rake +8 -16
  138. data/tasks/reek.rake +5 -13
  139. data/tasks/test.rake +5 -22
  140. metadata +56 -34
  141. data/lib/reek/cli/command_line.rb +0 -126
  142. data/lib/reek/cli/report.rb +0 -138
@@ -2,24 +2,22 @@ require 'reek/source/source_code'
2
2
 
3
3
  module Reek
4
4
  module Source
5
-
6
5
  #
7
6
  # Represents a file of Ruby source, whose contents will be examined
8
7
  # for code smells.
9
8
  #
10
9
  class SourceFile < SourceCode
11
-
12
10
  def initialize(path)
13
11
  @path = path
14
12
  super(IO.readlines(@path).join, @path)
15
13
  end
16
14
 
17
- def configure(sniffer)
15
+ def relevant_config_files
18
16
  path = File.expand_path(File.dirname(@path))
19
- all_config_files(path).each { |cf| ConfigFile.new(cf).configure(sniffer) }
17
+ all_config_files(path)
20
18
  end
21
19
 
22
- private
20
+ private
23
21
 
24
22
  def all_config_files(path)
25
23
  return [] unless File.exist?(path)
@@ -2,24 +2,23 @@ require 'reek/source/core_extras'
2
2
 
3
3
  module Reek
4
4
  module Source
5
-
6
5
  #
7
6
  # Finds Ruby source files in a filesystem.
8
7
  #
9
8
  class SourceLocator
10
9
  def initialize(paths)
11
- @paths = paths.map {|path| path.chomp('/') }
10
+ @paths = paths.map { |path| path.chomp('/') }
12
11
  end
13
12
 
14
13
  def all_sources
15
- valid_paths.map {|path| File.new(path).to_reek_source }
14
+ valid_paths.map { |path| File.new(path).to_reek_source }
16
15
  end
17
16
 
18
- private
17
+ private
19
18
 
20
19
  def all_ruby_source_files(paths)
21
20
  paths.map do |path|
22
- if test ?d, path
21
+ if test 'd', path
23
22
  all_ruby_source_files(Dir["#{path}/**/*.rb"])
24
23
  else
25
24
  path
@@ -29,7 +28,7 @@ module Reek
29
28
 
30
29
  def valid_paths
31
30
  all_ruby_source_files(@paths).select do |path|
32
- if test ?f, path
31
+ if test 'f', path
33
32
  true
34
33
  else
35
34
  $stderr.puts "Error: No such file - #{path}"
@@ -10,7 +10,7 @@ module Reek
10
10
  # single unit of Ruby source code.
11
11
  #
12
12
  class SourceRepository
13
- def self.parse source
13
+ def self.parse(source)
14
14
  case source
15
15
  when Array
16
16
  new 'dir', Source::SourceLocator.new(source).all_sources
@@ -25,12 +25,12 @@ module Reek
25
25
  include Enumerable
26
26
  attr_reader :description
27
27
 
28
- def initialize description, sources
28
+ def initialize(description, sources)
29
29
  @description = description
30
30
  @sources = sources
31
31
  end
32
32
 
33
- def each &block
33
+ def each(&block)
34
34
  @sources.each(&block)
35
35
  end
36
36
  end
@@ -33,12 +33,12 @@ module Reek
33
33
 
34
34
  def extension_map
35
35
  @extension_map ||= begin
36
- assoc = @extensions_module.constants.map { |const|
36
+ assoc = @extensions_module.constants.map do |const|
37
37
  [
38
38
  const.to_s.sub(/Node$/, '').downcase.to_sym,
39
39
  @extensions_module.const_get(const)
40
40
  ]
41
- }
41
+ end
42
42
  Hash[assoc]
43
43
  end
44
44
  end
data/lib/reek/spec.rb CHANGED
@@ -3,7 +3,6 @@ require 'reek/spec/should_reek_of'
3
3
  require 'reek/spec/should_reek_only_of'
4
4
 
5
5
  module Reek
6
-
7
6
  #
8
7
  # Provides matchers for Rspec, making it easy to check code quality.
9
8
  #
@@ -34,7 +33,7 @@ module Reek
34
33
  # 'def equals(other) other.thing == self.thing end'.should_not reek
35
34
  #
36
35
  # To check for specific smells, use something like this:
37
- #
36
+ #
38
37
  # ruby = 'def double_thing() @other.thing.foo + @other.thing.foo end'
39
38
  # ruby.should reek_of(:Duplication, /@other.thing[^\.]/)
40
39
  # ruby.should reek_of(:Duplication, /@other.thing.foo/)
@@ -1,9 +1,10 @@
1
1
  require 'reek/examiner'
2
- require 'reek/cli/report'
2
+ require 'reek/cli/report/report'
3
+ require 'reek/cli/report/formatter'
4
+ require 'reek/cli/report/strategy'
3
5
 
4
6
  module Reek
5
7
  module Spec
6
-
7
8
  #
8
9
  # An rspec matcher that matches when the +actual+ has code smells.
9
10
  #
@@ -12,11 +13,13 @@ module Reek
12
13
  @examiner = Examiner.new(actual)
13
14
  @examiner.smelly?
14
15
  end
15
- def failure_message_for_should
16
+
17
+ def failure_message
16
18
  "Expected #{@examiner.description} to reek, but it didn't"
17
19
  end
18
- def failure_message_for_should_not
19
- rpt = Cli::ReportFormatter.format_list(@examiner.smells)
20
+
21
+ def failure_message_when_negated
22
+ rpt = Cli::Report::Formatter.format_list(@examiner.smells)
20
23
  "Expected no smells, but got:\n#{rpt}"
21
24
  end
22
25
  end
@@ -2,7 +2,6 @@ require 'reek/examiner'
2
2
 
3
3
  module Reek
4
4
  module Spec
5
-
6
5
  #
7
6
  # An rspec matcher that matches when the +actual+ has the specified
8
7
  # code smell.
@@ -12,15 +11,18 @@ module Reek
12
11
  @klass = klass
13
12
  @patterns = patterns
14
13
  end
14
+
15
15
  def matches?(actual)
16
16
  @examiner = Examiner.new(actual)
17
17
  @all_smells = @examiner.smells
18
- @all_smells.any? {|warning| warning.matches?(@klass, @patterns)}
18
+ @all_smells.any? { |warning| warning.matches?(@klass, @patterns) }
19
19
  end
20
- def failure_message_for_should
20
+
21
+ def failure_message
21
22
  "Expected #{@examiner.description} to reek of #{@klass}, but it didn't"
22
23
  end
23
- def failure_message_for_should_not
24
+
25
+ def failure_message_when_negated
24
26
  "Expected #{@examiner.description} not to reek of #{@klass}, but it did"
25
27
  end
26
28
  end
@@ -1,9 +1,10 @@
1
1
  require 'reek/examiner'
2
- require 'reek/cli/report'
2
+ require 'reek/cli/report/report'
3
+ require 'reek/cli/report/formatter'
4
+ require 'reek/cli/report/strategy'
3
5
 
4
6
  module Reek
5
7
  module Spec
6
-
7
8
  #
8
9
  # An rspec matcher that matches when the +actual+ has the specified
9
10
  # code smell and no others.
@@ -12,16 +13,19 @@ module Reek
12
13
  def matches?(actual)
13
14
  matches_examiner?(Examiner.new(actual))
14
15
  end
16
+
15
17
  def matches_examiner?(examiner)
16
18
  @examiner = examiner
17
19
  @warnings = @examiner.smells
18
- @warnings.length == 1 and @warnings[0].matches?(@klass, @patterns)
20
+ @warnings.length == 1 && @warnings[0].matches?(@klass, @patterns)
19
21
  end
20
- def failure_message_for_should
21
- rpt = Cli::ReportFormatter.format_list(@warnings)
22
+
23
+ def failure_message
24
+ rpt = Cli::Report::Formatter.format_list(@warnings)
22
25
  "Expected #{@examiner.description} to reek only of #{@klass}, but got:\n#{rpt}"
23
26
  end
24
- def failure_message_for_should_not
27
+
28
+ def failure_message_when_negated
25
29
  "Expected #{@examiner.description} not to reek only of #{@klass}, but it did"
26
30
  end
27
31
  end
data/lib/reek/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Reek
2
- VERSION = '1.3.8'
2
+ VERSION = '1.4.0'
3
3
  end
data/reek.gemspec CHANGED
@@ -1,40 +1,44 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.join(File.dirname(__FILE__), "lib")
2
+ $LOAD_PATH.push File.join(File.dirname(__FILE__), 'lib')
3
3
  require 'reek/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
- s.name = %q{reek}
6
+ s.name = 'reek'
7
7
  s.version = Reek::VERSION
8
8
 
9
9
  s.authors = ['Kevin Rutherford', 'Timo Roessner', 'Matijs van Zuijlen']
10
- s.default_executable = %q{reek}
11
- s.description = %q{Reek is a tool that examines Ruby classes, modules and methods
12
- and reports any code smells it finds.
13
- }
14
- s.email = ["timo.roessner@googlemail.com"]
15
- s.executables = ["reek"]
16
- s.extra_rdoc_files = ["CHANGELOG", "License.txt"]
17
- s.files = Dir[".yardopts", "CHANGELOG", "License.txt", "README.md",
18
- "Rakefile", "bin/reek", "config/defaults.reek",
19
- "{features,lib,spec,tasks}/**/*",
20
- "reek.gemspec" ] & `git ls-files -z`.split("\0")
21
- s.homepage = %q{http://wiki.github.com/troessner/reek}
22
- s.post_install_message = %q{Thank you for downloading Reek. For info see the reek wiki http://wiki.github.com/troessner/reek}
23
- s.rdoc_options = ["--main", "README.md"]
24
- s.require_paths = ["lib"]
25
- s.rubyforge_project = %q{reek}
26
- s.rubygems_version = %q{1.3.6}
27
- s.summary = %q{Code smell detector for Ruby}
10
+ s.default_executable = 'reek'
11
+ s.description = <<-DESC
12
+ Reek is a tool that examines Ruby classes, modules and methods and reports
13
+ any code smells it finds.
14
+ DESC
28
15
 
29
- s.add_runtime_dependency(%q<ruby_parser>, ["~> 3.3"])
30
- s.add_runtime_dependency(%q<sexp_processor>)
31
- s.add_runtime_dependency(%q<ruby2ruby>, [">= 2.0.8", "< 3.0"])
32
- s.add_runtime_dependency(%q<rainbow>, [">= 1.99", "< 3.0"])
16
+ s.license = 'MIT'
17
+ s.email = ['timo.roessner@googlemail.com']
18
+ s.executables = ['reek']
19
+ s.extra_rdoc_files = ['CHANGELOG', 'License.txt']
20
+ s.files = Dir['.yardopts', 'CHANGELOG', 'License.txt', 'README.md',
21
+ 'Rakefile', 'assets/html_output.html.erb', 'bin/reek', 'config/defaults.reek',
22
+ '{features,lib,spec,tasks}/**/*',
23
+ 'reek.gemspec'] & `git ls-files -z`.split("\0")
24
+ s.homepage = 'http://wiki.github.com/troessner/reek'
25
+ s.rdoc_options = ['--main', 'README.md',
26
+ '-x', 'assets/|bin/|config/|features/|spec/|tasks/']
27
+ s.require_paths = ['lib']
28
+ s.rubyforge_project = 'reek'
29
+ s.rubygems_version = '1.3.6'
30
+ s.required_ruby_version = '>= 1.9.2'
31
+ s.summary = 'Code smell detector for Ruby'
33
32
 
34
- s.add_development_dependency(%q<bundler>, ["~> 1.1"])
35
- s.add_development_dependency(%q<rake>)
36
- s.add_development_dependency(%q<cucumber>)
37
- s.add_development_dependency(%q<rspec>, ["~> 2.12"])
38
- s.add_development_dependency(%q<flay>)
39
- s.add_development_dependency(%q<yard>)
33
+ s.add_runtime_dependency('ruby_parser', ['>= 3.5.0', '< 4.0'])
34
+ s.add_runtime_dependency('sexp_processor', ['~> 4.4'])
35
+ s.add_runtime_dependency('ruby2ruby', ['>= 2.0.8', '< 3.0'])
36
+ s.add_runtime_dependency('rainbow', ['>= 1.99', '< 3.0'])
37
+
38
+ s.add_development_dependency('bundler', ['~> 1.1'])
39
+ s.add_development_dependency('rake', ['~> 10.0'])
40
+ s.add_development_dependency('cucumber', ['~> 1.3'])
41
+ s.add_development_dependency('rspec', ['~> 3.0'])
42
+ s.add_development_dependency('flay', ['~> 2.4'])
43
+ s.add_development_dependency('yard', ['>= 0.8.7', '< 0.9'])
40
44
  end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require 'find'
3
3
 
4
4
  release_timestamp_file = 'build/.last-release'
5
- if test(?f, release_timestamp_file)
5
+ if test('f', release_timestamp_file)
6
6
  describe 'updates' do
7
7
  before :each do
8
8
  @release_time = File.stat(release_timestamp_file).mtime
@@ -11,16 +11,15 @@ if test(?f, release_timestamp_file)
11
11
  context 'version file' do
12
12
  it 'has been updated since the last release' do
13
13
  version_time = File.stat('lib/reek.rb').mtime
14
- (version_time > @release_time).should be_true
14
+ expect(version_time).to be > @release_time
15
15
  end
16
16
  end
17
17
 
18
18
  context 'history file' do
19
19
  it 'has been updated since the last release' do
20
20
  history_time = File.stat('History.txt').mtime
21
- (history_time > @release_time).should be_true
21
+ expect(history_time).to be > @release_time
22
22
  end
23
23
  end
24
24
  end
25
25
  end
26
-
@@ -9,7 +9,6 @@ describe 'yardoc' do
9
9
  @stderr = IO.read(stderr_file.path)
10
10
  end
11
11
  it 'raises no warnings' do
12
- @stderr.should == ''
12
+ expect(@stderr).to eq('')
13
13
  end
14
14
  end
15
-
@@ -6,11 +6,11 @@ module SmellOfMatcher
6
6
  @config = {}
7
7
  end
8
8
 
9
- def failure_message_for_should
9
+ def failure_message
10
10
  "Expected #{@source.desc} to smell of #{@klass}, but it didn't: #{@reason}"
11
11
  end
12
12
 
13
- def failure_message_for_should_not
13
+ def failure_message_when_negated
14
14
  "Expected #{@source.desc} not to smell of #{@klass}, but it did"
15
15
  end
16
16
 
@@ -41,19 +41,17 @@ module SmellOfMatcher
41
41
  end
42
42
 
43
43
  def no_smells_found?
44
- if @actual_smells.empty?
45
- @reason = 'no smells found by detector'
46
- return true
47
- end
44
+ return false if @actual_smells.any?
45
+ @reason = 'no smells found by detector'
46
+ true
48
47
  end
49
48
 
50
49
  def wrong_number_of_smells_found?
51
50
  return false if @expected_smells.empty?
51
+ return false if expected_number_of_smells == actual_number_of_smells
52
52
 
53
- if expected_number_of_smells != actual_number_of_smells
54
- @reason = "expected #{expected_number_of_smells} smell(s), found #{actual_number_of_smells}"
55
- true
56
- end
53
+ @reason = "expected #{expected_number_of_smells} smell(s), found #{actual_number_of_smells}"
54
+ true
57
55
  end
58
56
 
59
57
  def expected_number_of_smells
@@ -68,10 +66,10 @@ module SmellOfMatcher
68
66
  @expected_smells.zip(@actual_smells).each do |expected_smell, actual_smell|
69
67
  expected_smell.each do |key, value|
70
68
  actual_value = actual_smell.smell[key]
71
- if actual_value != value
72
- @reason = "expected #{key} to be #{value}, was #{actual_value}"
73
- return true
74
- end
69
+ next if actual_value == value
70
+
71
+ @reason = "expected #{key} to be #{value}, was #{actual_value}"
72
+ return true
75
73
  end
76
74
  end
77
75
  false
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'flay'
3
+
4
+ RSpec::Matchers.define :flay do |threshold|
5
+ match do |dirs_and_files|
6
+ @threshold = threshold
7
+ @flay = Flay.new(fuzzy: false, verbose: false, mass: @threshold)
8
+ @flay.process(*Flay.expand_dirs_to_files(dirs_and_files))
9
+ @flay.total > 0
10
+ end
11
+
12
+ failure_message_for_should do
13
+ "Expected source to contain duplication, but it didn't"
14
+ end
15
+
16
+ failure_message_for_should_not do
17
+ "Expected source not to contain duplication, but got:\n#{report}"
18
+ end
19
+
20
+ def report
21
+ lines = ["Total mass = #{@flay.total} (threshold = #{@threshold})"]
22
+ @flay.masses.each do |hash, mass|
23
+ nodes = @flay.hashes[hash]
24
+ match = @flay.identical[hash] ? 'IDENTICAL' : 'Similar'
25
+ lines << format('%s code found in %p (%d)', match, nodes.first.first, mass)
26
+ nodes.each { |x| lines << " #{x.file}:#{x.line}" }
27
+ end
28
+ lines.join("\n")
29
+ end
30
+ end
31
+
32
+ describe 'Reek source code' do
33
+ it 'has no smells' do
34
+ Dir['lib/**/*.rb'].should_not reek
35
+ end
36
+ it 'has no structural duplication' do
37
+ ['lib'].should_not flay(16)
38
+ end
39
+ it 'has no structural duplication in the tests' do
40
+ ['spec/reek'].should_not flay(25)
41
+ end
42
+ end
@@ -5,19 +5,21 @@ include Reek::Cli
5
5
 
6
6
  describe HelpCommand do
7
7
  before :each do
8
- @text = 'Piece of interesting text'
9
- @cmd = HelpCommand.new(@text)
8
+ @help_text = 'Piece of interesting text'
9
+ @parser = double('parser')
10
+ allow(@parser).to receive(:help_text).and_return @help_text
11
+ @cmd = HelpCommand.new(@parser)
10
12
  @view = double('view').as_null_object
11
- @view.should_not_receive(:report_smells)
12
13
  end
13
14
 
14
15
  it 'displays the correct text on the view' do
15
- @view.should_receive(:output).with(@text)
16
+ expect(@view).to receive(:output).with(@help_text)
16
17
  @cmd.execute(@view)
17
18
  end
18
19
 
19
20
  it 'tells the view it succeeded' do
20
- @view.should_receive(:report_success)
21
+ expect(@view).not_to receive(:report_smells)
22
+ expect(@view).to receive(:report_success)
21
23
  @cmd.execute(@view)
22
24
  end
23
25
  end