analyst 0.13.1 → 0.14.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/analyst.gemspec +4 -3
- data/lib/analyst/{entity_parser/association.rb → association.rb} +0 -0
- data/lib/analyst/entities/begin.rb +13 -0
- data/lib/analyst/entities/class.rb +97 -0
- data/lib/analyst/entities/empty.rb +10 -0
- data/lib/analyst/entities/entity.rb +67 -0
- data/lib/analyst/entities/method.rb +41 -0
- data/lib/analyst/entities/method_call.rb +28 -0
- data/lib/analyst/entities/module.rb +33 -0
- data/lib/analyst/entities/root.rb +22 -0
- data/lib/analyst/entities/singleton_class.rb +21 -0
- data/lib/analyst/parser.rb +30 -55
- data/lib/analyst/version.rb +1 -1
- data/lib/analyst.rb +40 -9
- data/spec/class_spec.rb +30 -0
- data/spec/fixtures/music.rb +70 -0
- data/spec/method_spec.rb +9 -0
- data/spec/parser_spec.rb +29 -0
- data/spec/spec_helper.rb +1 -0
- metadata +38 -87
- data/lib/analyst/cli.rb +0 -42
- data/lib/analyst/entity_parser/entities/class.rb +0 -92
- data/lib/analyst/entity_parser/entities/empty.rb +0 -13
- data/lib/analyst/entity_parser/entities/entity.rb +0 -29
- data/lib/analyst/entity_parser/entities/method.rb +0 -16
- data/lib/analyst/entity_parser/entities/module.rb +0 -31
- data/lib/analyst/formatters/base.rb +0 -33
- data/lib/analyst/formatters/csv.rb +0 -43
- data/lib/analyst/formatters/html.rb +0 -87
- data/lib/analyst/formatters/html_index.rb +0 -47
- data/lib/analyst/formatters/templates/index.html.haml +0 -92
- data/lib/analyst/formatters/templates/output.html.haml +0 -114
- data/lib/analyst/formatters/text.rb +0 -56
- data/lib/analyst/fukuzatsu/analyzer.rb +0 -162
- data/lib/analyst/fukuzatsu/cli.rb +0 -42
- data/lib/analyst/fukuzatsu/entity_parser/association.rb +0 -24
- data/lib/analyst/fukuzatsu/entity_parser/entities/class.rb +0 -92
- data/lib/analyst/fukuzatsu/entity_parser/entities/empty.rb +0 -13
- data/lib/analyst/fukuzatsu/entity_parser/entities/entity.rb +0 -29
- data/lib/analyst/fukuzatsu/entity_parser/entities/method.rb +0 -16
- data/lib/analyst/fukuzatsu/entity_parser/entities/module.rb +0 -31
- data/lib/analyst/fukuzatsu/formatters/base.rb +0 -33
- data/lib/analyst/fukuzatsu/formatters/csv.rb +0 -43
- data/lib/analyst/fukuzatsu/formatters/html.rb +0 -87
- data/lib/analyst/fukuzatsu/formatters/html_index.rb +0 -47
- data/lib/analyst/fukuzatsu/formatters/templates/index.html.haml +0 -92
- data/lib/analyst/fukuzatsu/formatters/templates/output.html.haml +0 -114
- data/lib/analyst/fukuzatsu/formatters/text.rb +0 -56
- data/lib/analyst/fukuzatsu/line_of_code.rb +0 -19
- data/lib/analyst/fukuzatsu/parsed_file.rb +0 -85
- data/lib/analyst/fukuzatsu/parsed_method.rb +0 -32
- data/lib/analyst/fukuzatsu/parser_original.rb +0 -76
- data/lib/analyst/fukuzatsu/rethink/parser.rb +0 -346
- data/lib/analyst/fukuzatsu/version.rb +0 -3
- data/lib/analyst/line_of_code.rb +0 -19
- data/lib/analyst/parsed_file.rb +0 -85
- data/lib/analyst/parsed_method.rb +0 -32
- data/lib/analyst/rethink/parser.rb +0 -346
- data/spec/analyzer_spec.rb +0 -122
- data/spec/cli_spec.rb +0 -48
- data/spec/fixtures/eg_class.rb +0 -8
- data/spec/fixtures/eg_mod_class.rb +0 -2
- data/spec/fixtures/eg_mod_class_2.rb +0 -5
- data/spec/fixtures/eg_module.rb +0 -2
- data/spec/fixtures/module_with_class.rb +0 -9
- data/spec/fixtures/multiple_methods.rb +0 -7
- data/spec/fixtures/nested_methods.rb +0 -8
- data/spec/fixtures/program_1.rb +0 -19
- data/spec/fixtures/program_2.rb +0 -25
- data/spec/fixtures/program_3.rb +0 -66
- data/spec/fixtures/program_4.rb +0 -1
- data/spec/fixtures/single_class.rb +0 -9
- data/spec/fixtures/single_method.rb +0 -3
- data/spec/formatters/csv_spec.rb +0 -37
- data/spec/formatters/html_index_spec.rb +0 -36
- data/spec/formatters/html_spec.rb +0 -48
- data/spec/formatters/text_spec.rb +0 -39
- data/spec/parsed_file_spec.rb +0 -67
- data/spec/parsed_method_spec.rb +0 -34
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
module Formatters
|
|
2
|
-
|
|
3
|
-
module Base
|
|
4
|
-
|
|
5
|
-
def self.included(klass)
|
|
6
|
-
klass.send(:attr_accessor, :file)
|
|
7
|
-
klass.send(:attr_accessor, :source)
|
|
8
|
-
klass.send(:attr_accessor, :output_directory)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def initialize(file, output_directory=nil, source="")
|
|
12
|
-
self.file = file
|
|
13
|
-
self.source = source
|
|
14
|
-
self.output_directory = output_directory
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def filename
|
|
18
|
-
File.basename(self.file.path_to_file) + file_extension
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def output_path
|
|
22
|
-
output_path = File.dirname(File.join(self.output_directory, self.file.path_to_file))
|
|
23
|
-
FileUtils.mkpath(output_path)
|
|
24
|
-
output_path
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def path_to_results
|
|
28
|
-
File.join(output_path, filename)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
end
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
module Formatters
|
|
2
|
-
|
|
3
|
-
class Csv
|
|
4
|
-
|
|
5
|
-
include Formatters::Base
|
|
6
|
-
|
|
7
|
-
def self.has_index?
|
|
8
|
-
false
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def self.writes_to_file_system?
|
|
12
|
-
true
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def content
|
|
16
|
-
rows + "\r\n"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def export
|
|
20
|
-
begin
|
|
21
|
-
File.open(path_to_results, 'a') {|outfile| outfile.write(content)}
|
|
22
|
-
rescue Exception => e
|
|
23
|
-
puts "Unable to write output: #{e} #{e.backtrace}"
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def file_extension
|
|
28
|
-
".csv"
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def path_to_results
|
|
32
|
-
File.join(output_directory, "results#{file_extension}")
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def rows
|
|
36
|
-
file.methods.map do |method|
|
|
37
|
-
"#{file.path_to_file},#{file.class_name},#{method.name},#{method.complexity}"
|
|
38
|
-
end.join("\r\n")
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
end
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
require 'rouge'
|
|
2
|
-
|
|
3
|
-
module Formatters
|
|
4
|
-
|
|
5
|
-
class Html
|
|
6
|
-
|
|
7
|
-
include Formatters::Base
|
|
8
|
-
|
|
9
|
-
def self.has_index?
|
|
10
|
-
true
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def self.writes_to_file_system?
|
|
14
|
-
true
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def self.index_class
|
|
18
|
-
Formatters::HtmlIndex
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def columns
|
|
22
|
-
["class", "method", "complexity"]
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def content
|
|
26
|
-
Haml::Engine.new(output_template).render(
|
|
27
|
-
Object.new, {
|
|
28
|
-
header: header,
|
|
29
|
-
rows: rows,
|
|
30
|
-
source_lines: preprocessed,
|
|
31
|
-
class_name: file.class_name,
|
|
32
|
-
complexity: file.complexity,
|
|
33
|
-
path_to_file: file.path_to_file,
|
|
34
|
-
date: Time.now.strftime("%Y/%m/%d"),
|
|
35
|
-
time: Time.now.strftime("%l:%M %P")
|
|
36
|
-
}
|
|
37
|
-
)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def export
|
|
41
|
-
begin
|
|
42
|
-
File.open(path_to_results, 'w') {|outfile| outfile.write(content)}
|
|
43
|
-
rescue Exception => e
|
|
44
|
-
puts "Unable to write output: #{e} #{e.backtrace}"
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def formatter
|
|
49
|
-
Rouge::Formatters::HTML.new(line_numbers: true)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def header
|
|
53
|
-
columns.map{|col| "<th>#{col.titleize}</th>"}.join("\r\n")
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def lexer
|
|
57
|
-
lexer = Rouge::Lexers::Ruby.new
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def output_template
|
|
61
|
-
File.read(File.dirname(__FILE__) + "/templates/output.html.haml")
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def preprocessed
|
|
65
|
-
formatter.format(lexer.lex(source))
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def rows
|
|
69
|
-
i = 0
|
|
70
|
-
file.methods.inject([]) do |a, method|
|
|
71
|
-
i += 1
|
|
72
|
-
a << "<tr class='#{i % 2 == 1 ? 'even' : 'odd'}'>"
|
|
73
|
-
a << " <td>#{file.class_name}</td>"
|
|
74
|
-
a << " <td>#{method.name}</td>"
|
|
75
|
-
a << " <td>#{method.complexity}</td>"
|
|
76
|
-
a << "</tr>"
|
|
77
|
-
a
|
|
78
|
-
end.join("\r\n")
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def file_extension
|
|
82
|
-
".htm"
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
end
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
module Formatters
|
|
2
|
-
|
|
3
|
-
class HtmlIndex
|
|
4
|
-
|
|
5
|
-
include Formatters::Base
|
|
6
|
-
|
|
7
|
-
attr_reader :file_summary, :output_directory
|
|
8
|
-
|
|
9
|
-
def initialize(file_summary, output_directory=nil)
|
|
10
|
-
@file_summary = file_summary
|
|
11
|
-
@output_directory = output_directory
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def content
|
|
15
|
-
Haml::Engine.new(output_template).render(
|
|
16
|
-
Object.new, {
|
|
17
|
-
file_summary: file_summary,
|
|
18
|
-
date: Time.now.strftime("%Y/%m/%d"),
|
|
19
|
-
time: Time.now.strftime("%l:%M %P")
|
|
20
|
-
}
|
|
21
|
-
)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def export
|
|
25
|
-
begin
|
|
26
|
-
File.open(path_to_results, 'w') {|outfile| outfile.write(content)}
|
|
27
|
-
rescue Exception => e
|
|
28
|
-
puts "Unable to write output: #{e} #{e.backtrace}"
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def filename
|
|
33
|
-
"index.htm"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def output_path
|
|
37
|
-
FileUtils.mkpath(self.output_directory)
|
|
38
|
-
self.output_directory
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def output_template
|
|
42
|
-
File.read(File.dirname(__FILE__) + "/templates/index.html.haml")
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
end
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
!!!
|
|
2
|
-
%html
|
|
3
|
-
%head
|
|
4
|
-
%title
|
|
5
|
-
Analyst
|
|
6
|
-
%link{href: "http://cdn.datatables.net/1.10.0/css/jquery.dataTables.css", rel: "stylesheet"}
|
|
7
|
-
%script{language: "javascript", src: "http://code.jquery.com/jquery-1.11.0.min.js", type: "text/javascript"}
|
|
8
|
-
%script{language: "javascript", src: "http://code.jquery.com/jquery-migrate-1.2.1.min.js", type: "text/javascript"}
|
|
9
|
-
%script{language: "javascript", src: "http://cdn.datatables.net/1.10.0/js/jquery.dataTables.js", type: "text/javascript"}
|
|
10
|
-
|
|
11
|
-
%style{media: "screen", type: "text/css"}
|
|
12
|
-
body { background: #593232; color: #fff; font-family: arial, sans-serif; padding: 2em; }
|
|
13
|
-
table { box-shadow: 0 5px 0 rgba(0,0,0,.8); background: #444; border-spacing: 0; border: 5px solid #000; border-radius: 25px; border-collapse: collapse; min-width: 50%; }
|
|
14
|
-
th.sorting_asc, th.sorting_desc { text-transform: uppercase !important; font-size: .8em !important; background-image: none !important; background: rgba(64, 41, 41, .5) !important;}
|
|
15
|
-
th.sorting { background-position: left !important; border-right: 1px solid #222; text-transform: uppercase !important; font-size: .8em !important}
|
|
16
|
-
tr.header th:first-child { border-radius: 6px 0 0 0; }
|
|
17
|
-
tr.header th:last-child { border-radius: 0 6px 0 0; }
|
|
18
|
-
tr.header th:only-child { border-radius: 6px 6px 0 0; }
|
|
19
|
-
tr.header { background-color: #222; }
|
|
20
|
-
tr.even { background: rgba(128, 128, 128, 0.5) !important;}
|
|
21
|
-
tr.odd { background: rgba(128, 128, 128, 0.25) !important}
|
|
22
|
-
tr.even:hover, tr.odd:hover { background: rgba(128, 128, 128, 0.75) !important;}
|
|
23
|
-
th { background: #000; text-align: left; padding: .5em; }
|
|
24
|
-
td { text-align: left; padding: .5em; padding-left: 1.25em !important;}
|
|
25
|
-
td.center { text-align: center; }
|
|
26
|
-
td.sorting_1 { background: none !important; padding-left: 1.25em !important; }
|
|
27
|
-
tfoot { background: #000; border-top: 10px solid #000; font-family: courier; margin-top: 4em; font-size: .75em; }
|
|
28
|
-
a:link, a:visited { color: #aaa }
|
|
29
|
-
div.file_meta { float: left; height: 3em; width: 30%; }
|
|
30
|
-
h1 { color:#fff; font-size: 1.25em; margin-top: .25em; }
|
|
31
|
-
h2 { color:#fff; font-size: .75em; margin-top: -1em; }
|
|
32
|
-
h3 { color:#fff; font-size: 1em; float: right; margin-top: 1em; }
|
|
33
|
-
td.sorting_1 { background: none !important; padding-left: 1.25em !important; }
|
|
34
|
-
div.dataTables_filter { margin-bottom: 2em !important; }
|
|
35
|
-
div.dataTables_filter label { color: #fff; }
|
|
36
|
-
div.dataTables_paginate { display: none !important; }
|
|
37
|
-
div.dataTables_info { display: none !important; }
|
|
38
|
-
|
|
39
|
-
%body
|
|
40
|
-
%table{class: "output-table"}
|
|
41
|
-
%thead
|
|
42
|
-
%tr.header
|
|
43
|
-
%th{colspan: 4}
|
|
44
|
-
.file_meta
|
|
45
|
-
%h1
|
|
46
|
-
Project Overview
|
|
47
|
-
%tr
|
|
48
|
-
%th
|
|
49
|
-
File
|
|
50
|
-
%th
|
|
51
|
-
Module/Class Name
|
|
52
|
-
%th
|
|
53
|
-
Complexity
|
|
54
|
-
%th
|
|
55
|
-
Details
|
|
56
|
-
%tbody
|
|
57
|
-
- file_summary.each do |summary|
|
|
58
|
-
%tr
|
|
59
|
-
%td
|
|
60
|
-
%a{href: "#{summary[:path_to_file]}.htm"}
|
|
61
|
-
= summary[:path_to_file]
|
|
62
|
-
%td
|
|
63
|
-
- if summary[:class_name].size > 25
|
|
64
|
-
= "..."
|
|
65
|
-
= summary[:class_name][-24..-1]
|
|
66
|
-
- else
|
|
67
|
-
= summary[:class_name]
|
|
68
|
-
%td
|
|
69
|
-
= summary[:complexity]
|
|
70
|
-
%td
|
|
71
|
-
%a{href: "#{summary[:path_to_file]}.htm"}
|
|
72
|
-
View Details
|
|
73
|
-
%tfoot
|
|
74
|
-
%tr
|
|
75
|
-
%td.center{colspan: 4}
|
|
76
|
-
%em
|
|
77
|
-
Analyzed on
|
|
78
|
-
= date
|
|
79
|
-
at
|
|
80
|
-
= time
|
|
81
|
-
by
|
|
82
|
-
%a{href: "https://gitlab.com/coraline/Analyst", target: "_new"}
|
|
83
|
-
Analyst
|
|
84
|
-
:javascript
|
|
85
|
-
$(document).ready(function(){
|
|
86
|
-
$('.output-table').dataTable({
|
|
87
|
-
bLengthChange: false,
|
|
88
|
-
iDisplayLength: 25000,
|
|
89
|
-
"order": [[2, "desc"]]
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
!!!
|
|
2
|
-
%html
|
|
3
|
-
%head
|
|
4
|
-
%title
|
|
5
|
-
Analyst:
|
|
6
|
-
= class_name
|
|
7
|
-
%link{href: "http://cdn.datatables.net/1.10.0/css/jquery.dataTables.css", rel: "stylesheet"}
|
|
8
|
-
%script{language: "javascript", src: "http://code.jquery.com/jquery-1.11.0.min.js", type: "text/javascript"}
|
|
9
|
-
%script{language: "javascript", src: "http://code.jquery.com/jquery-migrate-1.2.1.min.js", type: "text/javascript"}
|
|
10
|
-
%script{language: "javascript", src: "http://cdn.datatables.net/1.10.0/js/jquery.dataTables.js", type: "text/javascript"}
|
|
11
|
-
%script{language: "javascript", src: "http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.0/highlight.min.js", type: "text/javascript"}
|
|
12
|
-
:css
|
|
13
|
-
#{Rouge::Theme.find('thankful_eyes').render(scope: '.highlight')}
|
|
14
|
-
body { background: #593232; color: #fff; font-family: arial, sans-serif; padding: 2em; }
|
|
15
|
-
div.column { float: left; width: 45%; margin-left: 4%; }
|
|
16
|
-
div.file_listing { padding: .1em; border-radius: 5px; background: #000; width: 100%; border: 1px solid #000;}
|
|
17
|
-
div.file_meta { float: left; height: 3em; width: 30%; }
|
|
18
|
-
h1 { color:#fff; font-size: 1.25em; margin-top: .25em; }
|
|
19
|
-
h2 { color:#fff; font-size: .75em; margin-top: -1em; }
|
|
20
|
-
h3 { color:#fff; font-size: 1.1em;margin-top: 1em; }
|
|
21
|
-
h3.highlighted { background: rgba(170, 161, 57, .6); border-radius: 100px; padding: .25em; padding-left: 1em; color: #000;}
|
|
22
|
-
h3.highlighted-method { background: rgba(153, 51, 80, .6); border-radius: 100px; padding-left: 1em; }
|
|
23
|
-
li { margin-bottom: 1em;}
|
|
24
|
-
pre { line-height: 1.75em;}
|
|
25
|
-
pre.lineno { margin-top: -1.4em !important;}
|
|
26
|
-
span.highlighted { padding-left: 1em; display: inline-block; position: absolute; left: 0px; padding-right: 90%}
|
|
27
|
-
a:link, a:visited { color: #aaa }
|
|
28
|
-
|
|
29
|
-
.file_listing table { width: 100%; box-shadow: 0 5px 0 rgba(0,0,0,.8); border-spacing: 0; border: 5px solid #000; border-radius: 5px; border-collapse: collapse; min-width: 50%; }
|
|
30
|
-
.file_listing td { text-align: left; padding: .5em; padding-left: 1.25em !important;}
|
|
31
|
-
.file_listing td.gutter { background-color: rgb(109, 109, 109) !important; }
|
|
32
|
-
.file_listing tfoot { background: #000; border-top: 10px solid #000; font-family: courier; margin-top: 4em; font-size: .75em; }
|
|
33
|
-
.file_listing th { background: #000; text-align: left; padding: .5em; }
|
|
34
|
-
.file_listing tr.faint td { opacity: 0.5; font-style: italic; }
|
|
35
|
-
.file_listing tr.header { background-color: #222; }
|
|
36
|
-
.file_listing tr { background: rgba(0, 0, 0, 0.25) !important; border-bottom: 1px solid #000;}
|
|
37
|
-
.file_listing th { background: #000; text-align: left; padding: .5em;}
|
|
38
|
-
.file_listing td { text-align: left; padding: .5em; padding-left: 1.25em !important;}
|
|
39
|
-
.file_listing td.center { text-align: center; }
|
|
40
|
-
.file_listing td.sorting_1 { background: none !important; padding-left: 1.25em !important; }
|
|
41
|
-
.file_listing tfoot { background: #000; font-family: courier; margin-top: 4em; font-size: .75em; }
|
|
42
|
-
|
|
43
|
-
table { box-shadow: 0 5px 0 rgba(0,0,0,.8); background: #444; border-spacing: 0; border: 5px solid #000; border-radius: 25px; border-collapse: collapse; min-width: 50%; }
|
|
44
|
-
th.sorting_asc, th.sorting_desc { text-transform: uppercase !important; font-size: .8em !important; background-image: none !important; background: rgba(64, 41, 41, .5) !important;}
|
|
45
|
-
th.sorting { background-position: left !important; border-right: 1px solid #222; text-transform: uppercase !important; font-size: .8em !important}
|
|
46
|
-
tr.header th:first-child { border-radius: 6px 0 0 0; }
|
|
47
|
-
tr.header th:last-child { border-radius: 0 6px 0 0; }
|
|
48
|
-
tr.header th:only-child { border-radius: 6px 6px 0 0; }
|
|
49
|
-
tfoot tr { border-radius: 6px 6px 6px 6px; }
|
|
50
|
-
tr.header { background-color: #222; }
|
|
51
|
-
tr.even { background: rgba(128, 128, 128, 0.5) !important;}
|
|
52
|
-
tr.odd { background: rgba(128, 128, 128, 0.25) !important}
|
|
53
|
-
tr.even:hover, tr.odd:hover { background: rgba(128, 128, 128, 0.75) !important;}
|
|
54
|
-
th { background: #000; text-align: left; padding: .5em;}
|
|
55
|
-
td { text-align: left; padding: .5em; padding-left: 1.25em !important;}
|
|
56
|
-
td.center { text-align: center; }
|
|
57
|
-
td.sorting_1 { background: none !important; padding-left: 1.25em !important; }
|
|
58
|
-
tfoot { background: #000; font-family: courier; margin-top: 4em; font-size: .75em; }
|
|
59
|
-
|
|
60
|
-
h1 { color:#fff; font-size: 1.25em; margin-top: .25em; }
|
|
61
|
-
h2 { color:#fff; font-size: .75em; margin-top: -1em; }
|
|
62
|
-
h3 { color:#fff; font-size: 1em; float: right; margin-top: 1em; }
|
|
63
|
-
|
|
64
|
-
div.dataTables_filter { display: none !important; }
|
|
65
|
-
div.dataTables_paginate { display: none !important; }
|
|
66
|
-
div.dataTables_info { display: none !important; }
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
%body
|
|
70
|
-
.container
|
|
71
|
-
%table{class: "output-table"}
|
|
72
|
-
%thead
|
|
73
|
-
%tr.header
|
|
74
|
-
%th{colspan: 3}
|
|
75
|
-
.file_meta
|
|
76
|
-
%h1
|
|
77
|
-
= class_name
|
|
78
|
-
%h2
|
|
79
|
-
= path_to_file
|
|
80
|
-
.file_meta_right
|
|
81
|
-
%h3
|
|
82
|
-
= "Overall Complexity: #{complexity}"
|
|
83
|
-
%tr
|
|
84
|
-
= header
|
|
85
|
-
%tbody
|
|
86
|
-
= rows
|
|
87
|
-
%tfoot
|
|
88
|
-
%tr
|
|
89
|
-
%td.center{colspan: 3}
|
|
90
|
-
%em
|
|
91
|
-
Analyzed on
|
|
92
|
-
= date
|
|
93
|
-
at
|
|
94
|
-
= time
|
|
95
|
-
by
|
|
96
|
-
%a{href: "https://gitlab.com/coraline/Analyst", target: "_new"}
|
|
97
|
-
Analyst
|
|
98
|
-
%br
|
|
99
|
-
%input{onclick: "history.back(-1)", type: "button", value: "Back"}
|
|
100
|
-
|
|
101
|
-
%br
|
|
102
|
-
|
|
103
|
-
.file_listing
|
|
104
|
-
= source_lines
|
|
105
|
-
|
|
106
|
-
:javascript
|
|
107
|
-
$(document).ready(function(){
|
|
108
|
-
$('.output-table').dataTable({
|
|
109
|
-
bLengthChange: false,
|
|
110
|
-
iDisplayLength: 25000,
|
|
111
|
-
"order": [[2, "desc"]]
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
module Formatters
|
|
2
|
-
|
|
3
|
-
require 'terminal-table'
|
|
4
|
-
require 'rainbow/ext/string'
|
|
5
|
-
|
|
6
|
-
class Text
|
|
7
|
-
|
|
8
|
-
include Formatters::Base
|
|
9
|
-
|
|
10
|
-
def self.has_index?
|
|
11
|
-
false
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def self.writes_to_file_system?
|
|
15
|
-
false
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def color_for(row)
|
|
19
|
-
return :green if row.complexity == 0
|
|
20
|
-
return :yellow if row.complexity <= file.average_complexity
|
|
21
|
-
return :red if row.complexity > file.average_complexity
|
|
22
|
-
return :white
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def header
|
|
26
|
-
["Class/Module", "Method", "Complexity"]
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def export
|
|
30
|
-
return if rows.empty?
|
|
31
|
-
table = Terminal::Table.new(
|
|
32
|
-
title: file.path_to_file.color(:white),
|
|
33
|
-
headings: header,
|
|
34
|
-
rows: rows,
|
|
35
|
-
style: {width: 90}
|
|
36
|
-
)
|
|
37
|
-
table.align_column(3, :right)
|
|
38
|
-
puts table
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def rows
|
|
42
|
-
file.methods.map do |method|
|
|
43
|
-
color = color_for(method)
|
|
44
|
-
[wrap("#{file.class_name}").color(color), wrap("#{method.name}".color(color)), "#{method.complexity}".color(color)]
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def wrap(string)
|
|
49
|
-
return string if string.length < 25
|
|
50
|
-
string[0..20] << "..."
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
end
|
|
56
|
-
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
class LineOfCode
|
|
2
|
-
|
|
3
|
-
include PoroPlus
|
|
4
|
-
include Ephemeral::Base
|
|
5
|
-
|
|
6
|
-
attr_accessor :line_number, :range, :content
|
|
7
|
-
|
|
8
|
-
def self.containing(locs, start_index, end_index)
|
|
9
|
-
locs.inject([]) do |a, loc|
|
|
10
|
-
a << loc if loc.in_range?(start_index) || loc.in_range?(end_index)
|
|
11
|
-
a
|
|
12
|
-
end.compact
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def in_range?(index)
|
|
16
|
-
self.range.include?(index)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
end
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
class ParsedFile
|
|
2
|
-
|
|
3
|
-
attr_accessor :lines_of_code, :source
|
|
4
|
-
attr_accessor :complexity, :path_to_file, :class_name, :path_to_results
|
|
5
|
-
|
|
6
|
-
def initialize(path_to_file: path_to_file, class_name: class_name=nil, complexity: complexity)
|
|
7
|
-
@path_to_file = path_to_file
|
|
8
|
-
@class_name = class_name
|
|
9
|
-
@lines_of_code = []
|
|
10
|
-
@complexity = complexity
|
|
11
|
-
@source = parse!
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def class_name
|
|
15
|
-
@class_name ||= analyzer.class_name
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def class_references
|
|
19
|
-
@class_references ||= analyzer.constants
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def average_complexity
|
|
23
|
-
methods.map(&:complexity).reduce(:+) / methods.count.to_f
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def complexity
|
|
27
|
-
@complexity ||= analyzer.complexity
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def methods
|
|
31
|
-
@methods ||= analyzer.methods
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def method_counts
|
|
35
|
-
referenced_methods = methods.map(&:references).flatten
|
|
36
|
-
referenced_methods.inject({}) do |hash, method|
|
|
37
|
-
hash[method] ||= 0
|
|
38
|
-
hash[method] += 1
|
|
39
|
-
hash
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def source
|
|
44
|
-
return @source if @source
|
|
45
|
-
end_pos = 0
|
|
46
|
-
self.lines_of_code = []
|
|
47
|
-
@source = File.readlines(self.path_to_file).each_with_index do |line, index|
|
|
48
|
-
start_pos = end_pos + 1
|
|
49
|
-
end_pos += line.size
|
|
50
|
-
self.lines_of_code << LineOfCode.new(line_number: index + 1, range: (start_pos..end_pos))
|
|
51
|
-
line
|
|
52
|
-
end.join
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def summary
|
|
56
|
-
{
|
|
57
|
-
path_to_file: self.path_to_file,
|
|
58
|
-
results_file: self.path_to_results,
|
|
59
|
-
source: source,
|
|
60
|
-
class_name: self.class_name,
|
|
61
|
-
complexity: complexity
|
|
62
|
-
}
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
private
|
|
66
|
-
|
|
67
|
-
def analyzer
|
|
68
|
-
@analyzer ||= Analyzer.new(content)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def content
|
|
72
|
-
@content ||= File.open(path_to_file, "r").read
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def parse!
|
|
76
|
-
end_pos = 0
|
|
77
|
-
File.readlines(self.path_to_file).each_with_index do |line, index|
|
|
78
|
-
start_pos = end_pos + 1
|
|
79
|
-
end_pos += line.size
|
|
80
|
-
self.lines_of_code << LineOfCode.new(line_number: index + 1, range: (start_pos..end_pos))
|
|
81
|
-
line
|
|
82
|
-
end.join
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
class ParsedMethod
|
|
2
|
-
|
|
3
|
-
attr_reader :name, :content, :type, :complexity, :references
|
|
4
|
-
|
|
5
|
-
def initialize(name: name, content: content, type: type, refs: refs=[], complexity: complexity)
|
|
6
|
-
@name = name
|
|
7
|
-
@content = content
|
|
8
|
-
@type = type
|
|
9
|
-
@references = refs
|
|
10
|
-
@complexity = complexity
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def complexity
|
|
14
|
-
@complexity ||= analyzer.complexity
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def name
|
|
18
|
-
return "" if self.type == :none
|
|
19
|
-
"#{prefix}#{@name}"
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def prefix
|
|
23
|
-
return "." if self.type == :class
|
|
24
|
-
return "#" if self.type == :instance
|
|
25
|
-
return "*"
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def analyzer
|
|
29
|
-
Analyzer.new(self.content)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
end
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
require 'fileutils'
|
|
2
|
-
|
|
3
|
-
module Analyst
|
|
4
|
-
|
|
5
|
-
class Parser
|
|
6
|
-
|
|
7
|
-
attr_reader :start_path, :parsed_files
|
|
8
|
-
attr_reader :threshold, :formatter
|
|
9
|
-
attr_reader :start_time
|
|
10
|
-
|
|
11
|
-
OUTPUT_DIRECTORY = "doc/Analyst"
|
|
12
|
-
|
|
13
|
-
def initialize(path, formatter, threshold=0)
|
|
14
|
-
@start_path = path
|
|
15
|
-
@formatter = formatter
|
|
16
|
-
@threshold = threshold
|
|
17
|
-
@start_time = Time.now
|
|
18
|
-
reset_output_directory
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def parsed_files
|
|
22
|
-
@parsed_files = source_files.map do |path_to_file|
|
|
23
|
-
parse_source_file(path_to_file)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def report
|
|
28
|
-
self.parsed_files.each do |file|
|
|
29
|
-
print "."
|
|
30
|
-
formatter.new(file, OUTPUT_DIRECTORY, file.source).export
|
|
31
|
-
end
|
|
32
|
-
puts
|
|
33
|
-
write_report_index
|
|
34
|
-
report_complexity
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
|
|
39
|
-
def reset_output_directory
|
|
40
|
-
begin
|
|
41
|
-
FileUtils.remove_dir(OUTPUT_DIRECTORY)
|
|
42
|
-
rescue Errno::ENOENT
|
|
43
|
-
end
|
|
44
|
-
FileUtils.mkpath(OUTPUT_DIRECTORY)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def source_files
|
|
48
|
-
if File.directory?(start_path)
|
|
49
|
-
return Dir.glob(File.join(start_path, "**", "*.rb"))
|
|
50
|
-
else
|
|
51
|
-
return [start_path]
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def parse_source_file(path_to_file, options={})
|
|
56
|
-
ParsedFile.new(path_to_file: path_to_file)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def report_complexity
|
|
60
|
-
return if self.threshold == 0
|
|
61
|
-
complexities = self.parsed_files.map(&:complexity)
|
|
62
|
-
return if complexities.max.to_i <= self.threshold
|
|
63
|
-
puts "Maximum complexity of #{complexities.max} exceeds #{options['threshold']} threshold!"
|
|
64
|
-
exit 1
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def write_report_index
|
|
68
|
-
return unless self.formatter.writes_to_file_system?
|
|
69
|
-
puts "Results written to #{OUTPUT_DIRECTORY} "
|
|
70
|
-
return unless self.formatter.has_index?
|
|
71
|
-
formatter.index_class.new(parsed_files.map(&:summary), OUTPUT_DIRECTORY).export
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
end
|