rubycritic 0.0.5 → 1.4.0

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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +593 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGELOG.md +45 -0
  5. data/CONTRIBUTING.md +67 -15
  6. data/README.md +105 -14
  7. data/Rakefile +9 -6
  8. data/bin/rubycritic +3 -1
  9. data/lib/rubycritic/analysers/attributes.rb +21 -0
  10. data/lib/rubycritic/analysers/churn.rb +21 -0
  11. data/lib/rubycritic/analysers/complexity.rb +22 -0
  12. data/lib/rubycritic/analysers/helpers/ast_node.rb +69 -0
  13. data/lib/rubycritic/analysers/{config.reek → helpers/config.reek} +8 -0
  14. data/lib/rubycritic/analysers/helpers/flay.rb +13 -0
  15. data/lib/rubycritic/analysers/helpers/flog.rb +17 -0
  16. data/lib/rubycritic/analysers/helpers/methods_counter.rb +25 -0
  17. data/lib/rubycritic/analysers/helpers/modules_locator.rb +43 -0
  18. data/lib/rubycritic/analysers/helpers/parser.rb +12 -0
  19. data/lib/rubycritic/analysers/helpers/reek.rb +17 -0
  20. data/lib/rubycritic/analysers/smells/flay.rb +68 -0
  21. data/lib/rubycritic/analysers/smells/flog.rb +62 -0
  22. data/lib/rubycritic/analysers/smells/reek.rb +44 -0
  23. data/lib/rubycritic/analysers_runner.rb +21 -10
  24. data/lib/rubycritic/cli/application.rb +24 -0
  25. data/lib/rubycritic/cli/options.rb +79 -0
  26. data/lib/rubycritic/commands/ci.rb +26 -0
  27. data/lib/rubycritic/commands/default.rb +28 -0
  28. data/lib/rubycritic/commands/help.rb +13 -0
  29. data/lib/rubycritic/commands/version.rb +11 -0
  30. data/lib/rubycritic/configuration.rb +33 -0
  31. data/lib/rubycritic/core/analysed_module.rb +66 -0
  32. data/lib/rubycritic/{location.rb → core/location.rb} +17 -2
  33. data/lib/rubycritic/core/rating.rb +30 -0
  34. data/lib/rubycritic/{smell.rb → core/smell.rb} +22 -13
  35. data/lib/rubycritic/generators/html/assets/javascripts/application.js +104 -0
  36. data/lib/rubycritic/generators/html/assets/javascripts/highcharts.src-4.0.1.js +17672 -0
  37. data/lib/rubycritic/generators/html/assets/javascripts/jquery.floatThead-v1.2.7.js +754 -0
  38. data/lib/rubycritic/generators/html/assets/javascripts/jquery.scrollTo-1.4.11.js +186 -0
  39. data/lib/rubycritic/generators/html/assets/javascripts/jquery.tablesorter.js +2089 -0
  40. data/lib/rubycritic/generators/html/assets/javascripts/jquery.timeago-v1.4.1.js +214 -0
  41. data/lib/rubycritic/generators/html/assets/stylesheets/application.css +303 -0
  42. data/lib/rubycritic/{report_generators → generators/html}/assets/stylesheets/prettify.custom_theme.css +1 -4
  43. data/lib/rubycritic/generators/html/base.rb +52 -0
  44. data/lib/rubycritic/generators/html/code_file.rb +40 -0
  45. data/lib/rubycritic/generators/html/code_index.rb +26 -0
  46. data/lib/rubycritic/generators/html/line.rb +37 -0
  47. data/lib/rubycritic/generators/html/overview.rb +27 -0
  48. data/lib/rubycritic/generators/html/smells_index.rb +38 -0
  49. data/lib/rubycritic/generators/html/templates/code_file.html.erb +38 -0
  50. data/lib/rubycritic/generators/html/templates/code_index.html.erb +30 -0
  51. data/lib/rubycritic/generators/html/templates/layouts/application.html.erb +34 -0
  52. data/lib/rubycritic/generators/html/templates/overview.html.erb +5 -0
  53. data/lib/rubycritic/generators/html/templates/smells_index.html.erb +26 -0
  54. data/lib/rubycritic/{report_generators → generators/html}/templates/smelly_line.html.erb +1 -1
  55. data/lib/rubycritic/generators/html/turbulence.rb +17 -0
  56. data/lib/rubycritic/generators/html/view_helpers.rb +43 -0
  57. data/lib/rubycritic/generators/html_report.rb +66 -0
  58. data/lib/rubycritic/generators/json/simple.rb +30 -0
  59. data/lib/rubycritic/generators/json_report.rb +23 -0
  60. data/lib/rubycritic/reporter.rb +20 -0
  61. data/lib/rubycritic/revision_comparator.rb +27 -29
  62. data/lib/rubycritic/serializer.rb +32 -0
  63. data/lib/rubycritic/smells_status_setter.rb +7 -16
  64. data/lib/rubycritic/source_control_systems/base.rb +37 -0
  65. data/lib/rubycritic/source_control_systems/double.rb +18 -0
  66. data/lib/rubycritic/source_control_systems/git.rb +41 -37
  67. data/lib/rubycritic/source_control_systems/mercurial.rb +29 -0
  68. data/lib/rubycritic/source_locator.rb +25 -13
  69. data/lib/rubycritic/version.rb +1 -1
  70. data/lib/rubycritic.rb +17 -22
  71. data/rubycritic.gemspec +10 -7
  72. data/test/analysers_test_helper.rb +3 -0
  73. data/test/lib/rubycritic/analysers/churn_test.rb +33 -0
  74. data/test/lib/rubycritic/analysers/complexity_test.rb +16 -0
  75. data/test/lib/rubycritic/analysers/helpers/methods_counter_test.rb +29 -0
  76. data/test/lib/rubycritic/analysers/helpers/modules_locator_test.rb +53 -0
  77. data/test/lib/rubycritic/analysers/smells/flay_test.rb +39 -0
  78. data/test/lib/rubycritic/analysers/smells/flog_test.rb +26 -0
  79. data/test/lib/rubycritic/analysers/smells/reek_test.rb +33 -0
  80. data/test/lib/rubycritic/configuration_test.rb +29 -0
  81. data/test/lib/rubycritic/core/analysed_module_test.rb +88 -0
  82. data/test/lib/rubycritic/{location_test.rb → core/location_test.rb} +8 -4
  83. data/test/lib/rubycritic/core/smell_test.rb +72 -0
  84. data/test/lib/rubycritic/{smells_array_test.rb → core/smells_array_test.rb} +1 -1
  85. data/test/lib/rubycritic/report_generators/turbulence_test.rb +17 -0
  86. data/test/lib/rubycritic/report_generators/view_helpers_test.rb +83 -0
  87. data/test/lib/rubycritic/smells_status_setter_test.rb +5 -5
  88. data/test/lib/rubycritic/source_control_systems/base_test.rb +29 -0
  89. data/test/lib/rubycritic/source_control_systems/double_test.rb +11 -0
  90. data/test/lib/rubycritic/source_control_systems/git_test.rb +13 -0
  91. data/test/lib/rubycritic/source_control_systems/interfaces/basic.rb +7 -0
  92. data/test/lib/rubycritic/source_control_systems/interfaces/time_travel.rb +7 -0
  93. data/test/lib/rubycritic/source_control_systems/mercurial_test.rb +11 -0
  94. data/test/lib/rubycritic/source_locator_test.rb +42 -18
  95. data/test/lib/rubycritic/version_test.rb +1 -0
  96. data/test/samples/empty.rb +0 -0
  97. data/test/samples/flay/smelly.rb +8 -0
  98. data/test/samples/flay/smelly2.rb +8 -0
  99. data/test/samples/flog/complex.rb +11 -0
  100. data/test/samples/flog/smelly.rb +7 -2
  101. data/test/samples/location/file0_symlink.rb +0 -0
  102. data/test/samples/methods_count.rb +7 -0
  103. data/test/samples/module_names.rb +18 -0
  104. data/test/samples/reek/not_smelly.rb +31 -3
  105. data/test/samples/unparsable.rb +1 -0
  106. data/test/test_helper.rb +39 -0
  107. metadata +178 -53
  108. data/SPEC.md +0 -58
  109. data/lib/rubycritic/analysers/flog.rb +0 -20
  110. data/lib/rubycritic/analysers/reek.rb +0 -15
  111. data/lib/rubycritic/cli.rb +0 -25
  112. data/lib/rubycritic/report_generators/assets/javascripts/application.js +0 -25
  113. data/lib/rubycritic/report_generators/assets/stylesheets/application.css +0 -26
  114. data/lib/rubycritic/report_generators/base_generator.rb +0 -42
  115. data/lib/rubycritic/report_generators/file_generator.rb +0 -42
  116. data/lib/rubycritic/report_generators/index_generator.rb +0 -28
  117. data/lib/rubycritic/report_generators/line_generator.rb +0 -27
  118. data/lib/rubycritic/report_generators/reporter.rb +0 -45
  119. data/lib/rubycritic/report_generators/templates/file.html.erb +0 -3
  120. data/lib/rubycritic/report_generators/templates/index.html.erb +0 -14
  121. data/lib/rubycritic/report_generators/templates/layouts/application.html.erb +0 -19
  122. data/lib/rubycritic/report_generators/view_helpers.rb +0 -26
  123. data/lib/rubycritic/smell_adapters/flog.rb +0 -41
  124. data/lib/rubycritic/smell_adapters/reek.rb +0 -35
  125. data/lib/rubycritic/smells_aggregator.rb +0 -29
  126. data/lib/rubycritic/smelly_pathnames_serializer.rb +0 -34
  127. data/lib/rubycritic/source_control_systems/source_control_system.rb +0 -42
  128. data/test/lib/rubycritic/metric_adapters/flog_adapter_test.rb +0 -25
  129. data/test/lib/rubycritic/metric_adapters/reek_adapter_test.rb +0 -34
  130. data/test/lib/rubycritic/smell_test.rb +0 -71
  131. data/test/lib/rubycritic/smells_aggregator_test.rb +0 -47
  132. data/test/lib/rubycritic/source_control_systems/source_control_system_test.rb +0 -26
  133. /data/lib/rubycritic/{report_generators → generators/html}/assets/javascripts/jquery-2.1.0.js +0 -0
  134. /data/lib/rubycritic/{report_generators/assets/javascripts/prettify.js → generators/html/assets/javascripts/prettify-4-Mar-2013.js} +0 -0
  135. /data/lib/rubycritic/{report_generators → generators/html}/templates/line.html.erb +0 -0
