reek 4.4.2 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -1
  3. data/CHANGELOG.md +16 -0
  4. data/CONTRIBUTING.md +52 -23
  5. data/README.md +16 -3
  6. data/ataru_setup.rb +1 -1
  7. data/docs/API.md +1 -4
  8. data/docs/How-reek-works-internally.md +5 -5
  9. data/docs/Style-Guide.md +7 -0
  10. data/features/command_line_interface/options.feature +1 -0
  11. data/features/command_line_interface/show_progress.feature +33 -0
  12. data/features/configuration_files/masking_smells.feature +0 -1
  13. data/features/configuration_via_source_comments/erroneous_source_comments.feature +18 -4
  14. data/features/configuration_via_source_comments/well_formed_source_comments.feature +116 -0
  15. data/features/step_definitions/sample_file_steps.rb +5 -0
  16. data/features/todo_list.feature +42 -14
  17. data/lib/reek.rb +1 -1
  18. data/lib/reek/cli/application.rb +5 -0
  19. data/lib/reek/cli/command/report_command.rb +6 -1
  20. data/lib/reek/cli/command/todo_list_command.rb +1 -2
  21. data/lib/reek/cli/options.rb +19 -3
  22. data/lib/reek/code_comment.rb +83 -11
  23. data/lib/reek/configuration/configuration_validator.rb +2 -2
  24. data/lib/reek/errors/bad_detector_in_comment_error.rb +35 -0
  25. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +34 -0
  26. data/lib/reek/examiner.rb +36 -14
  27. data/lib/reek/report.rb +28 -9
  28. data/lib/reek/report/base_report.rb +77 -0
  29. data/lib/reek/report/code_climate.rb +4 -0
  30. data/lib/reek/report/code_climate/code_climate_fingerprint.rb +48 -0
  31. data/lib/reek/report/code_climate/code_climate_formatter.rb +5 -0
  32. data/lib/reek/report/code_climate/code_climate_report.rb +19 -0
  33. data/lib/reek/report/formatter.rb +5 -56
  34. data/lib/reek/report/{heading_formatter.rb → formatter/heading_formatter.rb} +4 -4
  35. data/lib/reek/report/formatter/location_formatter.rb +41 -0
  36. data/lib/reek/report/formatter/progress_formatter.rb +80 -0
  37. data/lib/reek/report/formatter/simple_warning_formatter.rb +35 -0
  38. data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +35 -0
  39. data/lib/reek/report/html_report.rb +21 -0
  40. data/lib/reek/report/{html_report.html.erb → html_report/html_report.html.erb} +0 -0
  41. data/lib/reek/report/json_report.rb +18 -0
  42. data/lib/reek/report/text_report.rb +68 -0
  43. data/lib/reek/report/xml_report.rb +61 -0
  44. data/lib/reek/report/yaml_report.rb +18 -0
  45. data/lib/reek/smell_detectors.rb +30 -0
  46. data/lib/reek/{smells → smell_detectors}/attribute.rb +3 -3
  47. data/lib/reek/{smells/smell_detector.rb → smell_detectors/base_detector.rb} +3 -3
  48. data/lib/reek/{smells → smell_detectors}/boolean_parameter.rb +3 -3
  49. data/lib/reek/{smells → smell_detectors}/class_variable.rb +3 -3
  50. data/lib/reek/{smells → smell_detectors}/control_parameter.rb +3 -3
  51. data/lib/reek/{smells → smell_detectors}/data_clump.rb +3 -3
  52. data/lib/reek/{smells/smell_repository.rb → smell_detectors/detector_repository.rb} +9 -9
  53. data/lib/reek/{smells → smell_detectors}/duplicate_method_call.rb +3 -3
  54. data/lib/reek/{smells → smell_detectors}/feature_envy.rb +3 -3
  55. data/lib/reek/{smells → smell_detectors}/instance_variable_assumption.rb +3 -3
  56. data/lib/reek/{smells → smell_detectors}/irresponsible_module.rb +3 -3
  57. data/lib/reek/{smells → smell_detectors}/long_parameter_list.rb +3 -3
  58. data/lib/reek/{smells → smell_detectors}/long_yield_list.rb +3 -3
  59. data/lib/reek/{smells → smell_detectors}/manual_dispatch.rb +3 -3
  60. data/lib/reek/{smells → smell_detectors}/module_initialize.rb +3 -3
  61. data/lib/reek/{smells → smell_detectors}/nested_iterators.rb +3 -3
  62. data/lib/reek/{smells → smell_detectors}/nil_check.rb +3 -3
  63. data/lib/reek/{smells → smell_detectors}/prima_donna_method.rb +3 -3
  64. data/lib/reek/{smells → smell_detectors}/repeated_conditional.rb +3 -3
  65. data/lib/reek/{smells → smell_detectors}/smell_configuration.rb +1 -1
  66. data/lib/reek/{smells → smell_detectors}/smell_warning.rb +1 -1
  67. data/lib/reek/{smells → smell_detectors}/subclassed_from_core_class.rb +3 -3
  68. data/lib/reek/{smells → smell_detectors}/too_many_constants.rb +3 -3
  69. data/lib/reek/{smells → smell_detectors}/too_many_instance_variables.rb +3 -3
  70. data/lib/reek/{smells → smell_detectors}/too_many_methods.rb +3 -3
  71. data/lib/reek/{smells → smell_detectors}/too_many_statements.rb +3 -3
  72. data/lib/reek/{smells → smell_detectors}/uncommunicative_method_name.rb +3 -3
  73. data/lib/reek/{smells → smell_detectors}/uncommunicative_module_name.rb +3 -3
  74. data/lib/reek/{smells → smell_detectors}/uncommunicative_parameter_name.rb +3 -3
  75. data/lib/reek/{smells → smell_detectors}/uncommunicative_variable_name.rb +3 -3
  76. data/lib/reek/{smells → smell_detectors}/unused_parameters.rb +3 -3
  77. data/lib/reek/{smells → smell_detectors}/unused_private_method.rb +3 -3
  78. data/lib/reek/{smells → smell_detectors}/utility_function.rb +3 -3
  79. data/lib/reek/spec/should_reek_of.rb +1 -1
  80. data/lib/reek/version.rb +1 -1
  81. data/reek.gemspec +1 -1
  82. data/spec/factories/factories.rb +6 -6
  83. data/spec/reek/cli/command/report_command_spec.rb +3 -1
  84. data/spec/reek/cli/options_spec.rb +12 -2
  85. data/spec/reek/code_comment_spec.rb +18 -6
  86. data/spec/reek/configuration/app_configuration_spec.rb +12 -12
  87. data/spec/reek/configuration/default_directive_spec.rb +1 -1
  88. data/spec/reek/configuration/directory_directives_spec.rb +2 -2
  89. data/spec/reek/examiner_spec.rb +56 -28
  90. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +122 -0
  91. data/spec/reek/report/{code_climate_formatter_spec.rb → code_climate/code_climate_formatter_spec.rb} +6 -2
  92. data/spec/reek/report/{code_climate_report_spec.rb → code_climate/code_climate_report_spec.rb} +7 -5
  93. data/spec/reek/report/{location_formatter_spec.rb → formatter/location_formatter_spec.rb} +4 -4
  94. data/spec/reek/report/formatter/progress_formatter_spec.rb +68 -0
  95. data/spec/reek/report/html_report_spec.rb +1 -1
  96. data/spec/reek/report/json_report_spec.rb +2 -2
  97. data/spec/reek/report/text_report_spec.rb +3 -4
  98. data/spec/reek/report/xml_report_spec.rb +1 -1
  99. data/spec/reek/report/yaml_report_spec.rb +2 -2
  100. data/spec/reek/report_spec.rb +3 -3
  101. data/spec/reek/{smells → smell_detectors}/attribute_spec.rb +2 -2
  102. data/spec/reek/{smells/smell_detector_spec.rb → smell_detectors/base_detector_spec.rb} +5 -5
  103. data/spec/reek/{smells → smell_detectors}/boolean_parameter_spec.rb +2 -2
  104. data/spec/reek/{smells → smell_detectors}/class_variable_spec.rb +2 -2
  105. data/spec/reek/{smells → smell_detectors}/control_parameter_spec.rb +2 -2
  106. data/spec/reek/{smells → smell_detectors}/data_clump_spec.rb +2 -2
  107. data/spec/reek/smell_detectors/detector_repository_spec.rb +22 -0
  108. data/spec/reek/{smells → smell_detectors}/duplicate_method_call_spec.rb +6 -6
  109. data/spec/reek/{smells → smell_detectors}/feature_envy_spec.rb +2 -2
  110. data/spec/reek/{smells → smell_detectors}/instance_variable_assumption_spec.rb +2 -2
  111. data/spec/reek/{smells → smell_detectors}/irresponsible_module_spec.rb +2 -2
  112. data/spec/reek/{smells → smell_detectors}/long_parameter_list_spec.rb +2 -2
  113. data/spec/reek/{smells → smell_detectors}/long_yield_list_spec.rb +2 -2
  114. data/spec/reek/{smells → smell_detectors}/manual_dispatch_spec.rb +2 -2
  115. data/spec/reek/{smells → smell_detectors}/module_initialize_spec.rb +2 -2
  116. data/spec/reek/{smells → smell_detectors}/nested_iterators_spec.rb +4 -4
  117. data/spec/reek/{smells → smell_detectors}/nil_check_spec.rb +2 -2
  118. data/spec/reek/{smells → smell_detectors}/prima_donna_method_spec.rb +2 -2
  119. data/spec/reek/{smells → smell_detectors}/repeated_conditional_spec.rb +2 -2
  120. data/spec/reek/{smells → smell_detectors}/smell_configuration_spec.rb +2 -2
  121. data/spec/reek/{smells → smell_detectors}/smell_warning_spec.rb +3 -3
  122. data/spec/reek/{smells → smell_detectors}/subclassed_from_core_class_spec.rb +2 -2
  123. data/spec/reek/{smells → smell_detectors}/too_many_constants_spec.rb +3 -3
  124. data/spec/reek/{smells → smell_detectors}/too_many_instance_variables_spec.rb +3 -3
  125. data/spec/reek/{smells → smell_detectors}/too_many_methods_spec.rb +3 -3
  126. data/spec/reek/{smells → smell_detectors}/too_many_statements_spec.rb +3 -3
  127. data/spec/reek/{smells → smell_detectors}/uncommunicative_method_name_spec.rb +2 -2
  128. data/spec/reek/{smells → smell_detectors}/uncommunicative_module_name_spec.rb +2 -2
  129. data/spec/reek/{smells → smell_detectors}/uncommunicative_parameter_name_spec.rb +2 -2
  130. data/spec/reek/{smells → smell_detectors}/uncommunicative_variable_name_spec.rb +2 -2
  131. data/spec/reek/{smells → smell_detectors}/unused_parameters_spec.rb +2 -2
  132. data/spec/reek/{smells → smell_detectors}/unused_private_method_spec.rb +4 -4
  133. data/spec/reek/{smells → smell_detectors}/utility_function_spec.rb +3 -3
  134. data/spec/reek/spec/should_reek_of_spec.rb +3 -3
  135. data/tasks/configuration.rake +2 -2
  136. metadata +95 -81
  137. data/features/smells/subclassed_from_core_class.feature +0 -14
  138. data/features/smells/too_many_constants.feature +0 -19
  139. data/lib/reek/errors.rb +0 -32
  140. data/lib/reek/report/location_formatter.rb +0 -39
  141. data/lib/reek/report/report.rb +0 -229
  142. data/lib/reek/smells.rb +0 -30
  143. data/spec/reek/smells/smell_repository_spec.rb +0 -22
