rubycritic 1.0.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/lib/rubycritic/analysers/attributes.rb +21 -0
- data/lib/rubycritic/analysers/churn.rb +5 -5
- data/lib/rubycritic/analysers/complexity.rb +6 -6
- data/lib/rubycritic/analysers/helpers/ast_node.rb +73 -0
- data/lib/rubycritic/analysers/{adapters → helpers}/config.reek +0 -0
- data/lib/rubycritic/analysers/{adapters → helpers}/flay.rb +0 -0
- data/lib/rubycritic/analysers/{adapters → helpers}/flog.rb +0 -0
- data/lib/rubycritic/analysers/helpers/methods_counter.rb +28 -0
- data/lib/rubycritic/analysers/helpers/modules_locator.rb +46 -0
- data/lib/rubycritic/analysers/{adapters → helpers}/reek.rb +0 -0
- data/lib/rubycritic/analysers/smells/flay.rb +9 -9
- data/lib/rubycritic/analysers/smells/flog.rb +8 -8
- data/lib/rubycritic/analysers/smells/reek.rb +8 -8
- data/lib/rubycritic/analysers_runner.rb +6 -6
- data/lib/rubycritic/cli.rb +2 -2
- data/lib/rubycritic/core/{analysed_file.rb → analysed_module.rb} +4 -7
- data/lib/rubycritic/modules_initializer.rb +14 -0
- data/lib/rubycritic/orchestrator.rb +5 -5
- data/lib/rubycritic/report_generators/code_file.rb +4 -4
- data/lib/rubycritic/report_generators/code_index.rb +2 -2
- data/lib/rubycritic/report_generators/overview.rb +2 -2
- data/lib/rubycritic/report_generators/smells_index.rb +13 -2
- data/lib/rubycritic/report_generators/templates/code_file.html.erb +10 -10
- data/lib/rubycritic/report_generators/templates/code_index.html.erb +7 -7
- data/lib/rubycritic/report_generators/templates/smells_index.html.erb +1 -1
- data/lib/rubycritic/report_generators/turbulence.rb +5 -5
- data/lib/rubycritic/report_generators/view_helpers.rb +4 -4
- data/lib/rubycritic/reporters/main.rb +7 -8
- data/lib/rubycritic/reporters/mini.rb +3 -3
- data/lib/rubycritic/revision_comparator.rb +12 -10
- data/lib/rubycritic/source_locator.rb +1 -1
- data/lib/rubycritic/version.rb +1 -1
- data/rubycritic.gemspec +3 -4
- data/test/analysers_test_helper.rb +1 -1
- data/test/lib/rubycritic/analysers/churn_test.rb +9 -9
- data/test/lib/rubycritic/analysers/complexity_test.rb +5 -5
- data/test/lib/rubycritic/analysers/helpers/methods_counter_test.rb +29 -0
- data/test/lib/rubycritic/analysers/helpers/modules_locator_test.rb +53 -0
- data/test/lib/rubycritic/analysers/smells/flay_test.rb +10 -12
- data/test/lib/rubycritic/analysers/smells/flog_test.rb +7 -7
- data/test/lib/rubycritic/analysers/smells/reek_test.rb +10 -10
- data/test/lib/rubycritic/core/analysed_module_test.rb +88 -0
- data/test/lib/rubycritic/report_generators/turbulence_test.rb +4 -4
- data/test/lib/rubycritic/report_generators/view_helpers_test.rb +10 -23
- data/test/lib/rubycritic/smells_status_setter_test.rb +1 -1
- data/test/lib/rubycritic/source_locator_test.rb +6 -6
- data/test/samples/{stats/empty_example.rb → empty.rb} +0 -0
- data/test/samples/{stats/example.rb → methods_count.rb} +0 -0
- data/test/samples/module_names.rb +18 -0
- data/test/samples/unparsable.rb +1 -0
- metadata +30 -23
- data/lib/rubycritic/analysers/adapters/ast_node.rb +0 -35
- data/lib/rubycritic/analysers/stats.rb +0 -34
- data/lib/rubycritic/files_initializer.rb +0 -15
- data/test/lib/rubycritic/analysers/stats_test.rb +0 -30
- data/test/lib/rubycritic/core/analysed_file_test.rb +0 -86
- 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/
|
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
|
-
|
15
|
-
AnalysersRunner.new(
|
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(
|
17
|
+
RevisionComparator.new(analysed_modules, @source_control_system).set_statuses
|
18
18
|
end
|
19
|
-
|
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(
|
12
|
-
@
|
13
|
-
@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 = @
|
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(
|
10
|
-
@
|
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(
|
11
|
-
@turbulence_data = Turbulence.data(
|
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(
|
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-<%= @
|
3
|
-
<h2 class="file-name"><%= @
|
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 @
|
7
|
-
Updated <%= timeago_tag(@
|
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
|
-
<%= @
|
15
|
+
<%= @analysed_module.complexity %> complexity
|
16
16
|
</div>
|
17
17
|
<div class="file-stat">
|
18
|
-
<%= @
|
18
|
+
<%= @analysed_module.complexity_per_method %> complexity per method
|
19
19
|
</div>
|
20
20
|
<div class="file-stat">
|
21
|
-
<%= @
|
21
|
+
<%= @analysed_module.churn %> churn
|
22
22
|
</div>
|
23
23
|
<div class="file-stat">
|
24
|
-
<%= @
|
24
|
+
<%= @analysed_module.methods_count %> methods
|
25
25
|
</div>
|
26
26
|
<div class="file-stat">
|
27
|
-
<%= @
|
27
|
+
<%= @analysed_module.duplication %> duplication
|
28
28
|
</div>
|
29
29
|
</div>
|
30
30
|
|
31
|
-
<% if @
|
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
|
-
<% @
|
13
|
+
<% @analysed_modules.each do |analysed_module| %>
|
14
14
|
<tr>
|
15
15
|
<td class="first-cell">
|
16
|
-
<a href="<%= file_path(
|
16
|
+
<a href="<%= file_path(analysed_module.pathname.sub_ext('.html')) %>"><%= analysed_module.name %></a>
|
17
17
|
</td>
|
18
|
-
<td class="numeric-cell"><%=
|
19
|
-
<td class="numeric-cell"><%=
|
20
|
-
<td class="numeric-cell"><%=
|
21
|
-
<td class="numeric-cell"><%=
|
22
|
-
<td class="centered-cell last-cell"><span class="rating-<%=
|
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.
|
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(
|
7
|
-
|
6
|
+
def self.data(analysed_modules)
|
7
|
+
analysed_modules.map do |analysed_module|
|
8
8
|
{
|
9
|
-
:name =>
|
10
|
-
:x =>
|
11
|
-
:y =>
|
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
|
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
|
13
|
+
asset_path("stylesheets/#{file}.css")
|
14
14
|
end
|
15
15
|
|
16
|
-
def asset_path(
|
17
|
-
relative_path(
|
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(
|
12
|
-
@
|
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(@
|
28
|
+
@overview_generator ||= Generator::Overview.new(@analysed_modules)
|
30
29
|
end
|
31
30
|
|
32
31
|
def code_index_generator
|
33
|
-
Generator::CodeIndex.new(@
|
32
|
+
Generator::CodeIndex.new(@analysed_modules)
|
34
33
|
end
|
35
34
|
|
36
35
|
def smells_index_generator
|
37
|
-
Generator::SmellsIndex.new(@
|
36
|
+
Generator::SmellsIndex.new(@analysed_modules)
|
38
37
|
end
|
39
38
|
|
40
39
|
def file_generators
|
41
|
-
@
|
42
|
-
Generator::CodeFile.new(
|
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(
|
9
|
-
@
|
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(@
|
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/
|
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(
|
12
|
-
@
|
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
|
-
|
19
|
-
@
|
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
|
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
|
-
|
31
|
+
analysed_modules = ModulesInitializer.init(["."])
|
31
32
|
@source_control_system.travel_to_head do
|
32
|
-
AnalysersRunner.new(
|
33
|
+
AnalysersRunner.new(analysed_modules, @source_control_system).run
|
33
34
|
end
|
34
|
-
serializer.dump(
|
35
|
-
|
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
|
data/lib/rubycritic/version.rb
CHANGED
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 =
|
12
|
-
|
13
|
-
|
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"
|
@@ -4,21 +4,21 @@ require "rubycritic/source_control_systems/base"
|
|
4
4
|
|
5
5
|
describe Rubycritic::Analyser::Churn do
|
6
6
|
before do
|
7
|
-
@
|
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
|
12
|
-
Rubycritic::Analyser::Churn.new(@
|
13
|
-
@
|
14
|
-
|
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
|
19
|
-
Rubycritic::Analyser::Churn.new(@
|
20
|
-
@
|
21
|
-
|
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
|
6
|
-
|
7
|
-
Rubycritic::Analyser::Complexity.new(
|
8
|
-
|
9
|
-
|
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
|