jscruggs-metric_fu 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.
- data/HISTORY +13 -0
- data/README +1 -1
- data/Rakefile +1 -29
- data/TODO +1 -2
- data/lib/base/base_template.rb +18 -6
- data/lib/base/configuration.rb +22 -2
- data/lib/base/generator.rb +15 -2
- data/lib/base/graph.rb +37 -0
- data/lib/generators/churn.rb +6 -1
- data/lib/generators/flay.rb +5 -0
- data/lib/generators/flog.rb +6 -0
- data/lib/generators/rcov.rb +10 -0
- data/lib/generators/reek.rb +5 -0
- data/lib/generators/roodi.rb +7 -0
- data/lib/generators/saikuro.rb +184 -187
- data/lib/graphs/flay_grapher.rb +34 -0
- data/lib/graphs/flog_grapher.rb +37 -0
- data/lib/graphs/rcov_grapher.rb +34 -0
- data/lib/graphs/reek_grapher.rb +44 -0
- data/lib/graphs/roodi_grapher.rb +34 -0
- data/lib/metric_fu.rb +4 -0
- data/lib/templates/awesome/awesome_template.rb +30 -0
- data/lib/templates/awesome/churn.html.erb +19 -0
- data/lib/templates/awesome/default.css +75 -0
- data/lib/templates/awesome/flay.html.erb +27 -0
- data/lib/templates/awesome/flog.html.erb +46 -0
- data/lib/templates/awesome/index.html.erb +28 -0
- data/lib/templates/awesome/layout.html.erb +27 -0
- data/lib/templates/awesome/rcov.html.erb +36 -0
- data/lib/templates/awesome/reek.html.erb +34 -0
- data/lib/templates/awesome/roodi.html.erb +21 -0
- data/lib/templates/awesome/saikuro.html.erb +71 -0
- data/lib/templates/awesome/stats.html.erb +41 -0
- data/lib/templates/standard/churn.html.erb +1 -0
- data/lib/templates/standard/flay.html.erb +1 -0
- data/lib/templates/standard/flog.html.erb +3 -2
- data/lib/templates/standard/rcov.html.erb +5 -4
- data/lib/templates/standard/reek.html.erb +1 -0
- data/lib/templates/standard/roodi.html.erb +1 -0
- data/lib/templates/standard/saikuro.html.erb +1 -0
- data/lib/templates/standard/stats.html.erb +1 -0
- data/spec/base/base_template_spec.rb +35 -14
- data/spec/base/configuration_spec.rb +4 -4
- data/spec/base/generator_spec.rb +23 -1
- data/spec/base/md5_tracker_spec.rb +1 -1
- data/spec/base/report_spec.rb +1 -1
- data/spec/generators/churn_spec.rb +8 -8
- data/spec/generators/flay_spec.rb +4 -1
- data/spec/generators/flog_spec.rb +10 -2
- data/spec/generators/reek_spec.rb +2 -1
- data/spec/generators/saikuro_spec.rb +22 -17
- data/spec/generators/stats_spec.rb +1 -1
- data/tasks/metric_fu.rake +8 -1
- data/vendor/_fonts/monaco.ttf +0 -0
- metadata +30 -20
- data/tasks/railroad.rake +0 -39
data/HISTORY
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
=== MetricFu 1.1.0 / 2009-6-22
|
2
|
+
|
3
|
+
* Flog, flay, reek, roodi, and rcov reports now graph progress over time. Well done Nick Quarantos and Edouard Brière.
|
4
|
+
* 'Awesome' template has been brought in so that reports look 90% less 'ghetto.' Also done by Nick Quarantos and Edouard Brière.
|
5
|
+
* Added links to TextMate (which keep getting removed. Probably by me. Sorry.) -- David Chelimsky
|
6
|
+
* Fixed a bug for scratch files which have a size of 0 -- Kevin Hall
|
7
|
+
* Changed gem dependencies from install-time in gemspec to runtime when each of the generators is loaded. This allows use of github gems (i.e. relevance-rcov instead of rcov) and also allows you to install only the gems for the metrics you plan on using. -- Alex Rothenberg
|
8
|
+
* Empty Flog file fix -- Adam Bair
|
9
|
+
* Added a simple fix for cases where Saikuro results with nested information -- Randy Souza
|
10
|
+
* Fixed rcov configuration so it ignores library files on Linux -- Diego Carrion
|
11
|
+
* Changing churn so that it still works deeper than the git root directory -- Andrew Timberlake
|
12
|
+
* Andrew Timberlake also made some nice changes to the base template which kinda of got overshadowed by the 'awesome' template. Sorry about that Andrew.
|
13
|
+
|
1
14
|
=== MetricFu 1.0.2 / 2009-5-11
|
2
15
|
|
3
16
|
* Fixing problems with Reek new line character (thanks to all who pointed this out)
|
data/README
CHANGED
@@ -1 +1 @@
|
|
1
|
-
See http://metric-fu.rubyforge.org/ for documentation, or the HISTORY file for a change log.
|
1
|
+
See http://metric-fu.rubyforge.org/ for documentation, or the HISTORY file for a change log.
|
data/Rakefile
CHANGED
@@ -12,35 +12,7 @@ Spec::Rake::SpecTask.new(:spec) do |t|
|
|
12
12
|
end
|
13
13
|
|
14
14
|
MetricFu::Configuration.run do |config|
|
15
|
-
|
16
|
-
|
17
|
-
namespace :metrics do
|
18
|
-
desc "Generate all reports"
|
19
|
-
task :all do
|
20
|
-
MetricFu.metrics.each {|metric| MetricFu.report.add(metric) }
|
21
|
-
MetricFu.report.save_output(MetricFu.report.to_yaml,
|
22
|
-
MetricFu.base_directory,
|
23
|
-
'report.yml')
|
24
|
-
MetricFu.report.save_templatized_report
|
25
|
-
if MetricFu.report.open_in_browser?
|
26
|
-
MetricFu.report.show_in_browser(MetricFu.output_directory)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
MetricFu.metrics.each do |metric|
|
31
|
-
desc "Generate report for #{metric}"
|
32
|
-
task metric do
|
33
|
-
|
34
|
-
MetricFu.report.add(metric)
|
35
|
-
MetricFu.report.save_output(MetricFu.report.to_yaml,
|
36
|
-
MetricFu.base_directory,
|
37
|
-
'report.yml')
|
38
|
-
MetricFu.report.save_templatized_report
|
39
|
-
if MetricFu.report.open_in_browser?
|
40
|
-
MetricFu.report.show_in_browser(MetricFu.output_directory)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
15
|
+
config.template_class = AwesomeTemplate
|
44
16
|
end
|
45
17
|
|
46
18
|
task :default => [:"metrics:all"]
|
data/TODO
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
== TODO list
|
2
2
|
|
3
3
|
* Color code flog results with scale from: http://jakescruggs.blogspot.com/2008/08/whats-good-flog-score.html
|
4
|
-
* Extract functionality from rake files and put under test
|
5
4
|
* Integrate Flog, Saikuro, and Coverage into one report so you can see methods that have high complexity and low coverage (this is a big one)
|
6
|
-
* Integrate MD5 hashing with remainder of reports
|
7
5
|
* Move HTML out of code and into templates/
|
8
6
|
* Replace #generate_report with #new on each metric class
|
9
7
|
* Make each class descend from MetricFu::CodeMetric
|
@@ -12,3 +10,4 @@
|
|
12
10
|
* Add flay specs that run flay
|
13
11
|
* Convert readme to markdown and rename to README.mkdn so github will render it
|
14
12
|
* Saikuro.rb falls over if tries to parse an empty file. Fair enough. We shouldn't feed it empty files
|
13
|
+
* Make running metric_fu on metric_fu less embarrassing
|
data/lib/base/base_template.rb
CHANGED
@@ -99,16 +99,28 @@ module MetricFu
|
|
99
99
|
#
|
100
100
|
# @return String
|
101
101
|
# An anchor link to a textmate reference or a file reference
|
102
|
-
def link_to_filename(name, line = nil)
|
103
|
-
|
102
|
+
def link_to_filename(name, line = nil, link_content = nil)
|
103
|
+
"<a href='#{file_url(name, line)}'>#{link_content(name, line, link_content)}</a>"
|
104
|
+
end
|
105
|
+
|
106
|
+
def link_content(name, line=nil, link_content=nil) # :nodoc:
|
107
|
+
if link_content
|
108
|
+
link_content
|
109
|
+
elsif line
|
110
|
+
"#{name}:#{line}"
|
111
|
+
else
|
112
|
+
name
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def file_url(name, line) # :nodoc:
|
117
|
+
filename = File.expand_path(name.gsub(/^\//, ''))
|
104
118
|
if MetricFu.configuration.platform.include?('darwin')
|
105
|
-
"
|
106
|
-
+"#{filename}&line=#{line}'>#{name}:#{line}</a>"
|
119
|
+
"txmt://open/?url=file://#{filename}" << (line ? "&line=#{line}" : "")
|
107
120
|
else
|
108
|
-
"
|
121
|
+
"file://#{filename}"
|
109
122
|
end
|
110
123
|
end
|
111
|
-
|
112
124
|
|
113
125
|
# Provides a brain dead way to cycle between two values during
|
114
126
|
# an iteration of some sort. Pass in the first_value, the second_value,
|
data/lib/base/configuration.rb
CHANGED
@@ -8,6 +8,7 @@ module MetricFu
|
|
8
8
|
AVAILABLE_METRICS = [:churn, :flog, :flay, :reek,
|
9
9
|
:roodi, :saikuro, :rcov]
|
10
10
|
|
11
|
+
AVAILABLE_GRAPHS = [:flog, :flay, :reek, :roodi, :rcov]
|
11
12
|
|
12
13
|
# The @@configuration class variable holds a global type configuration
|
13
14
|
# object for any parts of the system to use.
|
@@ -118,12 +119,14 @@ module MetricFu
|
|
118
119
|
@base_directory = ENV['CC_BUILD_ARTIFACTS'] || 'tmp/metric_fu'
|
119
120
|
@scratch_directory = File.join(@base_directory, 'scratch')
|
120
121
|
@output_directory = File.join(@base_directory, 'output')
|
122
|
+
@data_directory = File.join('tmp/metric_fu', '_data')
|
121
123
|
@metric_fu_root_directory = File.join(File.dirname(__FILE__),
|
122
124
|
'..', '..')
|
123
125
|
@template_directory = File.join(@metric_fu_root_directory,
|
124
126
|
'lib', 'templates')
|
125
|
-
@template_class =
|
127
|
+
@template_class = AwesomeTemplate
|
126
128
|
set_metrics
|
129
|
+
set_graphs
|
127
130
|
set_code_dirs
|
128
131
|
@flay = { :dirs_to_flay => @code_dirs }
|
129
132
|
@flog = { :dirs_to_flog => @code_dirs }
|
@@ -146,7 +149,20 @@ module MetricFu
|
|
146
149
|
"--no-color",
|
147
150
|
"--profile",
|
148
151
|
"--rails",
|
149
|
-
"--exclude /gems/,/Library/,spec"]}
|
152
|
+
"--exclude /gems/,/Library/,/usr/,spec"]}
|
153
|
+
|
154
|
+
@graph_theme = { :colors => %w(orange purple green white red blue pink yellow),
|
155
|
+
:marker_color => 'blue',
|
156
|
+
:background_colors => %w(white white)}
|
157
|
+
|
158
|
+
relative_font_path = [File.dirname(__FILE__), '..', '..', 'vendor', '_fonts', 'monaco.ttf']
|
159
|
+
@graph_font = File.expand_path(File.join(relative_font_path))
|
160
|
+
@graph_size = "1000x400"
|
161
|
+
@graph_title_font_size = 12
|
162
|
+
@graph_legend_box_size = 12
|
163
|
+
@graph_legend_font_size = 10
|
164
|
+
@graph_marker_font_size = 10
|
165
|
+
|
150
166
|
end
|
151
167
|
|
152
168
|
# Perform a simple check to try and guess if we're running
|
@@ -166,6 +182,10 @@ module MetricFu
|
|
166
182
|
@metrics = MetricFu::AVAILABLE_METRICS
|
167
183
|
end
|
168
184
|
end
|
185
|
+
|
186
|
+
def set_graphs
|
187
|
+
@graphs = MetricFu::AVAILABLE_GRAPHS
|
188
|
+
end
|
169
189
|
|
170
190
|
# Add the 'app' directory if we're running within rails.
|
171
191
|
def set_code_dirs
|
data/lib/base/generator.rb
CHANGED
@@ -33,8 +33,10 @@ module MetricFu
|
|
33
33
|
attr_reader :report, :template
|
34
34
|
|
35
35
|
def initialize(options={})
|
36
|
+
self.class.verify_dependencies!
|
36
37
|
create_metric_dir_if_missing
|
37
38
|
create_output_dir_if_missing
|
39
|
+
create_data_dir_if_missing
|
38
40
|
end
|
39
41
|
|
40
42
|
# Creates a new generator and returns the output of the
|
@@ -82,6 +84,12 @@ module MetricFu
|
|
82
84
|
FileUtils.mkdir_p(MetricFu.output_directory, :verbose => false)
|
83
85
|
end
|
84
86
|
end
|
87
|
+
|
88
|
+
def create_data_dir_if_missing #:nodoc:
|
89
|
+
unless File.directory?(MetricFu.data_directory)
|
90
|
+
FileUtils.mkdir_p(MetricFu.data_directory, :verbose => false)
|
91
|
+
end
|
92
|
+
end
|
85
93
|
|
86
94
|
# @return String
|
87
95
|
# The path of the metric directory this class is using.
|
@@ -119,6 +127,11 @@ module MetricFu
|
|
119
127
|
def round_to_tenths(decimal)
|
120
128
|
(decimal * 10).round / 10.0
|
121
129
|
end
|
130
|
+
|
131
|
+
# Allows subclasses to check for required gems
|
132
|
+
def self.verify_dependencies!
|
133
|
+
true
|
134
|
+
end
|
122
135
|
|
123
136
|
def emit #:nodoc:
|
124
137
|
raise <<-EOF
|
@@ -135,8 +148,8 @@ module MetricFu
|
|
135
148
|
information.
|
136
149
|
EOF
|
137
150
|
end
|
138
|
-
|
139
|
-
def
|
151
|
+
|
152
|
+
def to_graph #:nodoc:
|
140
153
|
raise <<-EOF
|
141
154
|
This method must be implemented by a concrete class descending
|
142
155
|
from Generator. See generator class documentation for more
|
data/lib/base/graph.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module MetricFu
|
2
|
+
|
3
|
+
def self.graph
|
4
|
+
@graph ||= Graph.new
|
5
|
+
end
|
6
|
+
|
7
|
+
class Graph
|
8
|
+
|
9
|
+
attr_accessor :clazz
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
self.clazz = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(graph_type)
|
16
|
+
grapher_name = graph_type.to_s.capitalize + "Grapher"
|
17
|
+
self.clazz.push MetricFu.const_get(grapher_name).new
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def generate
|
22
|
+
puts "Generating graphs"
|
23
|
+
Dir[File.join(MetricFu.data_directory, '*.yml')].sort.each do |metric_file|
|
24
|
+
puts "Generating graphs for #{metric_file}"
|
25
|
+
date = metric_file.split('/')[3].split('.')[0]
|
26
|
+
metrics = YAML::load(File.open(metric_file))
|
27
|
+
|
28
|
+
self.clazz.each do |grapher|
|
29
|
+
grapher.get_metrics(metrics, date)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
self.clazz.each do |grapher|
|
33
|
+
grapher.graph!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/generators/churn.rb
CHANGED
@@ -4,9 +4,10 @@ module MetricFu
|
|
4
4
|
|
5
5
|
class Churn < Generator
|
6
6
|
|
7
|
+
|
7
8
|
def initialize(options={})
|
8
9
|
super
|
9
|
-
if
|
10
|
+
if self.class.git?
|
10
11
|
@source_control = Git.new(MetricFu.churn[:start_date])
|
11
12
|
elsif File.exist?(".svn")
|
12
13
|
@source_control = Svn.new(MetricFu.churn[:start_date])
|
@@ -16,6 +17,10 @@ module MetricFu
|
|
16
17
|
@minimum_churn_count = MetricFu.churn[:minimum_churn_count] || 5
|
17
18
|
end
|
18
19
|
|
20
|
+
def self.git?
|
21
|
+
system("git branch")
|
22
|
+
end
|
23
|
+
|
19
24
|
def emit
|
20
25
|
@changes = parse_log_for_changes.reject {|file, change_count| change_count < @minimum_churn_count}
|
21
26
|
end
|
data/lib/generators/flay.rb
CHANGED
@@ -3,6 +3,11 @@ module MetricFu
|
|
3
3
|
|
4
4
|
class Flay < Generator
|
5
5
|
|
6
|
+
def self.verify_dependencies!
|
7
|
+
`flay --help`
|
8
|
+
raise 'sudo gem install flay # if you want the flay tasks' unless $?.success?
|
9
|
+
end
|
10
|
+
|
6
11
|
def emit
|
7
12
|
files_to_flay = MetricFu.flay[:dirs_to_flay].map{|dir| Dir[File.join(dir, "**/*.rb")] }
|
8
13
|
@output = `flay #{files_to_flay.join(" ")}`
|
data/lib/generators/flog.rb
CHANGED
@@ -3,6 +3,11 @@ module MetricFu
|
|
3
3
|
class Flog < Generator
|
4
4
|
attr_reader :pages
|
5
5
|
|
6
|
+
def self.verify_dependencies!
|
7
|
+
`flog --help`
|
8
|
+
raise 'sudo gem install flog # if you want the flog tasks' unless $?.success?
|
9
|
+
end
|
10
|
+
|
6
11
|
SCORE_FORMAT = "%0.2f"
|
7
12
|
METHOD_LINE_REGEX = /(\d+\.\d+):\s+([A-Za-z:]+#.*)/
|
8
13
|
OPERATOR_LINE_REGEX = /\s*(\d+\.\d+):\s(.*)$/
|
@@ -28,6 +33,7 @@ module MetricFu
|
|
28
33
|
|
29
34
|
def parse(text)
|
30
35
|
summary, methods_summary = text.split "\n\n"
|
36
|
+
return unless summary
|
31
37
|
score, average = summary.split("\n").map {|line| line[OPERATOR_LINE_REGEX, 1]}
|
32
38
|
return nil unless score && methods_summary
|
33
39
|
page = Flog::Page.new(score, average)
|
data/lib/generators/rcov.rb
CHANGED
@@ -5,6 +5,16 @@ module MetricFu
|
|
5
5
|
class Rcov < Generator
|
6
6
|
NEW_FILE_MARKER = ("=" * 80) + "\n"
|
7
7
|
|
8
|
+
def self.verify_dependencies!
|
9
|
+
`flay --help`
|
10
|
+
unless $?.success?
|
11
|
+
if RUBY_PLATFORM =~ /java/
|
12
|
+
raise 'running in jruby - rcov tasks not available'
|
13
|
+
else
|
14
|
+
raise 'sudo gem install rcov # if you want the rcov tasks'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
8
18
|
|
9
19
|
class Line
|
10
20
|
attr_accessor :content, :was_run
|
data/lib/generators/reek.rb
CHANGED
@@ -3,6 +3,11 @@ module MetricFu
|
|
3
3
|
class Reek < Generator
|
4
4
|
REEK_REGEX = /^(\S+) (.*) \((.*)\)$/
|
5
5
|
|
6
|
+
def self.verify_dependencies!
|
7
|
+
`reek --help`
|
8
|
+
raise 'sudo gem install reek # if you want the reek tasks' unless $?.success?
|
9
|
+
end
|
10
|
+
|
6
11
|
def emit
|
7
12
|
files_to_reek = MetricFu.reek[:dirs_to_reek].map{|dir| Dir[File.join(dir, "**/*.rb")] }
|
8
13
|
@output = `reek #{files_to_reek.join(" ")}`
|
data/lib/generators/roodi.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
module MetricFu
|
2
2
|
class Roodi < Generator
|
3
|
+
|
4
|
+
def self.verify_dependencies!
|
5
|
+
`roodi --help`
|
6
|
+
raise 'sudo gem install roodi # if you want the roodi tasks' unless $?.success?
|
7
|
+
end
|
8
|
+
|
9
|
+
|
3
10
|
def emit
|
4
11
|
files_to_analyze = MetricFu.roodi[:dirs_to_roodi].map{|dir| Dir[File.join(dir, "**/*.rb")] }
|
5
12
|
@output = `roodi #{files_to_analyze.join(" ")}`
|
data/lib/generators/saikuro.rb
CHANGED
@@ -1,211 +1,208 @@
|
|
1
1
|
module MetricFu
|
2
|
-
|
3
|
-
class Saikuro < Generator
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
options + "--#{option.join(' ')} "
|
15
|
-
end
|
16
|
-
|
17
|
-
sh %{ruby "#{saikuro}" #{options_string}} do |ok, response|
|
18
|
-
unless ok
|
19
|
-
puts "Saikuro failed with exit status: #{response.exitstatus}"
|
20
|
-
exit 1
|
2
|
+
|
3
|
+
class Saikuro < Generator
|
4
|
+
|
5
|
+
def emit
|
6
|
+
relative_path = [File.dirname(__FILE__), '..', '..',
|
7
|
+
'vendor', 'saikuro', 'saikuro.rb']
|
8
|
+
saikuro = File.expand_path(File.join(relative_path))
|
9
|
+
|
10
|
+
MetricFu.saikuro[:input_directory] = format_directories
|
11
|
+
|
12
|
+
options_string = MetricFu.saikuro.inject("") do |options, option|
|
13
|
+
options + "--#{option.join(' ')} "
|
21
14
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
dirs = "\"#{dirs}\""
|
28
|
-
MetricFu.saikuro[:input_directory] = dirs
|
29
|
-
end
|
30
|
-
|
31
|
-
def analyze
|
32
|
-
@files = []
|
33
|
-
saikuro_results.each do |path|
|
34
|
-
if Saikuro::SFile.is_valid_text_file?(path)
|
35
|
-
file = Saikuro::SFile.new(path)
|
36
|
-
if file
|
37
|
-
@files << file
|
15
|
+
|
16
|
+
sh %{ruby "#{saikuro}" #{options_string}} do |ok, response|
|
17
|
+
unless ok
|
18
|
+
puts "Saikuro failed with exit status: #{response.exitstatus}"
|
19
|
+
exit 1
|
38
20
|
end
|
39
21
|
end
|
40
22
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
23
|
+
|
24
|
+
def format_directories
|
25
|
+
dirs = MetricFu.saikuro[:input_directory].join(" | ")
|
26
|
+
"\"#{dirs}\""
|
45
27
|
end
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
28
|
+
|
29
|
+
def analyze
|
30
|
+
@files = []
|
31
|
+
saikuro_results.each do |path|
|
32
|
+
if Saikuro::SFile.is_valid_text_file?(path)
|
33
|
+
file = Saikuro::SFile.new(path)
|
34
|
+
if file
|
35
|
+
@files << file
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
@files = @files.sort_by do |file|
|
40
|
+
file.elements.
|
41
|
+
max {|a,b| a.complexity.to_i <=> b.complexity.to_i}.
|
42
|
+
complexity.to_i
|
43
|
+
end
|
44
|
+
@files.reverse!
|
45
|
+
klasses = []
|
46
|
+
@files.each {|f| klasses << f.elements}
|
47
|
+
klasses.flatten!
|
48
|
+
@classes = klasses.sort_by {|k| k.complexity.to_i}
|
49
|
+
@classes.reverse!
|
50
|
+
meths = []
|
51
|
+
@files.each {|f|
|
52
|
+
f.elements.each {|el|
|
53
|
+
el.defs.each {|defn|
|
54
|
+
defn.name = "#{el.name}##{defn.name}"
|
55
|
+
meths << defn}
|
56
|
+
}
|
58
57
|
}
|
59
|
-
|
60
|
-
|
61
|
-
@meths = meths.reverse
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
def to_h
|
66
|
-
files = @files.map do |file|
|
67
|
-
my_file = file.to_h
|
68
|
-
my_file[:filename] = file.filename
|
69
|
-
my_file
|
58
|
+
meths = meths.sort_by {|meth| meth.complexity.to_i}
|
59
|
+
@meths = meths.reverse
|
70
60
|
end
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
def saikuro_results
|
79
|
-
Dir.glob("#{metric_directory}/**/*.html")
|
80
|
-
end
|
81
|
-
|
82
|
-
private
|
83
|
-
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
|
-
class Saikuro::SFile
|
88
|
-
|
89
|
-
attr_reader :elements
|
90
|
-
|
91
|
-
def initialize(path)
|
92
|
-
@path = path
|
93
|
-
@file_handle = File.open(@path, "r")
|
94
|
-
@elements = []
|
95
|
-
get_elements
|
96
|
-
end
|
97
|
-
|
98
|
-
def self.is_valid_text_file?(path)
|
99
|
-
File.open(path, "r") do |f|
|
100
|
-
unless f.readline.match /--/
|
101
|
-
return false
|
102
|
-
else
|
103
|
-
return true
|
61
|
+
|
62
|
+
def to_h
|
63
|
+
files = @files.map do |file|
|
64
|
+
my_file = file.to_h
|
65
|
+
my_file[:filename] = file.filename
|
66
|
+
my_file
|
104
67
|
end
|
68
|
+
{:saikuro => {:files => files,
|
69
|
+
:classes => @classes.map {|c| c.to_h},
|
70
|
+
:methods => @meths.map {|m| m.to_h}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
def saikuro_results
|
76
|
+
Dir.glob("#{metric_directory}/**/*.html")
|
105
77
|
end
|
106
78
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
elsif line.match /END/
|
124
|
-
@elements << element
|
125
|
-
element = nil
|
79
|
+
|
80
|
+
class Saikuro::SFile
|
81
|
+
|
82
|
+
attr_reader :elements
|
83
|
+
|
84
|
+
def initialize(path)
|
85
|
+
@path = path
|
86
|
+
@file_handle = File.open(@path, "r")
|
87
|
+
@elements = []
|
88
|
+
get_elements
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.is_valid_text_file?(path)
|
92
|
+
File.open(path, "r") do |f|
|
93
|
+
if f.eof? || !f.readline.match(/--/)
|
94
|
+
return false
|
126
95
|
else
|
127
|
-
|
96
|
+
return true
|
128
97
|
end
|
129
98
|
end
|
130
|
-
rescue EOFError
|
131
|
-
nil
|
132
99
|
end
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
100
|
+
|
101
|
+
def filename
|
102
|
+
File.basename(@path, '_cyclo.html')
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_h
|
106
|
+
merge_classes
|
107
|
+
{:classes => @elements}
|
108
|
+
end
|
109
|
+
|
110
|
+
def get_elements
|
111
|
+
begin
|
112
|
+
while (line = @file_handle.readline) do
|
113
|
+
return [] if line.nil? || line !~ /\S/
|
114
|
+
element ||= nil
|
115
|
+
if line.match /START/
|
116
|
+
unless element.nil?
|
117
|
+
@elements << element
|
118
|
+
element = nil
|
119
|
+
end
|
120
|
+
line = @file_handle.readline
|
121
|
+
element = Saikuro::ParsingElement.new(line)
|
122
|
+
elsif line.match /END/
|
123
|
+
@elements << element unless element.nil?
|
124
|
+
element = nil
|
125
|
+
else
|
126
|
+
element << line
|
127
|
+
end
|
128
|
+
end
|
129
|
+
rescue EOFError
|
130
|
+
nil
|
147
131
|
end
|
148
|
-
|
149
|
-
new_element = {:class_name => target_class,
|
150
|
-
:complexity => complexity,
|
151
|
-
:lines => lines,
|
152
|
-
:methods => defns.flatten.map {|d| d.to_h}}
|
153
|
-
new_element[:methods] = new_element[:methods].
|
154
|
-
sort_by {|x| x[:complexity] }.
|
155
|
-
reverse
|
156
|
-
|
157
|
-
new_elements << new_element
|
158
132
|
end
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
133
|
+
|
134
|
+
|
135
|
+
def merge_classes
|
136
|
+
new_elements = []
|
137
|
+
get_class_names.each do |target_class|
|
138
|
+
elements = @elements.find_all {|el| el.name == target_class }
|
139
|
+
complexity = 0
|
140
|
+
lines = 0
|
141
|
+
defns = []
|
142
|
+
elements.each do |el|
|
143
|
+
complexity += el.complexity.to_i
|
144
|
+
lines += el.lines.to_i
|
145
|
+
defns << el.defs
|
146
|
+
end
|
147
|
+
|
148
|
+
new_element = {:class_name => target_class,
|
149
|
+
:complexity => complexity,
|
150
|
+
:lines => lines,
|
151
|
+
:methods => defns.flatten.map {|d| d.to_h}}
|
152
|
+
new_element[:methods] = new_element[:methods].
|
153
|
+
sort_by {|x| x[:complexity] }.
|
154
|
+
reverse
|
155
|
+
|
156
|
+
new_elements << new_element
|
167
157
|
end
|
158
|
+
@elements = new_elements if new_elements
|
168
159
|
end
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
attr_reader :complexity, :lines, :defs, :element_type
|
181
|
-
attr_accessor :name
|
182
|
-
|
183
|
-
def initialize(line)
|
184
|
-
@line = line
|
185
|
-
@element_type = line.match(TYPE_REGEX)[1].strip
|
186
|
-
@name = line.match(NAME_REGEX)[1].strip
|
187
|
-
@complexity = line.match(COMPLEXITY_REGEX)[1].strip
|
188
|
-
@lines = line.match(LINES_REGEX)[1].strip
|
189
|
-
@defs = []
|
190
|
-
end
|
191
|
-
|
192
|
-
def <<(line)
|
193
|
-
@defs << Saikuro::ParsingElement.new(line)
|
160
|
+
|
161
|
+
def get_class_names
|
162
|
+
class_names = []
|
163
|
+
@elements.each do |element|
|
164
|
+
unless class_names.include?(element.name)
|
165
|
+
class_names << element.name
|
166
|
+
end
|
167
|
+
end
|
168
|
+
class_names
|
169
|
+
end
|
170
|
+
|
194
171
|
end
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
172
|
+
|
173
|
+
class Saikuro::ParsingElement
|
174
|
+
TYPE_REGEX=/Type:(.*) Name/
|
175
|
+
NAME_REGEX=/Name:(.*) Complexity/
|
176
|
+
COMPLEXITY_REGEX=/Complexity:(.*) Lines/
|
177
|
+
LINES_REGEX=/Lines:(.*)/
|
178
|
+
|
179
|
+
attr_reader :complexity, :lines, :defs, :element_type
|
180
|
+
attr_accessor :name
|
181
|
+
|
182
|
+
def initialize(line)
|
183
|
+
@line = line
|
184
|
+
@element_type = line.match(TYPE_REGEX)[1].strip
|
185
|
+
@name = line.match(NAME_REGEX)[1].strip
|
186
|
+
@complexity = line.match(COMPLEXITY_REGEX)[1].strip
|
187
|
+
@lines = line.match(LINES_REGEX)[1].strip
|
188
|
+
@defs = []
|
189
|
+
end
|
190
|
+
|
191
|
+
def <<(line)
|
192
|
+
@defs << Saikuro::ParsingElement.new(line)
|
193
|
+
end
|
194
|
+
|
195
|
+
def to_h
|
196
|
+
base = {:name => @name, :complexity => @complexity.to_i, :lines => @lines.to_i}
|
197
|
+
unless @defs.empty?
|
198
|
+
defs = @defs.map do |my_def|
|
199
|
+
my_def = my_def.to_h
|
200
|
+
my_def.delete(:defs)
|
201
|
+
my_def
|
202
|
+
end
|
203
|
+
base[:defs] = defs
|
203
204
|
end
|
204
|
-
base
|
205
|
+
return base
|
205
206
|
end
|
206
|
-
return base
|
207
207
|
end
|
208
208
|
end
|
209
|
-
|
210
|
-
|
211
|
-
end
|