rubycritic 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/lib/rubycritic/analysers/attributes.rb +21 -0
  4. data/lib/rubycritic/analysers/churn.rb +5 -5
  5. data/lib/rubycritic/analysers/complexity.rb +6 -6
  6. data/lib/rubycritic/analysers/helpers/ast_node.rb +73 -0
  7. data/lib/rubycritic/analysers/{adapters → helpers}/config.reek +0 -0
  8. data/lib/rubycritic/analysers/{adapters → helpers}/flay.rb +0 -0
  9. data/lib/rubycritic/analysers/{adapters → helpers}/flog.rb +0 -0
  10. data/lib/rubycritic/analysers/helpers/methods_counter.rb +28 -0
  11. data/lib/rubycritic/analysers/helpers/modules_locator.rb +46 -0
  12. data/lib/rubycritic/analysers/{adapters → helpers}/reek.rb +0 -0
  13. data/lib/rubycritic/analysers/smells/flay.rb +9 -9
  14. data/lib/rubycritic/analysers/smells/flog.rb +8 -8
  15. data/lib/rubycritic/analysers/smells/reek.rb +8 -8
  16. data/lib/rubycritic/analysers_runner.rb +6 -6
  17. data/lib/rubycritic/cli.rb +2 -2
  18. data/lib/rubycritic/core/{analysed_file.rb → analysed_module.rb} +4 -7
  19. data/lib/rubycritic/modules_initializer.rb +14 -0
  20. data/lib/rubycritic/orchestrator.rb +5 -5
  21. data/lib/rubycritic/report_generators/code_file.rb +4 -4
  22. data/lib/rubycritic/report_generators/code_index.rb +2 -2
  23. data/lib/rubycritic/report_generators/overview.rb +2 -2
  24. data/lib/rubycritic/report_generators/smells_index.rb +13 -2
  25. data/lib/rubycritic/report_generators/templates/code_file.html.erb +10 -10
  26. data/lib/rubycritic/report_generators/templates/code_index.html.erb +7 -7
  27. data/lib/rubycritic/report_generators/templates/smells_index.html.erb +1 -1
  28. data/lib/rubycritic/report_generators/turbulence.rb +5 -5
  29. data/lib/rubycritic/report_generators/view_helpers.rb +4 -4
  30. data/lib/rubycritic/reporters/main.rb +7 -8
  31. data/lib/rubycritic/reporters/mini.rb +3 -3
  32. data/lib/rubycritic/revision_comparator.rb +12 -10
  33. data/lib/rubycritic/source_locator.rb +1 -1
  34. data/lib/rubycritic/version.rb +1 -1
  35. data/rubycritic.gemspec +3 -4
  36. data/test/analysers_test_helper.rb +1 -1
  37. data/test/lib/rubycritic/analysers/churn_test.rb +9 -9
  38. data/test/lib/rubycritic/analysers/complexity_test.rb +5 -5
  39. data/test/lib/rubycritic/analysers/helpers/methods_counter_test.rb +29 -0
  40. data/test/lib/rubycritic/analysers/helpers/modules_locator_test.rb +53 -0
  41. data/test/lib/rubycritic/analysers/smells/flay_test.rb +10 -12
  42. data/test/lib/rubycritic/analysers/smells/flog_test.rb +7 -7
  43. data/test/lib/rubycritic/analysers/smells/reek_test.rb +10 -10
  44. data/test/lib/rubycritic/core/analysed_module_test.rb +88 -0
  45. data/test/lib/rubycritic/report_generators/turbulence_test.rb +4 -4
  46. data/test/lib/rubycritic/report_generators/view_helpers_test.rb +10 -23
  47. data/test/lib/rubycritic/smells_status_setter_test.rb +1 -1
  48. data/test/lib/rubycritic/source_locator_test.rb +6 -6
  49. data/test/samples/{stats/empty_example.rb → empty.rb} +0 -0
  50. data/test/samples/{stats/example.rb → methods_count.rb} +0 -0
  51. data/test/samples/module_names.rb +18 -0
  52. data/test/samples/unparsable.rb +1 -0
  53. metadata +30 -23
  54. data/lib/rubycritic/analysers/adapters/ast_node.rb +0 -35
  55. data/lib/rubycritic/analysers/stats.rb +0 -34
  56. data/lib/rubycritic/files_initializer.rb +0 -15
  57. data/test/lib/rubycritic/analysers/stats_test.rb +0 -30
  58. data/test/lib/rubycritic/core/analysed_file_test.rb +0 -86
  59. data/test/samples/stats/unparsable_example.rb +0 -2