@@ -1,7 +1,11 @@
1
1
  # frozen_string_literal: true
2
- require_relative 'report/report'
2
+ require_relative 'report/code_climate'
3
+ require_relative 'report/html_report'
4
+ require_relative 'report/json_report'
5
+ require_relative 'report/text_report'
6
+ require_relative 'report/xml_report'
7
+ require_relative 'report/yaml_report'
3
8
  require_relative 'report/formatter'
4
- require_relative 'report/heading_formatter'
5
9
 
6
10
  module Reek
7
11
  # Reek reporting functionality.
@@ -16,19 +20,24 @@ module Reek
16
20
  }.freeze
17
21
 
18
22
  LOCATION_FORMATTERS = {
19
- single_line: SingleLineLocationFormatter,
20
- plain: BlankLocationFormatter,
21
- numbers: DefaultLocationFormatter
23
+ single_line: Formatter::SingleLineLocationFormatter,
24
+ plain: Formatter::BlankLocationFormatter,
25
+ numbers: Formatter::DefaultLocationFormatter
22
26
  }.freeze
23
27
 
24
28
  HEADING_FORMATTERS = {
25
- verbose: HeadingFormatter::Verbose,
26
- quiet: HeadingFormatter::Quiet
29
+ verbose: Formatter::VerboseHeadingFormatter,
30
+ quiet: Formatter::QuietHeadingFormatter
31
+ }.freeze
32
+
33
+ PROGRESS_FORMATTERS = {
34
+ dots: Formatter::ProgressFormatter::Dots,
35
+ quiet: Formatter::ProgressFormatter::Quiet
27
36
  }.freeze