@@ -0,0 +1,38 @@
1
+ require "rubycritic/generators/html/base"
2
+
3
+ module Rubycritic
4
+ module Generator
5
+ module Html
6
+
7
+ class SmellsIndex < Base
8
+ TEMPLATE = erb_template("smells_index.html.erb")
9
+
10
+ def initialize(analysed_modules)
11
+ @smells = analysed_modules.flat_map(&:smells).uniq
12
+ @analysed_module_names = analysed_module_names(analysed_modules)
13
+ @show_status = (Config.mode == :default)
14
+ end
15
+
16
+ def file_name
17
+ "smells_index.html"
18
+ end
19
+
20
+ def render
21
+ index_body = TEMPLATE.result(get_binding)
22
+ LAYOUT_TEMPLATE.result(get_binding { index_body })
23
+ end
24
+
25
+ private
26
+
27
+ def analysed_module_names(analysed_modules)
28
+ names = {}
29
+ analysed_modules.each do |analysed_module|
30
+ names[analysed_module.pathname] = analysed_module.name
31
+ end
32
+ names
33
+ end
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ <div class="file-header group <%= Config.suppress_ratings ? 'unrated' : 'rated' %>">
2
+ <span class="rating rating-<%= @analysed_module.rating.to_s.downcase %> circled-text circle">
3
+ <%= @analysed_module.rating %>
4
+ </span>
5
+ <h2 class="file-name"><%= @analysed_module.name %></h2>
6
+
7
+ <span class="file-committed-at">
8
+ <% if @analysed_module.committed_at %>
9
+ Updated <%= timeago_tag(@analysed_module.committed_at) %>
10
+ <% else %>
11
+ Never committed
12
+ <% end %>
13
+ </span>
14
+
15
+ <div class="file-stats group">
16
+ <div class="file-stat">
17
+ <%= @analysed_module.complexity %> complexity
18
+ </div>
19
+ <div class="file-stat">
20
+ <%= @analysed_module.complexity_per_method %> complexity per method
21
+ </div>
22
+ <div class="file-stat">
23
+ <%= @analysed_module.churn %> churn
24
+ </div>
25
+ <div class="file-stat">
26
+ <%= @analysed_module.methods_count %> methods
27
+ </div>
28
+ <div class="file-stat">
29
+ <%= @analysed_module.duplication %> duplication
30
+ </div>
31
+ </div>
32
+
33
+ <% if @analysed_module.smells? %>
34
+ <button id="js-toggle-smells" class="smells-toggle-button button">Toggle Smells</button>
35
+ <% end %>
36
+ </div>
37
+
38
+ <code class="prettyprint linenums lang-ruby file-code js-file-code"><%= yield %></code>
@@ -0,0 +1,30 @@
1
+ <table id="js-index-table" class="index-table sortable-table">
2
+ <thead>
3
+ <tr>
4
+ <th>Name</th>
5
+ <th class="numeric-cell" title="Number of times a file has changed">Churn</th>
6
+ <th class="numeric-cell" title="Overall amount of code in a file">Complexity</th>
7
+ <th class="numeric-cell" title="Amount of code that is similar to other code">Duplication</th>
8
+ <th class="numeric-cell">Smells</th>
9
+ <% unless Config.suppress_ratings %>
10
+ <th class="centered-cell">Rating</th>
11
+ <% end %>
12
+ </tr>
13
+ </thead>
14
+ <tbody>
15
+ <% @analysed_modules.each do |analysed_module| %>
16
+ <tr>
17
+ <td>
18
+ <a href="<%= file_path(analysed_module.pathname.sub_ext('.html')) %>"><%= analysed_module.name %></a>
19
+ </td>
20
+ <td class="numeric-cell"><%= analysed_module.churn %></td>
21
+ <td class="numeric-cell"><%= analysed_module.complexity %></td>
22
+ <td class="numeric-cell"><%= analysed_module.duplication %></td>
23
+ <td class="numeric-cell"><%= analysed_module.smells.length %></td>
24
+ <% unless Config.suppress_ratings %>
25
+ <td class="centered-cell"><span class="rating-<%= analysed_module.rating.to_s.downcase %> circled-text circle"><%= analysed_module.rating %></span></td>
26
+ <% end %>
27
+ </tr>
28
+ <% end %>
29
+ </tbody>
30
+ </table>
@@ -0,0 +1,34 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <title>RubyCritic</title>
7
+ <link href="<%= stylesheet_path(:application) %>" media="screen, projection, print" rel="stylesheet" type="text/css">
8
+ <link href="<%= stylesheet_path(:'prettify.custom_theme') %>" media="screen, projection, print" rel="stylesheet" type="text/css">
9
+ <meta name="viewport" content="width=device-width, initial-scale=1">
10
+ </head>
11
+ <body>
12
+ <header class="project-header group">
13
+ <div class="container">
14
+ <h1 class="logo"><a href="<%= file_path('overview.html') %>" class="logo-link">RubyCritic</a></h1>
15
+ <nav class="project-nav">
16
+ <a href="<%= file_path('overview.html') %>" class="project-nav-item">Overview</a>
17
+ <a href="<%= file_path('code_index.html') %>" class="project-nav-item">Code</a>
18
+ <a href="<%= file_path('smells_index.html') %>" class="project-nav-item">Smells</a>
19
+ </nav>
20
+ </div>
21
+ </header>
22
+ <div class="container">
23
+ <%= yield %>
24
+ </div>
25
+ <%= javascript_tag(:'jquery-2.1.0') %>
26
+ <%= javascript_tag(:'jquery.tablesorter') %>
27
+ <%= javascript_tag(:'jquery.floatThead-v1.2.7') %>
28
+ <%= javascript_tag(:'jquery.timeago-v1.4.1') %>
29
+ <%= javascript_tag(:'highcharts.src-4.0.1') %>
30
+ <%= javascript_tag(:'jquery.scrollTo-1.4.11') %>
31
+ <%= javascript_tag(:'prettify-4-Mar-2013') %>
32
+ <%= javascript_tag(:application) %>
33
+ </body>
34
+ </html>
@@ -0,0 +1,5 @@
1
+ <div id="js-chart-container" class="chart-container"></div>
2
+
3
+ <script type="text/javascript">
4
+ var turbulenceData = <%= @turbulence_data %>;
5
+ </script>
@@ -0,0 +1,26 @@
1
+ <table id="js-index-table" class="smells-index-table index-table sortable-table">
2
+ <thead>
3
+ <tr>
4
+ <th>Smell</th>
5
+ <th>Locations</th>
6
+ <% if @show_status %>
7
+ <th class="centered-cell" title="Code smells introduced recently are marked as new. There's still time before they are committed!">Status</th>
8
+ <% end %>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% @smells.each do |smell| %>
13
+ <tr>
14
+ <td><%= smell.type %></td>
15
+ <td>
16
+ <% smell.locations.each do |location| %>
17
+ <a href="<%= smell_location_path(location) %>"><%= @analysed_module_names[location.pathname] %></a>
18
+ <% end %>
19
+ </td>
20
+ <% if @show_status %>
21
+ <td class="centered-cell"><span class="status-<%= smell.status %> circled-text circle"><%= smell.status %></span></td>
22
+ <% end %>
23
+ </tr>
24
+ <% end %>
25
+ </tbody>
26
+ </table>
@@ -4,7 +4,7 @@
4
4
  <% @smells.each do |smell| %>