@@ -0,0 +1,14 @@
1
+ require "rubycritic/source_locator"
2
+ require "rubycritic/core/analysed_module"
3
+
4
+ module Rubycritic
5
+
6
+ module ModulesInitializer
7
+ def self.init(paths)
8
+ SourceLocator.new(paths).pathnames.map do |pathname|
9
+ AnalysedModule.new(:pathname => pathname)
10
+ end
11
+ end
12
+ end
13
+
14
+ end
@@ -1,5 +1,5 @@
1
1
  require "rubycritic/source_control_systems/base"
2
- require "rubycritic/files_initializer"
2
+ require "rubycritic/modules_initializer"
3
3
  require "rubycritic/analysers_runner"
4
4
  require "rubycritic/revision_comparator"
5
5
 
@@ -11,12 +11,12 @@ module Rubycritic
11
11
  end
12
12
 
13
13
  def critique(paths)
14
- analysed_files = FilesInitializer.init(paths)
15
- AnalysersRunner.new(analysed_files, @source_control_system).run
14
+ analysed_modules = ModulesInitializer.init(paths)
15
+ AnalysersRunner.new(analysed_modules, @source_control_system).run
16
16
  if @source_control_system.has_revision?
17
- RevisionComparator.new(analysed_files, @source_control_system).set_statuses
17
+ RevisionComparator.new(analysed_modules, @source_control_system).set_statuses
18
18
  end
19
- analysed_files
19
+ analysed_modules
20
20
  end
21
21
  end
22
22
 
@@ -8,9 +8,9 @@ module Rubycritic
8
8
  LINE_NUMBER_OFFSET = 1
9
9
  TEMPLATE = erb_template("code_file.html.erb")
10
10
 
11
- def initialize(analysed_file)
12
- @analysed_file = analysed_file
13
- @pathname = @analysed_file.pathname
11
+ def initialize(analysed_module)
12
+ @analysed_module = analysed_module
13
+ @pathname = @analysed_module.pathname
14
14
  end
15
15
 
16
16
  def file_directory
@@ -25,7 +25,7 @@ module Rubycritic
25
25
  file_code = ""
26
26
  File.readlines(@pathname).each.with_index(LINE_NUMBER_OFFSET) do |line_text, line_number|
27
27
  location = Location.new(@pathname, line_number)
28
- line_smells = @analysed_file.smells_at_location(location)
28
+ line_smells = @analysed_module.smells_at_location(location)
29
29
  file_code << Line.new(file_directory, line_text, line_smells).render
30
30
  end
31
31
 
@@ -6,8 +6,8 @@ module Rubycritic
6
6
  class CodeIndex < Base
7
7
  TEMPLATE = erb_template("code_index.html.erb")
8
8
 
9
- def initialize(analysed_files)
10
- @analysed_files = analysed_files
9
+ def initialize(analysed_modules)
10
+ @analysed_modules = analysed_modules
11
11
  end
12
12
 
13
13
  def file_name
@@ -7,8 +7,8 @@ module Rubycritic
7
7
  class Overview < Base
8
8
  TEMPLATE = erb_template("overview.html.erb")
9
9
 
10
- def initialize(analysed_files)
11
- @turbulence_data = Turbulence.data(analysed_files)
10
+ def initialize(analysed_modules)
11
+ @turbulence_data = Turbulence.data(analysed_modules)
12
12
  end
13
13
 
14
14
  def file_name
@@ -6,8 +6,9 @@ module Rubycritic
6
6
  class SmellsIndex < Base
7
7
  TEMPLATE = erb_template("smells_index.html.erb")
8
8
 
9
- def initialize(smells)
10
- @smells = smells
9
+ def initialize(analysed_modules)
10
+ @smells = analysed_modules.flat_map(&:smells).uniq
11
+ @analysed_module_names = analysed_module_names(analysed_modules)
11
12
  end
