edouard-metric_fu 1.0.4.5 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/HISTORY +17 -0
  2. data/README +1 -1
  3. data/Rakefile +0 -29
  4. data/TODO +1 -2
  5. data/lib/base/base_template.rb +18 -6
  6. data/lib/base/configuration.rb +1 -1
  7. data/lib/base/generator.rb +6 -0
  8. data/lib/generators/churn.rb +6 -1
  9. data/lib/generators/flay.rb +5 -0
  10. data/lib/generators/flog.rb +14 -1
  11. data/lib/generators/rcov.rb +11 -0
  12. data/lib/generators/reek.rb +5 -0
  13. data/lib/generators/roodi.rb +7 -0
  14. data/lib/generators/saikuro.rb +164 -172
  15. data/lib/templates/awesome/churn.html.erb +1 -1
  16. data/lib/templates/awesome/default.css +9 -0
  17. data/lib/templates/awesome/flay.html.erb +1 -1
  18. data/lib/templates/awesome/flog.html.erb +1 -1
  19. data/lib/templates/awesome/rcov.html.erb +2 -2
  20. data/lib/templates/awesome/reek.html.erb +1 -1
  21. data/lib/templates/awesome/roodi.html.erb +1 -1
  22. data/lib/templates/standard/churn.html.erb +1 -0
  23. data/lib/templates/standard/flay.html.erb +1 -0
  24. data/lib/templates/standard/flog.html.erb +3 -2
  25. data/lib/templates/standard/rcov.html.erb +5 -4
  26. data/lib/templates/standard/reek.html.erb +1 -0
  27. data/lib/templates/standard/roodi.html.erb +1 -0
  28. data/lib/templates/standard/saikuro.html.erb +1 -0
  29. data/lib/templates/standard/stats.html.erb +1 -0
  30. data/spec/base/base_template_spec.rb +35 -14
  31. data/spec/base/configuration_spec.rb +1 -1
  32. data/spec/base/generator_spec.rb +23 -1
  33. data/spec/base/md5_tracker_spec.rb +1 -1
  34. data/spec/base/report_spec.rb +1 -1
  35. data/spec/generators/churn_spec.rb +8 -8
  36. data/spec/generators/flay_spec.rb +4 -1
  37. data/spec/generators/flog_spec.rb +22 -3
  38. data/spec/generators/reek_spec.rb +2 -1
  39. data/spec/generators/saikuro_spec.rb +7 -12
  40. data/spec/generators/stats_spec.rb +1 -1
  41. data/spec/graphs/flog_grapher_spec.rb +15 -0
  42. data/spec/resources/saikuro/app/controllers/sessions_controller.rb_cyclo.html +10 -0
  43. data/spec/resources/saikuro/app/controllers/users_controller.rb_cyclo.html +16 -0
  44. data/spec/resources/saikuro/index_cyclo.html +155 -0
  45. data/spec/resources/saikuro_sfiles/thing.rb_cyclo.html +10 -0
  46. data/spec/spec.opts +8 -0
  47. data/tasks/metric_fu.rake +3 -0
  48. metadata +26 -41
  49. data/tasks/railroad.rake +0 -39
data/HISTORY CHANGED
@@ -1,3 +1,20 @@
1
+ === MetricFu 1.1.1 / 2009-6-29
2
+
3
+ * Fix for empty flog files
4
+
5
+ === MetricFu 1.1.0 / 2009-6-22
6
+
7
+ * Flog, flay, reek, roodi, and rcov reports now graph progress over time. Well done Nick Quaranto and Edouard Brière.
8
+ * 'Awesome' template has been brought in so that reports look 90% less 'ghetto.' Also done by Nick Quaranto and Edouard Brière.
9
+ * Added links to TextMate (which keep getting removed. Probably by me. Sorry.) -- David Chelimsky
10
+ * Fixed a bug for scratch files which have a size of 0 -- Kevin Hall
11
+ * 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
12
+ * Empty Flog file fix -- Adam Bair
13
+ * Added a simple fix for cases where Saikuro results with nested information -- Randy Souza
14
+ * Fixed rcov configuration so it ignores library files on Linux -- Diego Carrion
15
+ * Changing churn so that it still works deeper than the git root directory -- Andrew Timberlake
16
+ * Andrew Timberlake also made some nice changes to the base template which kinda of got overshadowed by the 'awesome' template. Sorry about that Andrew.
17
+
1
18
  === MetricFu 1.0.2 / 2009-5-11