5
5
  <li class="smell <%= smell.status %>">
6
6
  <span class="description"><%= smell %>
7
- <% if smell.has_multiple_locations? %>
7
+ <% if smell.multiple_locations? %>
8
8
  <% smell.locations.each_with_index do |location, index| %>
9
9
  <a href="<%= smell_location_path(location) %>" class="js-smell-location"><%= index %></a>
10
10
  <% end %>
@@ -0,0 +1,17 @@
1
+ require "json"
2
+
3
+ module Rubycritic
4
+
5
+ module Turbulence
6
+ def self.data(analysed_modules)
7
+ analysed_modules.map do |analysed_module|
8
+ {
9
+ :name => analysed_module.name,
10
+ :x => analysed_module.churn,
11
+ :y => analysed_module.complexity
12
+ }
13
+ end.to_json
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,43 @@
1
+ module Rubycritic
2
+
3
+ module ViewHelpers
4
+ def timeago_tag(time)
5
+ "<time class='js-timeago' datetime='#{time}'>#{time}</time>"
6
+ end
7
+
8
+ def javascript_tag(file)
9
+ "<script src='" + asset_path("javascripts/#{file}.js").to_s + "'></script>"
10
+ end
11
+
12
+ def stylesheet_path(file)
13
+ asset_path("stylesheets/#{file}.css")
14
+ end
15
+
16
+ def asset_path(file)
17
+ relative_path("assets/#{file}")
18
+ end
19
+
20
+ def file_path(file)
21
+ relative_path(file)
22
+ end
23
+
24
+ def smell_location_path(location)
25
+ file_path("#{location.pathname.sub_ext('.html')}#L#{location.line}")
26
+ end
27
+
28
+ private
29
+
30
+ def relative_path(file)
31
+ (root_directory + file).relative_path_from(file_directory)
32
+ end
33
+
34
+ def file_directory
35
+ raise NotImplementedError.new("The #{self.class} class must implement the #{__method__} method.")
36
+ end
37
+
38
+ def root_directory
39
+ raise NotImplementedError.new("The #{self.class} class must implement the #{__method__} method.")
40
+ end
41
+ end
42
+
43
+ end
@@ -0,0 +1,66 @@
1
+ require "fileutils"
2
+ require "rubycritic/generators/html/overview"
3
+ require "rubycritic/generators/html/smells_index"
4
+ require "rubycritic/generators/html/code_index"
5
+ require "rubycritic/generators/html/code_file"
6
+
7
+ module Rubycritic
8
+ module Generator
9
+
10
+ class HtmlReport
11
+ ASSETS_DIR = File.expand_path("../html/assets", __FILE__)
12
+
13
+ def initialize(analysed_modules)
14
+ @analysed_modules = analysed_modules
15
+ end
16
+
17
+ def generate_report
18
+ create_directories_and_files
19
+ copy_assets_to_report_directory
20
+ puts "New critique at #{report_location}"
21
+ end
22
+
23
+ private
24
+
25
+ def create_directories_and_files
26
+ Array(generators).each do |generator|
27
+ FileUtils.mkdir_p(generator.file_directory)
28
+ File.open(generator.file_pathname, "w+") do |file|
29
+ file.write(generator.render)
30
+ end
31
+ end
32
+ end
33
+
34
+ def generators
35
+ [overview_generator, code_index_generator, smells_index_generator] + file_generators
36
+ end
37
+
38
+ def overview_generator
39
+ @overview_generator ||= Html::Overview.new(@analysed_modules)
40
+ end
41
+
42
+ def code_index_generator
43
+ Html::CodeIndex.new(@analysed_modules)
44
+ end
45
+
46
+ def smells_index_generator
47
+ Html::SmellsIndex.new(@analysed_modules)
48
+ end
49
+
50
+ def file_generators
51
+ @analysed_modules.map do |analysed_module|
52
+ Html::CodeFile.new(analysed_module)
53
+ end
54
+ end
55
+
56
+ def copy_assets_to_report_directory
57
+ FileUtils.cp_r(ASSETS_DIR, Config.root)
58
+ end
59
+
60
+ def report_location
61
+ overview_generator.file_href
62
+ end
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,30 @@
1
+ require "json"
2
+
3
+ module Rubycritic
4
+ module Generator
5
+ module Json
6
+
7
+ class Simple
8
+ def initialize(analysed_modules)
9
+ @analysed_modules = analysed_modules
10
+ end
11
+
12
+ def render
13
+ JSON.dump(data)
14
+ end
15
+
16
+ def data
17
+ {
18
+ :metadata => {
19
+ :rubycritic => {
20
+ :version => Rubycritic::VERSION
21
+ }
22
+ },
23
+ :analysed_modules => @analysed_modules
24
+ }
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ require "rubycritic/generators/json/simple"
2
+
3
+ module Rubycritic
4
+ module Generator
5
+
6
+ class JsonReport
7
+ def initialize(analysed_modules)
8
+ @analysed_modules = analysed_modules
9
+ end
10
+
11
+ def generate_report
12
+ print generator.render
13
+ end
14
+
15
+ private
16
+
17
+ def generator
18
+ Json::Simple.new(@analysed_modules)
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ module Rubycritic
2
+
3
+ module Reporter
4
+ def self.generate_report(analysed_modules)
5
+ report_generator_class.new(analysed_modules).generate_report
6
+ end
7
+
8
+ def self.report_generator_class
9
+ case Config.format
10
+ when :json
11
+ require "rubycritic/generators/json_report"
12
+ Generator::JsonReport
13
+ else
14
+ require "rubycritic/generators/html_report"
15
+ Generator::HtmlReport
16
+ end
17
+ end
18
+ end
19
+
20
+ end
@@ -1,54 +1,52 @@
1
- require "rubycritic/smelly_pathnames_serializer"
2
- require "rubycritic/source_locator"
1
+ require "rubycritic/serializer"
3
2
  require "rubycritic/analysers_runner"