28
37
 
29
38
  WARNING_FORMATTER_CLASSES = {
30
- wiki_links: WikiLinkWarningFormatter,
31
- simple: SimpleWarningFormatter
39
+ wiki_links: Formatter::WikiLinkWarningFormatter,
40
+ simple: Formatter::SimpleWarningFormatter
32
41
  }.freeze
33
42
 
34
43
  # Map report format symbol to a report class.
@@ -61,6 +70,16 @@ module Reek
61
70
  HEADING_FORMATTERS.fetch(heading_format)
62
71
  end
63
72
 
73
+ # Map progress format symbol to a report class.
74
+ #
75
+ # @param [Symbol] progress_format The format to map
76
+ #
77
+ # @return The mapped progress class
78
+ #
79
+ def self.progress_formatter(progress_format)
80
+ PROGRESS_FORMATTERS.fetch(progress_format)
81
+ end
82
+
64
83
  # Map warning format symbol to a report class.
65
84
  #
66
85
  # @param [Symbol] warning_format The format to map
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+ require 'json'
3
+ require 'pathname'
4
+ require 'rainbow'
5
+
6
+ require_relative 'formatter'
7
+
8
+ module Reek
9
+ # @public
10
+ module Report
11
+ #
12
+ # A report that contains the smells and smell counts following source code analysis.
13
+ #
14
+ # @abstract Subclass and override {#show} to create a concrete report class.
15
+ #
16
+ # @public
17
+ #
18
+ # :reek:TooManyInstanceVariables: { max_instance_variables: 7 }
19
+ class BaseReport
20
+ NO_WARNINGS_COLOR = :green
21
+ WARNINGS_COLOR = :red
22
+
23
+ # @public
24
+ #
25
+ # :reek:BooleanParameter
26
+ def initialize(heading_formatter: Formatter::QuietHeadingFormatter,
27
+ report_formatter: Formatter,
28
+ sort_by_issue_count: false,
29
+ warning_formatter: Formatter::SimpleWarningFormatter.new,
30
+ progress_formatter: Formatter::ProgressFormatter::Quiet.new(0))
31
+ @examiners = []
32
+ @heading_formatter = heading_formatter.new(report_formatter)
33
+ @report_formatter = report_formatter
34
+ @progress_formatter = progress_formatter
35
+ @sort_by_issue_count = sort_by_issue_count
36
+ @total_smell_count = 0
37
+ @warning_formatter = warning_formatter
38
+ end
39
+
40
+ # Add Examiner to report on. The report will output results for all
41
+ # added examiners.
42
+ #
43
+ # @param [Reek::Examiner] examiner object to report on
44
+ #
45
+ # @public
46
+ def add_examiner(examiner)
47
+ self.total_smell_count += examiner.smells_count
48
+ examiners << examiner
49
+ self
50
+ end
51
+
52
+ # Render the report results on STDOUT
53
+ #
54
+ # @public
55
+ def show
56
+ raise NotImplementedError
57
+ end
58
+
59
+ def smells?
60
+ total_smell_count > 0
61
+ end
62
+
63
+ def smells
64
+ examiners.map(&:smells).flatten
65
+ end
66
+
67
+ protected
68
+
69
+ attr_accessor :total_smell_count
70
+
71
+ private
72
+
73
+ attr_reader :examiners, :heading_formatter, :report_formatter,
74
+ :sort_by_issue_count, :warning_formatter, :progress_formatter
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'code_climate/code_climate_fingerprint'
3
+ require_relative 'code_climate/code_climate_formatter'
4
+ require_relative 'code_climate/code_climate_report'
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ module Reek
3
+ module Report
4
+ # Generates a string to uniquely identify a smell
5
+ class CodeClimateFingerprint
6
+ NON_IDENTIFYING_PARAMETERS = [:count, :depth].freeze
7
+
8
+ def initialize(warning)
9
+ @warning = warning
10
+ end
11
+
12
+ def compute
13
+ return unless warning_uniquely_identifiable?
14
+
15
+ identify_warning
16
+
17
+ identifying_aspects.hexdigest
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :warning
23
+
24
+ def identify_warning
25
+ identifying_aspects << warning.source
26
+ identifying_aspects << warning.smell_type
27
+ identifying_aspects << warning.context
28
+ identifying_aspects << parameters
29
+ end
30
+
31
+ def identifying_aspects
32
+ @identifying_aspects ||= Digest::MD5.new
33
+ end
34
+
35
+ def parameters
36
+ warning.parameters.except(*NON_IDENTIFYING_PARAMETERS).sort.to_s
37
+ end
38
+
39
+ def warning_uniquely_identifiable?
40
+ # These could be identifiable if they had parameters
41
+ ![
42
+ 'ManualDispatch',
43
+ 'NilCheck'
44
+ ].include?(warning.smell_type)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -15,6 +15,7 @@ module Reek
15
15
  categories: categories,