2
19
 
3
20
  * Fixing problems with Reek new line character (thanks to all who pointed this out)
data/README CHANGED
@@ -1 +1 @@
1
- Same as jscruggs/metric_fu, but with awesome templates and graphs.
1
+ See http://metric-fu.rubyforge.org/ for documentation, or the HISTORY file for a change log.
data/Rakefile CHANGED
@@ -15,33 +15,4 @@ MetricFu::Configuration.run do |config|
15
15
  config.template_class = AwesomeTemplate
16
16
  end
17
17
 
18
- namespace :metrics do
19
- desc "Generate all reports"
20
- task :all do
21
- MetricFu.metrics.each {|metric| MetricFu.report.add(metric) }
22
- MetricFu.report.save_output(MetricFu.report.to_yaml,
23
- MetricFu.data_directory,
24
- "#{Time.now.strftime("%Y%m%d")}.yml")
25
- MetricFu.report.save_templatized_report
26
- if MetricFu.report.open_in_browser?
27
- MetricFu.report.show_in_browser(MetricFu.output_directory)
28
- end
29
- end
30
-
31
- MetricFu.metrics.each do |metric|
32
- desc "Generate report for #{metric}"
33
- task metric do
34
-
35
- MetricFu.report.add(metric)
36
- MetricFu.report.save_output(MetricFu.report.to_yaml,
37
- MetricFu.data_directory,
38
- "#{Time.now.strftime("%Y%m%d")}.yml")
39
- MetricFu.report.save_templatized_report
40
- if MetricFu.report.open_in_browser?
41
- MetricFu.report.show_in_browser(MetricFu.output_directory)
42
- end
43
- end
44
- end
45
- end
46
-
47
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
@@ -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
- filename = File.expand_path(name)
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
- "<a href='txmt://open/?url=file://" \
106
- +"#{filename}&line=#{line}'>#{name}:#{line}</a>"
119
+ "txmt://open/?url=file://#{filename}" << (line ? "&line=#{line}" : "")
107
120
  else
108
- "<a href='file://#{filename}'>#{name}:#{line}</a>"
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,
@@ -119,7 +119,7 @@ module MetricFu
119
119
  @base_directory = ENV['CC_BUILD_ARTIFACTS'] || 'tmp/metric_fu'
120
120
  @scratch_directory = File.join(@base_directory, 'scratch')
121
121
  @output_directory = File.join(@base_directory, 'output')
122
- @data_directory = File.join(@base_directory, '_data')
122
+ @data_directory = File.join('tmp/metric_fu', '_data')
123
123
  @metric_fu_root_directory = File.join(File.dirname(__FILE__),
124
124
  '..', '..')