4
- require "rubycritic/smells_aggregator"
5
3
  require "rubycritic/smells_status_setter"
4
+ require "rubycritic/version"
5
+ require "digest/md5"
6
6
 
7
7
  module Rubycritic
8
8
 
9
9
  class RevisionComparator
10
- SNAPSHOTS_DIR = File.expand_path("tmp/rubycritic/snapshots", Dir.getwd)
10
+ SNAPSHOTS_DIR_NAME = "snapshots"
11
11
 
12
- def initialize(paths, source_control_system)
12
+ def initialize(paths)
13
13
  @paths = paths
14
- @source_control_system = source_control_system
15
14
  end
16
15
 
17
- def compare
18
- SmellsStatusSetter.new(smelly_pathnames_before, smelly_pathnames_now).smelly_pathnames
16
+ def set_statuses(analysed_modules_now)
17
+ if Config.source_control_system.revision?
18
+ SmellsStatusSetter.set(
19
+ analysed_modules_before.flat_map(&:smells),
20
+ analysed_modules_now.flat_map(&:smells)
21
+ )
22
+ end
23
+ analysed_modules_now
19
24
  end
20
25
 
21
26
  private
22
27
 
23
- def smelly_pathnames_before
24
- serializer = SmellyPathnamesSerializer.new(revision_file)
28
+ def analysed_modules_before
29
+ serializer = Serializer.new(revision_file)
25
30
  if File.file?(revision_file)
