rubycritic 1.0.2 → 1.1.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.
- 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
|