16
16
  location: location,
17
17
  remediation_points: remediation_points,
18
+ fingerprint: fingerprint,
18
19
  content: content).render
19
20
  end
20
21
 
@@ -45,6 +46,10 @@ module Reek
45
46
  configuration[warning.smell_type].fetch('remediation_points')
46
47
  end
47
48
 
49
+ def fingerprint
50
+ CodeClimateFingerprint.new(warning).compute
51
+ end
52
+
48
53
  def content
49
54
  configuration[warning.smell_type].fetch('content')
50
55
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ require_relative '../base_report'
3
+
4
+ module Reek
5
+ module Report
6
+ #
7
+ # Displays a list of smells in Code Climate engine format
8
+ # (https://github.com/codeclimate/spec/blob/master/SPEC.md)
9
+ # JSON with empty array for 0 smells
10
+ #
11
+ class CodeClimateReport < BaseReport
12
+ def show(out = $stdout)
13
+ smells.map do |smell|
14
+ out.print warning_formatter.format_code_climate_hash(smell)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
- require_relative 'location_formatter'
3
2
  require_relative 'code_climate/code_climate_formatter'
3
+ require_relative 'formatter/heading_formatter'
4
+ require_relative 'formatter/location_formatter'
5
+ require_relative 'formatter/progress_formatter'
6
+ require_relative 'formatter/simple_warning_formatter'
7
+ require_relative 'formatter/wiki_link_warning_formatter'
4
8
 