26
31
  serializer.load
27
32
  else
28
- smelly_pathnames = nil
29
- @source_control_system.travel_to_head do
30
- smelly_pathnames = smelly_pathnames(paths_of_tracked_files)
33
+ analysed_modules = nil
34
+ Config.source_control_system.travel_to_head do
35
+ analysed_modules = AnalysersRunner.new(@paths).run
31
36
  end
32
- serializer.dump(smelly_pathnames)
33
- smelly_pathnames
37
+ serializer.dump(analysed_modules)
38
+ analysed_modules
34
39
  end
35
40
  end
36
41
 
37
- def smelly_pathnames_now
38
- smelly_pathnames(@paths)
39
- end
40
-
41
- def smelly_pathnames(paths)
42
- smell_adapters = AnalysersRunner.new(paths).run
43
- SmellsAggregator.new(smell_adapters).smelly_pathnames
44
- end
45
-
46
42
  def revision_file
47
- @revision_file ||= File.join(SNAPSHOTS_DIR, @source_control_system.head_reference)
48
- end
49
-
50
- def paths_of_tracked_files
51
- SourceLocator.new(["."]).paths
43
+ @revision_file ||= File.join(
44
+ Config.root,
45
+ SNAPSHOTS_DIR_NAME,
46
+ VERSION,
47
+ Digest::MD5.hexdigest(Marshal.dump(@paths)),
48
+ Config.source_control_system.head_reference
49
+ )
52
50
  end
