coco 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +674 -0
- data/NEWS +34 -0
- data/README.rdoc +48 -0
- data/Rakefile +32 -0
- data/TODO +3 -0
- data/VERSION +1 -0
- data/lib/coco.rb +33 -0
- data/lib/coco/configuration.rb +35 -0
- data/lib/coco/cover.rb +4 -0
- data/lib/coco/cover/coverage_result.rb +48 -0
- data/lib/coco/cover/coverage_stat.rb +33 -0
- data/lib/coco/formatter.rb +9 -0
- data/lib/coco/formatter/colored_string.rb +33 -0
- data/lib/coco/formatter/console_formatter.rb +46 -0
- data/lib/coco/formatter/context.rb +35 -0
- data/lib/coco/formatter/formatter.rb +22 -0
- data/lib/coco/formatter/html_formatter.rb +39 -0
- data/lib/coco/formatter/html_index_formatter.rb +37 -0
- data/lib/coco/formatter/template.rb +17 -0
- data/lib/coco/helpers.rb +36 -0
- data/lib/coco/lister.rb +4 -0
- data/lib/coco/lister/source_lister.rb +47 -0
- data/lib/coco/lister/uncovered_lister.rb +26 -0
- data/lib/coco/writer.rb +6 -0
- data/lib/coco/writer/file_writer.rb +14 -0
- data/lib/coco/writer/html_directory.rb +39 -0
- data/lib/coco/writer/html_files_writer.rb +32 -0
- data/lib/coco/writer/html_index_writer.rb +21 -0
- data/template/css/LICENCE +5 -0
- data/template/css/base-min.css +1 -0
- data/template/css/coco.css +96 -0
- data/template/css/ext.css +5 -0
- data/template/css/fonts-min.css +1 -0
- data/template/css/reset-min.css +1 -0
- data/template/file.erb +35 -0
- data/template/img/coconut16.png +0 -0
- data/template/img/licenses +19 -0
- data/template/index.erb +58 -0
- metadata +113 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
module Coco
|
6
|
+
|
7
|
+
# I format the index.html
|
8
|
+
# @todo document
|
9
|
+
class HtmlIndexFormatter < Formatter
|
10
|
+
|
11
|
+
def initialize raw_coverages, uncovered
|
12
|
+
super(raw_coverages, uncovered)
|
13
|
+
@context = nil
|
14
|
+
@template = Template.open File.join($COCO_PATH,'template/index.erb')
|
15
|
+
@lines = []
|
16
|
+
build_lines_for_context
|
17
|
+
end
|
18
|
+
|
19
|
+
def format
|
20
|
+
@context = IndexContext.new Helpers.index_title, @lines, @uncovered
|
21
|
+
@template.result(@context.get_binding)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def build_lines_for_context
|
27
|
+
@raw_coverages.each do |filename, coverage|
|
28
|
+
filename = File.expand_path(filename)
|
29
|
+
percentage = CoverageStat.coverage_percent(coverage)
|
30
|
+
@lines << [percentage, filename, Helpers.rb2html(filename)]
|
31
|
+
end
|
32
|
+
@lines.sort!
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
module Coco
|
6
|
+
|
7
|
+
# From me, you can obtain ERB templates.
|
8
|
+
class Template
|
9
|
+
# @param [String] filename An ERB template
|
10
|
+
# @return [ERB]
|
11
|
+
def self.open filename
|
12
|
+
io = IO.readlines(filename, nil)
|
13
|
+
ERB.new(io[0], nil, '><')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/lib/coco/helpers.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Coco
|
4
|
+
|
5
|
+
# @todo The app is full of <tt>Dir.pwd</tt>. This is the root project directory
|
6
|
+
# and must be in Configuration class (or Coco module ?).
|
7
|
+
module Helpers
|
8
|
+
|
9
|
+
# Get html filename (from a ruby filename) suitable for the coverage
|
10
|
+
# directory.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# ruby = '/home/user/my_project/lib/source.rb'
|
14
|
+
# html = Helpers.rb2html(ruby)
|
15
|
+
# => '_lib_source.rb.html'
|
16
|
+
#
|
17
|
+
# @param [String] name Ruby filename
|
18
|
+
# @return [String] Html filename
|
19
|
+
def Helpers.rb2html name
|
20
|
+
name.sub(Dir.pwd, '').tr('/\\', '_') + '.html'
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [String] The title of the index.html file
|
24
|
+
def Helpers.index_title
|
25
|
+
"Coco #{File.read(File.join($COCO_PATH, 'VERSION')).strip}, code coverage for #{File.basename(Dir.pwd)}"
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [Array<String>] files List of filenames
|
29
|
+
# @return [Array<String>]
|
30
|
+
def Helpers.expand files
|
31
|
+
files.map {|file| File.expand_path file}
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/lib/coco/lister.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Coco
|
4
|
+
|
5
|
+
# I retrieve the .rb files from a list of directories.
|
6
|
+
class SourceLister
|
7
|
+
|
8
|
+
# @param [Hash] config
|
9
|
+
def initialize config
|
10
|
+
@exclude_files = config[:excludes]
|
11
|
+
dirs = config[:directories]
|
12
|
+
unless dirs.is_a? Array
|
13
|
+
@folders = [dirs]
|
14
|
+
else
|
15
|
+
@folders = dirs
|
16
|
+
end
|
17
|
+
@folders.each {|folder| raise ArgumentError unless File.directory?(folder)}
|
18
|
+
@list = []
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Array<String>] A list of all .rb files from the directories found in configuration
|
22
|
+
def list
|
23
|
+
look_for_sources
|
24
|
+
@list.map! {|file| File.expand_path(file)}
|
25
|
+
exclude_files_user_dont_want
|
26
|
+
@list
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def look_for_sources
|
32
|
+
@folders.each do |folder|
|
33
|
+
rb_files = File.join(folder, "**", "*.rb")
|
34
|
+
@list += Dir.glob(rb_files)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def exclude_files_user_dont_want
|
39
|
+
return if @exclude_files.nil?
|
40
|
+
@exclude_files.each do |filename|
|
41
|
+
@list.delete File.expand_path(filename)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Coco
|
4
|
+
|
5
|
+
# I retrieve the list of uncovered (0%) .rb files.
|
6
|
+
class UncoveredLister
|
7
|
+
|
8
|
+
# @param [Array<String>] sources List of filenames
|
9
|
+
# @param [Hash] covered Raw coverage from the domain
|
10
|
+
def initialize sources, covered
|
11
|
+
@source_files = Helpers.expand(sources)
|
12
|
+
@covered_files = Helpers.expand(covered.keys)
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Array<String>] List of uncovered filenames
|
16
|
+
def list
|
17
|
+
list = []
|
18
|
+
@source_files.each do |elem|
|
19
|
+
list << elem unless @covered_files.include?(elem)
|
20
|
+
end
|
21
|
+
list
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/lib/coco/writer.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Coco
|
4
|
+
|
5
|
+
# I prepare the coverage/ directory for html files.
|
6
|
+
class HtmlDirectory
|
7
|
+
attr_reader :coverage_dir
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@coverage_dir = 'coverage'
|
11
|
+
@css_dir = 'coverage/css'
|
12
|
+
@img_dir = 'coverage/img'
|
13
|
+
css = File.join($COCO_PATH, 'template/css')
|
14
|
+
@css_files = Dir.glob(css + '/*')
|
15
|
+
img = File.join($COCO_PATH, 'template/img')
|
16
|
+
@img_files = Dir.glob(img + '/*')
|
17
|
+
end
|
18
|
+
|
19
|
+
# Delete the coverage/ directory
|
20
|
+
def clean
|
21
|
+
FileUtils.remove_dir @coverage_dir if File.exist? @coverage_dir
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup
|
25
|
+
FileUtils.makedirs @css_dir
|
26
|
+
FileUtils.makedirs @img_dir
|
27
|
+
FileUtils.cp @css_files, @css_dir
|
28
|
+
FileUtils.cp @img_files, @img_dir
|
29
|
+
end
|
30
|
+
|
31
|
+
# I list the html files from the coverage directory
|
32
|
+
def list
|
33
|
+
files = Dir.glob("#{@coverage_dir}/*.html")
|
34
|
+
files.map {|file| File.basename(file)}
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Coco
|
4
|
+
|
5
|
+
# I populate the coverage/ directory with files, if any.
|
6
|
+
class HtmlFilesWriter
|
7
|
+
|
8
|
+
# @param [Hash] html_files Key is filename, value is html content
|
9
|
+
def initialize html_files
|
10
|
+
@html_files = html_files
|
11
|
+
@html_dir = HtmlDirectory.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def write
|
15
|
+
@html_dir.clean
|
16
|
+
if @html_files.size > 0
|
17
|
+
@html_dir.setup
|
18
|
+
write_each_file
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def write_each_file
|
25
|
+
@html_files.each do |filename, html|
|
26
|
+
FileWriter.write File.join('coverage', Helpers.rb2html(filename)), html
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Coco
|
4
|
+
|
5
|
+
# I write the index.html
|
6
|
+
class HtmlIndexWriter
|
7
|
+
|
8
|
+
def initialize index
|
9
|
+
@index = index
|
10
|
+
@dir = HtmlDirectory.new.coverage_dir
|
11
|
+
end
|
12
|
+
|
13
|
+
def write
|
14
|
+
if File.exist?(@dir)
|
15
|
+
FileWriter.write File.join(@dir, 'index.html'), @index
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
body{margin:10px;}h1{font-size:138.5%;}h2{font-size:123.1%;}h3{font-size:108%;}h1,h2,h3{margin:1em 0;}h1,h2,h3,h4,h5,h6,strong,dt{font-weight:bold;}optgroup{font-weight:normal;}abbr,acronym{border-bottom:1px dotted #000;cursor:help;}em{font-style:italic;}del{text-decoration:line-through;}blockquote,ul,ol,dl{margin:1em;}ol,ul,dl{margin-left:2em;}ol li{list-style:decimal outside;}ul li{list-style:disc outside;}dl dd{margin-left:1em;}th,td{border:1px solid #000;padding:.5em;}th{font-weight:bold;text-align:center;}caption{margin-bottom:.5em;text-align:center;}sup{vertical-align:super;}sub{vertical-align:sub;}p,fieldset,table,pre{margin-bottom:1em;}button,input[type="checkbox"],input[type="radio"],input[type="reset"],input[type="submit"]{padding:1px;}
|
@@ -0,0 +1,96 @@
|
|
1
|
+
@charset "UTF-8";
|
2
|
+
@import url("reset-min.css");
|
3
|
+
@import url("base-min.css");
|
4
|
+
@import url("font-min.css");
|
5
|
+
@import url("ext.css");
|
6
|
+
|
7
|
+
html
|
8
|
+
{
|
9
|
+
background-color: #fcfcff;
|
10
|
+
}
|
11
|
+
|
12
|
+
h2
|
13
|
+
{
|
14
|
+
padding: 10px;
|
15
|
+
background-color: #668;
|
16
|
+
color: #fcfcff;
|
17
|
+
}
|
18
|
+
|
19
|
+
a
|
20
|
+
{
|
21
|
+
color:#446;
|
22
|
+
text-decoration: none;
|
23
|
+
}
|
24
|
+
|
25
|
+
p.menu a
|
26
|
+
{
|
27
|
+
font-weight: bold;
|
28
|
+
}
|
29
|
+
|
30
|
+
p.license
|
31
|
+
{
|
32
|
+
color: #888;
|
33
|
+
margin-top: 20px;
|
34
|
+
padding-top: 5px;
|
35
|
+
border-top: 1px solid #888;
|
36
|
+
font-size: 80%;
|
37
|
+
}
|
38
|
+
|
39
|
+
p.date
|
40
|
+
{
|
41
|
+
font-size: 80%;
|
42
|
+
}
|
43
|
+
|
44
|
+
table td
|
45
|
+
{
|
46
|
+
border-width: 0;
|
47
|
+
}
|
48
|
+
|
49
|
+
table.source td
|
50
|
+
{
|
51
|
+
padding: 0;
|
52
|
+
}
|
53
|
+
|
54
|
+
tr.never
|
55
|
+
{
|
56
|
+
background-color: #eee;
|
57
|
+
}
|
58
|
+
|
59
|
+
tr.hit
|
60
|
+
{
|
61
|
+
background-color: #efe;
|
62
|
+
}
|
63
|
+
|
64
|
+
tr.miss
|
65
|
+
{
|
66
|
+
background-color: #fbb;
|
67
|
+
}
|
68
|
+
|
69
|
+
td.yellow
|
70
|
+
{
|
71
|
+
background-color: #fffead;
|
72
|
+
}
|
73
|
+
|
74
|
+
td.orange
|
75
|
+
{
|
76
|
+
background-color: #ffcd84;
|
77
|
+
}
|
78
|
+
|
79
|
+
td.pink
|
80
|
+
{
|
81
|
+
background-color: #ffcd84;
|
82
|
+
}
|
83
|
+
|
84
|
+
td.red
|
85
|
+
{
|
86
|
+
background-color: #ff4747;
|
87
|
+
color: #fff;
|
88
|
+
font-weight: bold;
|
89
|
+
}
|
90
|
+
|
91
|
+
td.black
|
92
|
+
{
|
93
|
+
background-color: #002;
|
94
|
+
color: #fff;
|
95
|
+
font-weight: bold;
|
96
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea,button{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}
|
@@ -0,0 +1 @@
|
|
1
|
+
html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}
|
data/template/file.erb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<meta charset='utf-8'>
|
4
|
+
<title><%= @filename %></title>
|
5
|
+
<link rel="stylesheet" href="css/coco.css" type="text/css" />
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<p class="menu">
|
9
|
+
<a href="index.html">Index</a> <img src="img/coconut16.png" width="16" height="16" />
|
10
|
+
<a href="https://github.com/lkdjiin/coco/wiki">Wiki</a> <img src="img/coconut16.png" width="16" height="16" />
|
11
|
+
<a href="https://github.com/lkdjiin/coco">Source</a> <img src="img/coconut16.png" width="16" height="16" />
|
12
|
+
<a href="#">Web site</a>
|
13
|
+
</p>
|
14
|
+
<h2><%= @filename %></h2>
|
15
|
+
<p class="date"><%= "#{Time.now}" %></p>
|
16
|
+
|
17
|
+
<table class="source">
|
18
|
+
|
19
|
+
<% @lines.each do |num, text, hit|%>
|
20
|
+
<% if hit.nil? %>
|
21
|
+
<tr class="never">
|
22
|
+
<% elsif hit.zero? %>
|
23
|
+
<tr class="miss">
|
24
|
+
<% elsif hit > 0 %>
|
25
|
+
<tr class="hit" %>
|
26
|
+
<% end %>
|
27
|
+
|
28
|
+
<%= "<td><pre>#{num} </pre></td><td><pre>#{text}</pre></td>" %>
|
29
|
+
|
30
|
+
</tr>
|
31
|
+
<% end%>
|
32
|
+
|
33
|
+
</table>
|
34
|
+
</body>
|
35
|
+
</html>
|