12
13
 
13
14
  def file_name
@@ -18,6 +19,16 @@ module Rubycritic
18
19
  index_body = TEMPLATE.result(get_binding)
19
20
  LAYOUT_TEMPLATE.result(get_binding { index_body })
20
21
  end
22
+
23
+ private
24
+
25
+ def analysed_module_names(analysed_modules)
26
+ names = {}
27
+ analysed_modules.each do |analysed_module|
28
+ names[analysed_module.pathname] = analysed_module.name
29
+ end
30
+ names
31
+ end
21
32
  end
22
33
 
23
34
  end
@@ -1,10 +1,10 @@
1
1
  <div class="file-header group">
2
- <span class="rating-<%= @analysed_file.rating.to_s.downcase %> circled-text circle "><%= @analysed_file.rating %></span>
3
- <h2 class="file-name"><%= @analysed_file.name %></h2>
2
+ <span class="rating-<%= @analysed_module.rating.to_s.downcase %> circled-text circle "><%= @analysed_module.rating %></span>
3
+ <h2 class="file-name"><%= @analysed_module.name %></h2>
4
4
 
5
5
  <span class="file-committed-at">
6
- <% if @analysed_file.committed_at %>
7
- Updated <%= timeago_tag(@analysed_file.committed_at) %>
6
+ <% if @analysed_module.committed_at %>
7
+ Updated <%= timeago_tag(@analysed_module.committed_at) %>
8
8
  <% else %>
9
9
  Never committed
10
10
  <% end %>
@@ -12,23 +12,23 @@
12
12
 
13
13
  <div class="file-stats group">
14
14
  <div class="file-stat">
15
- <%= @analysed_file.complexity %> complexity
15
+ <%= @analysed_module.complexity %> complexity
16
16
  </div>
17
17
  <div class="file-stat">
18
- <%= @analysed_file.complexity_per_method %> complexity per method
18
+ <%= @analysed_module.complexity_per_method %> complexity per method
19
19
  </div>
20
20
  <div class="file-stat">
21
- <%= @analysed_file.churn %> churn
21
+ <%= @analysed_module.churn %> churn
22
22
  </div>
23
23
  <div class="file-stat">
24
- <%= @analysed_file.methods_count %> methods
24
+ <%= @analysed_module.methods_count %> methods
25
25
  </div>
26
26
  <div class="file-stat">
27
- <%= @analysed_file.duplication %> duplication
27
+ <%= @analysed_module.duplication %> duplication
28
28
  </div>
29
29
  </div>
30
30
 
31
- <% if @analysed_file.has_smells? %>
31
+ <% if @analysed_module.has_smells? %>
32
32
  <button id="js-toggle-smells" class="smells-toggle-button button">Toggle Smells</button>
33
33
  <% end %>
34
34
  </div>
@@ -10,16 +10,16 @@
10
10
  </tr>
11
11
  </thead>
12
12
  <tbody>
13
- <% @analysed_files.each do |analysed_file| %>
13
+ <% @analysed_modules.each do |analysed_module| %>
14
14
  <tr>
15
15
  <td class="first-cell">
16
- <a href="<%= file_path(analysed_file.pathname.sub_ext('.html')) %>"><%= analysed_file.name %></a>
16
+ <a href="<%= file_path(analysed_module.pathname.sub_ext('.html')) %>"><%= analysed_module.name %></a>
17
17
  </td>
18
- <td class="numeric-cell"><%= analysed_file.churn %></td>
19
- <td class="numeric-cell"><%= analysed_file.complexity %></td>
20
- <td class="numeric-cell"><%= analysed_file.duplication %></td>
21
- <td class="numeric-cell"><%= analysed_file.smells.length %></td>
22
- <td class="centered-cell last-cell"><span class="rating-<%= analysed_file.rating.to_s.downcase %> circled-text circle"><%= analysed_file.rating %></span></td>
18
+ <td class="numeric-cell"><%= analysed_module.churn %></td>
19
+ <td class="numeric-cell"><%= analysed_module.complexity %></td>
20
+ <td class="numeric-cell"><%= analysed_module.duplication %></td>
21
+ <td class="numeric-cell"><%= analysed_module.smells.length %></td>
22
+ <td class="centered-cell last-cell"><span class="rating-<%= analysed_module.rating.to_s.downcase %> circled-text circle"><%= analysed_module.rating %></span></td>
23
23
  </tr>