53
51
  end
54
52
 
@@ -0,0 +1,32 @@
1
+ require "fileutils"
2
+
3
+ module Rubycritic
4
+
5
+ class Serializer
6
+ def initialize(file)
7
+ @file = file
8
+ end
9
+
10
+ def load
11
+ Marshal.load(File.binread(@file))
12
+ end
13
+
14
+ def dump(content)
15
+ create_file_directory
16
+ File.open(@file, "w+") do |file|
17
+ Marshal.dump(content, file)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def create_file_directory
24
+ FileUtils.mkdir_p(file_directory)
25
+ end
26
+
27
+ def file_directory
28
+ File.dirname(@file)
29
+ end
30
+ end
31
+
32
+ end
@@ -1,25 +1,16 @@
1
1
  module Rubycritic
2
2
 
3
- class SmellsStatusSetter
4
- def initialize(smelly_pathnames_before, smelly_pathnames_now)
5
- @smelly_pathnames_before = smelly_pathnames_before
6
- @smelly_pathnames_now = smelly_pathnames_now
7
- end
8
-
9
- def smelly_pathnames
10
- @smelly_pathnames_now.each do |pathname, smells_now|
11
- smells_before = @smelly_pathnames_before[pathname] || []
12
- old_smells = smells_now & smells_before
13
- set_status(old_smells, :old)
14
- new_smells = smells_now - smells_before
15
- set_status(new_smells, :new)
16
- end
17
- @smelly_pathnames_now
3
+ module SmellsStatusSetter
4
+ def self.set(smells_before, smells_now)
5
+ old_smells = smells_now & smells_before
6
+ set_status(old_smells, :old)
7
+ new_smells = smells_now - smells_before
8
+ set_status(new_smells, :new)
18
9
  end