5
9
  module Reek
6
10
  module Report
@@ -24,60 +28,5 @@ module Reek
24
28
  result
25
29
  end
26
30
  end
27
-
28
- #
29
- # Basic formatter that just shows a simple message for each warning,
30
- # prepended with the result of the passed-in location formatter.
31
- #
32
- class SimpleWarningFormatter
33
- def initialize(location_formatter: BlankLocationFormatter)
34
- @location_formatter = location_formatter
35
- end
36
-
37
- def format(warning)
38
- "#{location_formatter.format(warning)}#{warning.base_message}"
39
- end
40
-
41
- # :reek:UtilityFunction
42
- def format_hash(warning)
43
- warning.yaml_hash
44
- end
45
-
46
- # :reek:UtilityFunction
47
- def format_code_climate_hash(warning)
48
- CodeClimateFormatter.new(warning).render
49
- end
50
-
51
- private
52
-
53
- attr_reader :location_formatter
54
- end
55
-
56
- #
57
- # Formatter that adds a link to the wiki to the basic message from
58
- # SimpleWarningFormatter.
59
- #
60
- class WikiLinkWarningFormatter < SimpleWarningFormatter
61
- BASE_URL_FOR_HELP_LINK = 'https://github.com/troessner/reek/blob/master/docs/'.freeze
62
-
63
- def format(warning)
64
- "#{super} [#{explanatory_link(warning)}]"
65
- end
66
-
67
- def format_hash(warning)
68
- super.merge('wiki_link' => explanatory_link(warning))
69
- end
70
-
71
- private
72
-
73
- def explanatory_link(warning)
74
- "#{BASE_URL_FOR_HELP_LINK}#{class_name_to_param(warning.smell_type)}.md"
75
- end
76
-
77
- # :reek:UtilityFunction
78
- def class_name_to_param(name)
79
- name.split(/(?=[A-Z])/).join('-')
80
- end
81
- end
82
31
  end