24
24
  <% end %>
25
25
  </tbody>
@@ -12,7 +12,7 @@
12
12
  <td class="first-cell"><%= smell.type %></td>
13
13
  <td>
14
14
  <% smell.locations.each do |location| %>
15
- <a href="<%= smell_location_path(location) %>"><%= location.file_name %></a>
15
+ <a href="<%= smell_location_path(location) %>"><%= @analysed_module_names[location.pathname] %></a>
16
16
  <% end %>
17
17
  </td>
18
18
  <td class="centered-cell last-cell"><span class="status-<%= smell.status %> circled-text circle"><%= smell.status %></span></td>
@@ -3,12 +3,12 @@ require "json"
3
3
  module Rubycritic
4
4
 
5
5
  module Turbulence
6
- def self.data(analysed_files)
7
- analysed_files.map do |analysed_file|
6
+ def self.data(analysed_modules)
7
+ analysed_modules.map do |analysed_module|
8
8
  {
9
- :name => analysed_file.pathname,
10
- :x => analysed_file.churn,
11
- :y => analysed_file.complexity
9
+ :name => analysed_module.name,
10
+ :x => analysed_module.churn,
11
+ :y => analysed_module.complexity
12
12
  }
13
13
  end.to_json
14
14
  end
@@ -6,15 +6,15 @@ module Rubycritic
6
6
  end
7
7
 
8
8
  def javascript_tag(file)
9
- "<script src='" + asset_path("javascripts", "#{file}.js").to_s + "'></script>"
9
+ "<script src='" + asset_path("javascripts/#{file}.js").to_s + "'></script>"
10
10
  end
11
11
 
12
12
  def stylesheet_path(file)
13
- asset_path("stylesheets", "#{file}.css")
13
+ asset_path("stylesheets/#{file}.css")
14
14
  end
15
15
 
16
- def asset_path(*fragments)
17
- relative_path(([root_directory, "assets"] + fragments).reduce(:+))
16
+ def asset_path(file)
17
+ relative_path(root_directory + "assets" + file)
18
18
  end
19
19
 
20
20
  def file_path(file)
@@ -8,9 +8,8 @@ module Rubycritic
8
8
  module Reporter
9
9
 
10
10
  class Main < Base
11
- def initialize(analysed_files)
12
- @analysed_files = analysed_files
13
- @smells = analysed_files.flat_map(&:smells).uniq
11
+ def initialize(analysed_modules)
12
+ @analysed_modules = analysed_modules
14
13
  end
15
14
 
16
15
  def generate_report
@@ -26,20 +25,20 @@ module Rubycritic
26
25
  end
27
26
 
28
27
  def overview_generator
29
- @overview_generator ||= Generator::Overview.new(@analysed_files)
28
+ @overview_generator ||= Generator::Overview.new(@analysed_modules)
30
29
  end
31
30
 
32
31
  def code_index_generator
33
- Generator::CodeIndex.new(@analysed_files)
32
+ Generator::CodeIndex.new(@analysed_modules)
34
33
  end
35
34
 
36
35
  def smells_index_generator
37
- Generator::SmellsIndex.new(@smells)
36
+ Generator::SmellsIndex.new(@analysed_modules)
38
37
  end
39
38
 
40
39
  def file_generators
41
- @analysed_files.map do |analysed_file|
42
- Generator::CodeFile.new(analysed_file)
40
+ @analysed_modules.map do |analysed_module|
41
+ Generator::CodeFile.new(analysed_module)
43
42
  end
44
43
  end
45
44
 
@@ -5,8 +5,8 @@ module Rubycritic
5
5
  module Reporter
6
6
 
7
7
  class Mini < Base
8
- def initialize(analysed_files)
9
- @analysed_file = analysed_files.first
8
+ def initialize(analysed_modules)
9
+ @analysed_module = analysed_modules.first
10
10
  end