19
10
 
20
11
  private
21
12
 
22
- def set_status(smells, status)
13
+ def self.set_status(smells, status)
23
14
  smells.each { |smell| smell.status = status }
24
15
  end
25
16
  end
@@ -0,0 +1,37 @@
1
+ require "shellwords"
2
+
3
+ module Rubycritic
4
+ module SourceControlSystem
5
+
6
+ class Base
7
+ @@systems = []
8
+
9
+ def self.register_system
10
+ @@systems << self
11
+ end
12
+
13
+ def self.systems
14
+ @@systems
15
+ end
16
+
17
+ def self.create
18
+ supported_system = systems.find(&:supported?)
19
+ if supported_system
20
+ supported_system.new
21
+ else
22
+ puts "RubyCritic can provide more feedback if you use a #{connected_system_names} repository."
23
+ Double.new
24
+ end
25
+ end
26
+
27
+ def self.connected_system_names
28
+ "#{systems[0...-1].join(', ')} or #{systems[-1]}"
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+
35
+ require "rubycritic/source_control_systems/double"
36
+ require "rubycritic/source_control_systems/git"
37
+ require "rubycritic/source_control_systems/mercurial"
@@ -0,0 +1,18 @@
1
+ module Rubycritic
2
+ module SourceControlSystem
3
+ class Double < Base
4
+ def revisions_count(_)
5
+ "N/A"
6
+ end
7
+
8
+ def date_of_last_commit(_)
9
+ nil
10
+ end
11
+
12
+ def revision?
13
+ false
14
+ end
15
+ end
16
+
17
+ end
18
+ end