83
32
  end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
  module Reek
3
3
  module Report
4
- module HeadingFormatter
4
+ module Formatter
5
5
  #
6
6
  # Base class for heading formatters.
7
7
  # Is responsible for formatting the heading emitted for each examiner
8
8
  #
9
9
  # @abstract Override {#show_header?} to implement a heading formatter.
10
- class Base
10
+ class HeadingFormatterBase
11
11
  attr_reader :report_formatter
12
12
 
13
13
  def initialize(report_formatter)
@@ -31,7 +31,7 @@ module Reek
31
31
  #
32
32
  # Lists out each examiner, even if it has no smell
33
33
  #
34
- class Verbose < Base
34
+ class VerboseHeadingFormatter < HeadingFormatterBase
35
35
  def show_header?(_examiner)
36
36
  true
37
37
  end
@@ -40,7 +40,7 @@ module Reek
40
40
  #
41
41
  # Lists only smelly examiners
42
42
  #
43
- class Quiet < Base
43
+ class QuietHeadingFormatter < HeadingFormatterBase
44
44
  # :reek:UtilityFunction
45
45
  def show_header?(examiner)
46
46
  examiner.smelly?
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+ module Reek
3
+ module Report
4
+ module Formatter
5
+ #
6
+ # Formats the location of a warning as an empty string.
7
+ #
8
+ module BlankLocationFormatter
9
+ module_function
10
+
11
+ def format(_warning)
12
+ ''
13
+ end
14
+ end
15
+
16
+ #
17
+ # Formats the location of a warning as an array of line numbers.
18
+ #
19
+ module DefaultLocationFormatter
20
+ module_function
21
+
22
+ def format(warning)
23
+ "#{warning.lines.sort.inspect}:"
24
+ end
25
+ end
26
+
27
+ #
28
+ # Formats the location of a warning as a combination of source file name
29
+ # and line number. In this format, it is not possible to show more than
30
+ # one line number, so the first number is displayed.
31
+ #
32
+ module SingleLineLocationFormatter
33
+ module_function
34
+
35
+ def format(warning)
36
+ "#{warning.source}:#{warning.lines.sort.first}: "
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+ module Reek
3
+ module Report
4
+ module Formatter
5
+ module ProgressFormatter
6
+ #
7
+ # Base class for progress formatters.
8
+ # Is responsible for formatting the progress emitted for each examiner
9
+ #
10
+ # @abstract Override {#header, #progress, #footer} to implement a progress formatter.
11
+ class Base
12
+ attr_reader :sources_count
13
+
14
+ def initialize(sources_count)
15
+ @sources_count = sources_count
16
+ end
17
+
18
+ def header
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def progress(_examiner)
23
+ raise NotImplementedError
24
+ end
25
+
26
+ def footer
27
+ raise NotImplementedError
28
+ end
29
+ end
30
+
31
+ #
32
+ # Shows the status of each source as either a dot (.) or an S
33
+ #
34
+ class Dots < Base
35
+ NO_WARNINGS_COLOR = :green
36
+ WARNINGS_COLOR = :red
37
+
38
+ def header
39
+ "Inspecting #{sources_count} file(s):\n"
40
+ end
41
+
42
+ def progress(examiner)
43
+ examiner.smelly? ? display_smelly : display_clean
44
+ end
45
+
46
+ def footer
47
+ "\n\n"
48
+ end
49
+
50
+ private
51
+
52
+ def display_clean
53
+ Rainbow('.').color(NO_WARNINGS_COLOR)
54
+ end
55
+
56
+ def display_smelly
57
+ Rainbow('S').color(WARNINGS_COLOR)
58
+ end
59
+ end
60
+
61
+ #
62
+ # Does not show progress
63
+ #
64
+ class Quiet < Base
65
+ def header
66
+ ''
67
+ end
68
+
69
+ def progress(_examiner)
70
+ ''
71
+ end
72
+
73
+ def footer
74
+ ''
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end