11
11
 
12
12
  def generate_report
@@ -18,7 +18,7 @@ module Rubycritic
18
18
  private
19
19
 
20
20
  def file_generator
21
- @file_generator ||= Generator::CurrentCodeFile.new(@analysed_file)
21
+ @file_generator ||= Generator::CurrentCodeFile.new(@analysed_module)
22
22
  end
23
23
 
24
24
  def report_location
@@ -1,38 +1,39 @@
1
1
  require "rubycritic/serializer"
2
- require "rubycritic/files_initializer"
2
+ require "rubycritic/modules_initializer"
3
3
  require "rubycritic/analysers_runner"
4
4
  require "rubycritic/smells_status_setter"
5
+ require "rubycritic/version"
5
6
 
6
7
  module Rubycritic
7
8
 
8
9
  class RevisionComparator
9
10
  SNAPSHOTS_DIR_NAME = "snapshots"
10
11
 
11
- def initialize(analysed_files, source_control_system)
12
- @analysed_files_now = analysed_files
12
+ def initialize(analysed_modules, source_control_system)
13
+ @analysed_modules_now = analysed_modules
13
14
  @source_control_system = source_control_system
14
15
  end
15
16
 
16
17
  def set_statuses
17
18
  SmellsStatusSetter.set(
18
- analysed_files_before.flat_map(&:smells),
19
- @analysed_files_now.flat_map(&:smells)
19
+ analysed_modules_before.flat_map(&:smells),
20
+ @analysed_modules_now.flat_map(&:smells)
20
21
  )
21
22
  end
22
23
 
23
24
  private
24
25
 
25
- def analysed_files_before
26
+ def analysed_modules_before
26
27
  serializer = Serializer.new(revision_file)
27
28
  if File.file?(revision_file)
28
29
  serializer.load
29
30
  else
30
- analysed_files = FilesInitializer.init(["."])
31
+ analysed_modules = ModulesInitializer.init(["."])
31
32
  @source_control_system.travel_to_head do
32
- AnalysersRunner.new(analysed_files, @source_control_system).run
33
+ AnalysersRunner.new(analysed_modules, @source_control_system).run
33
34
  end
34
- serializer.dump(analysed_files)
35
- analysed_files
35
+ serializer.dump(analysed_modules)
36
+ analysed_modules
36
37
  end
37
38
  end
38
39
 
@@ -40,6 +41,7 @@ module Rubycritic
40
41
  @revision_file ||= File.join(
41
42
  ::Rubycritic.configuration.root,
42
43
  SNAPSHOTS_DIR_NAME,
44
+ VERSION,
43
45
  @source_control_system.head_reference
44
46
  )
45
47
  end
@@ -27,7 +27,7 @@ module Rubycritic
27
27
  elsif File.exists?(path) && File.extname(path) == RUBY_EXTENSION
28
28
  Pathname.new(path)
29
29
  end
30
- end.flatten.compact.map(&:cleanpath).sort
30
+ end.flatten.compact.map(&:cleanpath)
31
31
  end
32
32
  end
33
33
 
@@ -1,3 +1,3 @@
1
1
  module Rubycritic
2
- VERSION = "1.0.2"
2
+ VERSION = "1.1.0"
3
3
  end
data/rubycritic.gemspec CHANGED
@@ -8,10 +8,9 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Rubycritic::VERSION
9
9
  spec.authors = ["Guilherme Simoes"]
10
10
  spec.email = ["guilherme.rdems@gmail.com"]
11
- spec.description = <<-EOF
12
- Ruby Critic is a tool that detects and reports smells in Ruby classes, modules and methods.
13
- EOF
14
- spec.summary = "Ruby code smell detector"
11
+ spec.description = "RubyCritic is a tool that wraps around various static analysis gems "\
12
+ "to provide a quality report of your Ruby code."
13
+ spec.summary = "RubyCritic is a Ruby code quality reporter"
15
14
  spec.homepage = "https://github.com/whitesmith/rubycritic"
16
15
  spec.license = "MIT"
17
16
  spec.required_ruby_version = ">= 1.9.3"
@@ -1,3 +1,3 @@
1
1
  require "test_helper"