125
125
  @template_directory = File.join(@metric_fu_root_directory,
@@ -33,6 +33,7 @@ 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
38
39
  create_data_dir_if_missing
@@ -126,6 +127,11 @@ module MetricFu
126
127
  def round_to_tenths(decimal)
127
128
  (decimal * 10).round / 10.0
128
129
  end
130
+
131
+ # Allows subclasses to check for required gems
132
+ def self.verify_dependencies!
133
+ true
134
+ end
129
135
 
130
136
  def emit #:nodoc:
131
137
  raise <<-EOF
@@ -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 File.exist?(".git")
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
@@ -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(" ")}`
@@ -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)
@@ -58,10 +64,17 @@ module MetricFu
58
64
  total_flog_score = @pages.inject(0) {|total, page| total += page.score}
59
65
  sorted_pages = @pages.sort_by {|page| page.score }.reverse
60
66
  {:flog => { :total => total_flog_score,
61
- :average => round_to_tenths(total_flog_score/number_of_methods),
67
+ :average => average_score(total_flog_score, number_of_methods),
62
68
  :pages => sorted_pages.map {|page| page.to_h}}}
63
69
  end
64
70
 
71
+ private
72
+
73
+ def average_score(total_flog_score, number_of_methods)
74
+ return 0 if total_flog_score == 0
75
+ round_to_tenths(total_flog_score/number_of_methods)
76
+ end
77
+
65
78
  def flog_results
66
79
  Dir.glob("#{metric_directory}/**/*.txt")
67
80
  end
@@ -5,6 +5,17 @@ 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
18
+
8
19
  class Line
9
20
  attr_accessor :content, :was_run
10
21
 
@@ -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(" ")}`
@@ -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(" ")}`
@@ -1,216 +1,208 @@
1
1
  module MetricFu
2
2
 
3
- class Saikuro < Generator
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))
4
9
 
10
+ MetricFu.saikuro[:input_directory] = format_directories
5
11
 
6
- def emit
7
- relative_path = [File.dirname(__FILE__), '..', '..',
8
- 'vendor', 'saikuro', 'saikuro.rb']
9
- saikuro = File.expand_path(File.join(relative_path))
10
-
11
- format_directories
12
-
13
- options_string = MetricFu.saikuro.inject("") do |options, option|
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
12
+ options_string = MetricFu.saikuro.inject("") do |options, option|
13
+ options + "--#{option.join(' ')} "
21
14
  end
22
- end
23
- end
24
15
 
25
- def format_directories
26
- dirs = MetricFu.saikuro[:input_directory].join(" | ")
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
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
- @files = @files.sort_by do |file|
42
- file.elements.
43
- max {|a,b| a.complexity.to_i <=> b.complexity.to_i}.
44
- complexity.to_i
23
+
24
+ def format_directories
25
+ dirs = MetricFu.saikuro[:input_directory].join(" | ")
26
+ "\"#{dirs}\""
45
27
  end
46
- @files.reverse!
47
- klasses = []
48
- @files.each {|f| klasses << f.elements}
49
- klasses.flatten!
50
- @classes = klasses.sort_by {|k| k.complexity.to_i}
51
- @classes.reverse!
52
- meths = []
53
- @files.each {|f|
54
- f.elements.each {|el|
55
- el.defs.each {|defn|
56
- defn.name = "#{el.name}##{defn.name}"
57
- meths << defn}
58
- }
59
- }
60
- meths = meths.sort_by {|meth| meth.complexity.to_i}
61
- @meths = meths.reverse
62
28
 
63
- end
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
+ }
57
+ }
58
+ meths = meths.sort_by {|meth| meth.complexity.to_i}
59
+ @meths = meths.reverse
60
+ end
64
61
 
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
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
67
+ end
68
+ {:saikuro => {:files => files,
69
+ :classes => @classes.map {|c| c.to_h},
70
+ :methods => @meths.map {|m| m.to_h}
71
+ }
72
+ }
70
73
  end
71
- {:saikuro => {:files => files,
72
- :classes => @classes.map {|c| c.to_h},
73
- :methods => @meths.map {|m| m.to_h}
74
- }
75
- }
76
- end
77
74
 
78
- def saikuro_results
79
- Dir.glob("#{metric_directory}/**/*.html")
75
+ def saikuro_results
76
+ Dir.glob("#{metric_directory}/**/*.html")
77
+ end
80
78
  end
81
79
 
82
- private
80
+ class Saikuro::SFile
83
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
84
90
 
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
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
95
+ else
96
+ return true
97
+ end
104
98
  end
105
99
  end
106
- end
107
100
 
108
- def filename
109
- File.basename(@path, '_cyclo.html')
110
- end
101
+ def filename
102
+ File.basename(@path, '_cyclo.html')
103
+ end
111
104
 
112
- def to_h
113
- merge_classes
114
- {:classes => @elements}
115
- end
105
+ def to_h
106
+ merge_classes
107
+ {:classes => @elements}
108
+ end
116
109
 
117
- def get_elements
118
- begin
119
- while ( line = @file_handle.readline) do
120
- element ||= nil
121
- if line.match /START/
122
- unless element.nil?
123
- @elements << element
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
124
  element = nil
125
+ else
126
+ element << line
125
127
  end
126
- line = @file_handle.readline
127
- element = Saikuro::ParsingElement.new(line)
128
- elsif line.match /END/
129
- @elements << element unless element.nil?
130
- element = nil
131
- else
132
- element << line
133
128
  end
129
+ rescue EOFError
130
+ nil
134
131
  end
135
- rescue EOFError
136
- nil
137
132
  end
138
- end
139
133
 
140
134
 
141
- def merge_classes
142
- new_elements = []
143
- get_class_names.each do |target_class|
144
- elements = @elements.find_all {|el| el.name == target_class }
145
- complexity = 0
146
- lines = 0
147
- defns = []
148
- elements.each do |el|
149
- complexity += el.complexity.to_i
150
- lines += el.lines.to_i
151
- defns << el.defs
152
- end
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
153
147
 
154
- new_element = {:class_name => target_class,
155
- :complexity => complexity,
156
- :lines => lines,
157
- :methods => defns.flatten.map {|d| d.to_h}}
158
- new_element[:methods] = new_element[:methods].
159
- sort_by {|x| x[:complexity] }.
160
- reverse
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
161
155
 
162
- new_elements << new_element
156
+ new_elements << new_element
157
+ end
158
+ @elements = new_elements if new_elements
163
159
  end
164
- @elements = new_elements if new_elements
165
- end
166
160
 
167
- def get_class_names
168
- class_names = []
169
- @elements.each do |element|
170
- unless class_names.include?(element.name)
171
- class_names << element.name
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
172
167
  end
168
+ class_names
173
169
  end
174
- class_names
175
- end
176
170
 
177
- end
178
-
179
- class Saikuro::ParsingElement
180
- TYPE_REGEX=/Type:(.*) Name/
181
- NAME_REGEX=/Name:(.*) Complexity/
182
- COMPLEXITY_REGEX=/Complexity:(.*) Lines/
183
- LINES_REGEX=/Lines:(.*)/
184
-
185
- attr_reader :complexity, :lines, :defs, :element_type
186
- attr_accessor :name
187
-
188
- def initialize(line)
189
- @line = line
190
- @element_type = line.match(TYPE_REGEX)[1].strip
191
- @name = line.match(NAME_REGEX)[1].strip
192
- @complexity = line.match(COMPLEXITY_REGEX)[1].strip
193
- @lines = line.match(LINES_REGEX)[1].strip
194
- @defs = []
195
171
  end
196
172
 
197
- def <<(line)
198
- @defs << Saikuro::ParsingElement.new(line)
199
- end
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
200
190
 
201
- def to_h
202
- base = {:name => @name, :complexity => @complexity.to_i, :lines => @lines.to_i}
203
- unless @defs.empty?
204
- defs = @defs.map do |my_def|
205
- my_def = my_def.to_h
206
- my_def.delete(:defs)
207
- my_def
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
208
204
  end
209
- base[:defs] = defs
205
+ return base
210
206
  end
211
- return base
212
207
  end
213
208
  end
214
-
215
-
216
- end
@@ -10,7 +10,7 @@
10
10
  <% count = 0 %>
11
11
  <% @churn[:changes].each do |change| %>
12
12
  <tr>
13
- <td><%= change[:file_path] %></td>
13
+ <td><%= link_to_filename(change[:file_path]) %></td>
14
14
  <td><%= change[:times_changed] %></td>
15
15
  </tr>
16
16
  <% count += 1 %>
@@ -60,6 +60,15 @@ table td.score {
60
60
  .rcov_not_run {
61
61
  background-color: #d88;
62
62
  }
63
+ .rcov_run a, .rcov_not_run a {
64
+ text-decoration: none;
65
+ }
66
+ .rcov_run a {
67
+ color: #333;
68
+ }
69
+ .rcov_not_run a {
70
+ color: #000;
71
+ }
63
72
  .rcov_overflow {
64
73
  overflow: auto;
65
74
  font-size: 50%;
@@ -16,7 +16,7 @@
16
16
  <tr class='<%= cycle("light", "dark", count) %>'>
17
17
  <td>
18
18
  <% match[:matches].each do |file| %>
19
- <%= file[:name] %>:<%= file[:line] %><br />
19
+ <%= link_to_filename(file[:name], file[:line]) %><br/>
20
20
  <% end %>
21
21
  </td>
22
22
  <td><%= match[:reason] %></td>