2
2
 
3
- class AnalysedFileDouble < OpenStruct; end
3
+ class AnalysedModuleDouble < OpenStruct; end
@@ -4,21 +4,21 @@ require "rubycritic/source_control_systems/base"
4
4
 
5
5
  describe Rubycritic::Analyser::Churn do
6
6
  before do
7
- @analysed_files = [AnalysedFileDouble.new(:path => "path_to_some_file.rb")]
7
+ @analysed_modules = [AnalysedModuleDouble.new(:path => "path_to_some_file.rb")]
8
8
  @source_control_system = SourceControlSystemDouble.new
9
9
  end
10
10
 
11
- it "calculates the churn of each file and adds it to analysed_files" do
12
- Rubycritic::Analyser::Churn.new(@analysed_files, @source_control_system).run
13
- @analysed_files.each do |analysed_file|
14
- analysed_file.churn.must_equal 1
11
+ it "calculates the churn of each file and adds it to analysed_modules" do
12
+ Rubycritic::Analyser::Churn.new(@analysed_modules, @source_control_system).run
13
+ @analysed_modules.each do |analysed_module|
14
+ analysed_module.churn.must_equal 1
15
15
  end
16
16
  end
17
17
 
18
- it "calculates the date of the last commit of each file and adds it to analysed_files" do
19
- Rubycritic::Analyser::Churn.new(@analysed_files, @source_control_system).run
20
- @analysed_files.each do |analysed_file|
21
- analysed_file.committed_at.must_equal "2013-10-09 12:52:49 +0100"
18
+ it "calculates the date of the last commit of each file and adds it to analysed_modules" do
19
+ Rubycritic::Analyser::Churn.new(@analysed_modules, @source_control_system).run
20
+ @analysed_modules.each do |analysed_module|
21
+ analysed_module.committed_at.must_equal "2013-10-09 12:52:49 +0100"
22
22
  end
23
23
  end
24
24
  end
@@ -2,11 +2,11 @@ require "analysers_test_helper"
2
2
  require "rubycritic/analysers/complexity"
3
3
 
4
4
  describe Rubycritic::Analyser::Complexity do
5
- it "calculates the complexity of each file and adds it to analysed_files" do
6
- analysed_files = [AnalysedFileDouble.new(:path => "test/samples/flog/complex.rb")]
7
- Rubycritic::Analyser::Complexity.new(analysed_files).run
8
- analysed_files.each do |analysed_file|
9
- analysed_file.complexity.must_be_kind_of Numeric
5
+ it "calculates the complexity of each file and adds it to analysed_modules" do
6
+ analysed_modules = [AnalysedModuleDouble.new(:path => "test/samples/flog/complex.rb")]
7
+ Rubycritic::Analyser::Complexity.new(analysed_modules).run
8
+ analysed_modules.each do |analysed_module|
9
+ analysed_module.complexity.must_be_kind_of Numeric
10
10
  end
11
11
  end
12
12
  end
@@ -0,0 +1,29 @@
1
+ require "analysers_test_helper"
2
+ require "rubycritic/analysers/helpers/methods_counter"
3
+
4
+ describe Rubycritic::MethodsCounter do
5
+ describe "#count" do
6
+ context "when a file contains Ruby code" do
7
+ it "calculates the number of methods" do
8
+ analysed_module = AnalysedModuleDouble.new(:path => "test/samples/methods_count.rb")
9
+ Rubycritic::MethodsCounter.new(analysed_module).count.must_equal 2
10
+ end
11
+ end
12
+
13
+ context "when a file is empty" do
14
+ it "returns 0 as the number of methods" do
15
+ analysed_module = AnalysedModuleDouble.new(:path => "test/samples/empty.rb")
16
+ Rubycritic::MethodsCounter.new(analysed_module).count.must_equal 0
17
+ end
18
+ end
19
+
20
+ context "when a file is unparsable" do
21
+ it "does not blow up and returns 0 as the number of methods" do
22
+ analysed_module = AnalysedModuleDouble.new(:path => "test/samples/unparsable.rb")
23
+ capture_output_streams do
24
+ Rubycritic::MethodsCounter.new(analysed_module).count.must_equal 0
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end