coco 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTORS +9 -0
- data/Changelog.markdown +42 -0
- data/Gemfile.lock +36 -55
- data/LICENSE +7 -0
- data/README.markdown +124 -73
- data/Rakefile +10 -37
- data/VERSION +1 -1
- data/lib/coco.rb +9 -21
- data/lib/coco/configuration.rb +59 -20
- data/lib/coco/cover.rb +1 -0
- data/lib/coco/cover/coverage_result.rb +72 -16
- data/lib/coco/cover/coverage_stat.rb +20 -8
- data/lib/coco/cover/summary.rb +50 -0
- data/lib/coco/deprecated_message.rb +31 -0
- data/lib/coco/formatter.rb +2 -2
- data/lib/coco/formatter/colored_string.rb +1 -1
- data/lib/coco/formatter/console_formatter.rb +24 -19
- data/lib/coco/formatter/context.rb +10 -39
- data/lib/coco/formatter/html_formatter.rb +7 -13
- data/lib/coco/formatter/html_index_formatter.rb +20 -16
- data/lib/coco/formatter/index_context.rb +37 -0
- data/lib/coco/formatter/index_line.rb +21 -0
- data/lib/coco/formatter/template.rb +2 -3
- data/lib/coco/helpers.rb +88 -68
- data/lib/coco/lister/source_lister.rb +23 -26
- data/lib/coco/lister/uncovered_lister.rb +6 -9
- data/lib/coco/project.rb +65 -0
- data/lib/coco/theme.rb +15 -0
- data/lib/coco/writer/file_writer.rb +5 -5
- data/lib/coco/writer/html_directory.rb +16 -8
- data/lib/coco/writer/html_files_writer.rb +9 -6
- data/lib/coco/writer/html_index_writer.rb +6 -3
- data/template/css/dark.css +178 -0
- data/template/css/{coco.css → light.css} +22 -9
- data/template/file.erb +3 -3
- data/template/index.erb +35 -33
- data/template/js/coco.js +18 -0
- metadata +34 -58
- data/COPYING +0 -674
- data/lib/coco/formatter/formatter.rb +0 -23
- data/template/img/coconut16.png +0 -0
- data/template/img/licenses +0 -19
@@ -2,16 +2,12 @@ module Coco
|
|
2
2
|
|
3
3
|
# I retrieve the .rb files from a list of directories.
|
4
4
|
class SourceLister
|
5
|
-
|
5
|
+
|
6
6
|
# config - Hash.
|
7
7
|
def initialize(config)
|
8
|
-
@exclude_files = config[:
|
9
|
-
dirs = config[:
|
10
|
-
|
11
|
-
@folders = [dirs]
|
12
|
-
else
|
13
|
-
@folders = dirs
|
14
|
-
end
|
8
|
+
@exclude_files = config[:exclude]
|
9
|
+
dirs = config[:include]
|
10
|
+
@folders = [*dirs]
|
15
11
|
@folders.each do |folder|
|
16
12
|
unless File.directory?(folder)
|
17
13
|
raise ArgumentError, "Not a folder: #{folder}"
|
@@ -19,41 +15,42 @@ module Coco
|
|
19
15
|
end
|
20
16
|
@list = []
|
21
17
|
end
|
22
|
-
|
18
|
+
|
23
19
|
# Returns Array of String, that is a list of all `.rb` files from
|
24
20
|
# the directories found in configuration.
|
25
21
|
def list
|
26
22
|
look_for_sources
|
27
|
-
@list.map! {|file| File.expand_path(file) }
|
28
|
-
exclude_files_user_dont_want
|
23
|
+
@list.map! { |file| File.expand_path(file) }
|
24
|
+
exclude_files_user_dont_want if @exclude_files
|
29
25
|
@list
|
30
26
|
end
|
31
|
-
|
27
|
+
|
32
28
|
private
|
33
|
-
|
29
|
+
|
34
30
|
def look_for_sources
|
35
|
-
@folders.each
|
31
|
+
@folders.each do |folder|
|
32
|
+
@list += Helpers.rb_files_from folder
|
33
|
+
end
|
36
34
|
end
|
37
|
-
|
35
|
+
|
38
36
|
def exclude_files_user_dont_want
|
39
|
-
return if @exclude_files.nil?
|
40
|
-
|
41
37
|
@exclude_files.each do |filename|
|
42
|
-
|
43
|
-
if File.file?(full_path)
|
44
|
-
@list.delete full_path
|
45
|
-
elsif File.directory?(full_path)
|
46
|
-
exclude_all_from_dir full_path
|
47
|
-
end
|
38
|
+
exclude_path(File.expand_path(filename))
|
48
39
|
end
|
49
40
|
end
|
50
|
-
|
41
|
+
|
42
|
+
def exclude_path(full_path)
|
43
|
+
if File.file?(full_path)
|
44
|
+
@list.delete full_path
|
45
|
+
elsif File.directory?(full_path)
|
46
|
+
exclude_all_from_dir full_path
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
51
50
|
def exclude_all_from_dir(full_path)
|
52
51
|
Helpers.rb_files_from(full_path).each do |file|
|
53
52
|
@list.delete File.expand_path(file)
|
54
53
|
end
|
55
54
|
end
|
56
|
-
|
57
55
|
end
|
58
|
-
|
59
56
|
end
|
@@ -1,24 +1,21 @@
|
|
1
1
|
module Coco
|
2
2
|
|
3
3
|
# I retrieve the list of uncovered (0%) .rb files.
|
4
|
+
#
|
4
5
|
class UncoveredLister
|
5
|
-
|
6
|
+
|
6
7
|
# sources - Array of String list of filenames.
|
7
8
|
# covered - Hash raw coverage from the domain.
|
9
|
+
#
|
8
10
|
def initialize(sources, covered)
|
9
11
|
@source_files = Helpers.expand(sources)
|
10
12
|
@covered_files = Helpers.expand(covered.keys)
|
11
13
|
end
|
12
|
-
|
14
|
+
|
13
15
|
# Returns Array of String list of uncovered filenames.
|
16
|
+
#
|
14
17
|
def list
|
15
|
-
|
16
|
-
@source_files.each do |elem|
|
17
|
-
list << elem unless @covered_files.include?(elem)
|
18
|
-
end
|
19
|
-
list
|
18
|
+
@source_files.select { |elem| !@covered_files.include?(elem) }
|
20
19
|
end
|
21
|
-
|
22
20
|
end
|
23
|
-
|
24
21
|
end
|
data/lib/coco/project.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
module Coco
|
2
|
+
|
3
|
+
# A project reports statistics about the code coverage.
|
4
|
+
#
|
5
|
+
class Project
|
6
|
+
|
7
|
+
# raw_result - The hash obtain by the call to `Coverage.result`.
|
8
|
+
# out - The output where results will be displayed, by
|
9
|
+
# default this is stdout.
|
10
|
+
#
|
11
|
+
def self.run(raw_result, out = STDOUT)
|
12
|
+
new(raw_result, out).run
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(raw_result, out)
|
16
|
+
@raw_result = raw_result
|
17
|
+
@out = out
|
18
|
+
@config = Configuration.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
return unless @config.run_this_time?
|
23
|
+
|
24
|
+
report_on_console
|
25
|
+
report_in_html
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def report_on_console
|
31
|
+
formatter = ConsoleFormatter.new(uncovered, @config[:threshold],
|
32
|
+
result, @config)
|
33
|
+
@out.puts formatter.format
|
34
|
+
@out.puts formatter.link if @config[:show_link_in_terminal]
|
35
|
+
end
|
36
|
+
|
37
|
+
def report_in_html
|
38
|
+
report_code_files
|
39
|
+
report_index
|
40
|
+
end
|
41
|
+
|
42
|
+
def report_code_files
|
43
|
+
files = HtmlFormatter.new(result.coverable_files).format
|
44
|
+
HtmlFilesWriter.new(files, @config[:theme]).write
|
45
|
+
end
|
46
|
+
|
47
|
+
def report_index
|
48
|
+
index = HtmlIndexFormatter.new(uncovered, result,
|
49
|
+
@config[:threshold]).format
|
50
|
+
HtmlIndexWriter.new(index).write
|
51
|
+
end
|
52
|
+
|
53
|
+
def result
|
54
|
+
@result ||= CoverageResult.new(@config, @raw_result)
|
55
|
+
end
|
56
|
+
|
57
|
+
def uncovered
|
58
|
+
@uncovered ||= UncoveredLister.new(sources, result.coverable_files).list
|
59
|
+
end
|
60
|
+
|
61
|
+
def sources
|
62
|
+
SourceLister.new(@config).list
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/coco/theme.rb
ADDED
@@ -1,8 +1,8 @@
|
|
1
1
|
module Coco
|
2
|
-
|
2
|
+
|
3
3
|
# Public: I write a single file.
|
4
|
+
#
|
4
5
|
module FileWriter
|
5
|
-
extend self
|
6
6
|
|
7
7
|
# Public: Write a file.
|
8
8
|
#
|
@@ -10,9 +10,9 @@ module Coco
|
|
10
10
|
# content - String content to put in the file.
|
11
11
|
#
|
12
12
|
# Returns nothing.
|
13
|
-
|
14
|
-
|
13
|
+
#
|
14
|
+
def self.write(filename, content)
|
15
|
+
File.open(filename, 'w') { |file| file.write(content) }
|
15
16
|
end
|
16
17
|
end
|
17
|
-
|
18
18
|
end
|
@@ -1,13 +1,17 @@
|
|
1
1
|
module Coco
|
2
2
|
|
3
3
|
# Public: I prepare the coverage/ directory for html files.
|
4
|
+
#
|
4
5
|
class HtmlDirectory
|
5
|
-
COVERAGE_DIR = 'coverage'
|
6
|
+
COVERAGE_DIR = 'coverage'.freeze
|
6
7
|
|
7
8
|
# Public: Initialize a new HtmlDirectory object.
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
#
|
10
|
+
# theme - The String name of the theme. There is 2 builtin themes :
|
11
|
+
# light & dark. The default one is light.
|
12
|
+
#
|
13
|
+
def initialize(theme = 'light')
|
14
|
+
@theme = Theme.new(theme)
|
11
15
|
img = File.join(Coco::ROOT, 'template/img')
|
12
16
|
@img_files = Dir.glob(img + '/*')
|
13
17
|
end
|
@@ -32,10 +36,10 @@ module Coco
|
|
32
36
|
#
|
33
37
|
# Returns nothing.
|
34
38
|
def setup
|
35
|
-
FileUtils.makedirs(css_dir)
|
36
|
-
FileUtils.
|
37
|
-
FileUtils.cp(@css_files, css_dir)
|
39
|
+
FileUtils.makedirs([css_dir, image_dir, js_dir])
|
40
|
+
FileUtils.cp(@theme.filename, File.join(css_dir, 'coco.css'))
|
38
41
|
FileUtils.cp(@img_files, image_dir)
|
42
|
+
FileUtils.cp(File.join(Coco::ROOT, 'template/js/coco.js'), js_dir)
|
39
43
|
end
|
40
44
|
|
41
45
|
# Public: I list the html files from the directory where the HTML
|
@@ -44,7 +48,7 @@ module Coco
|
|
44
48
|
# Returns nothing.
|
45
49
|
def list
|
46
50
|
files = Dir.glob("#{coverage_dir}/*.html")
|
47
|
-
files.map {|file| File.basename(file) }
|
51
|
+
files.map { |file| File.basename(file) }
|
48
52
|
end
|
49
53
|
|
50
54
|
private
|
@@ -56,5 +60,9 @@ module Coco
|
|
56
60
|
def image_dir
|
57
61
|
"#{COVERAGE_DIR}/img"
|
58
62
|
end
|
63
|
+
|
64
|
+
def js_dir
|
65
|
+
"#{COVERAGE_DIR}/js"
|
66
|
+
end
|
59
67
|
end
|
60
68
|
end
|
@@ -6,20 +6,23 @@ module Coco
|
|
6
6
|
# Public: Initialize a new HtmlFilesWriter.
|
7
7
|
#
|
8
8
|
# html_files - Hash, key is filename, value is html content.
|
9
|
-
|
9
|
+
# theme - The String name of the theme. Default is light.
|
10
|
+
#
|
11
|
+
def initialize(html_files, theme = 'light')
|
10
12
|
@html_files = html_files
|
11
|
-
@html_dir = HtmlDirectory.new
|
13
|
+
@html_dir = HtmlDirectory.new(theme)
|
12
14
|
end
|
13
15
|
|
14
16
|
# Public: Write HTML files in the right place.
|
15
17
|
#
|
16
18
|
# Returns nothing.
|
19
|
+
#
|
17
20
|
def write
|
18
21
|
@html_dir.clean
|
19
|
-
if @html_files.
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
return if @html_files.empty?
|
23
|
+
|
24
|
+
@html_dir.setup
|
25
|
+
write_each_file
|
23
26
|
end
|
24
27
|
|
25
28
|
private
|
@@ -1,19 +1,22 @@
|
|
1
1
|
module Coco
|
2
|
-
|
2
|
+
|
3
3
|
# Public: I write the index.html
|
4
|
+
#
|
4
5
|
class HtmlIndexWriter
|
5
|
-
|
6
|
+
|
6
7
|
# Public: Initialize a new HtmlIndexWriter object.
|
7
8
|
#
|
8
9
|
# index - A String HTML document.
|
10
|
+
#
|
9
11
|
def initialize(index)
|
10
12
|
@index = index
|
11
13
|
@dir = HtmlDirectory.new.coverage_dir
|
12
14
|
end
|
13
|
-
|
15
|
+
|
14
16
|
# Public: Write the index file in the right place.
|
15
17
|
#
|
16
18
|
# Returns nothing.
|
19
|
+
#
|
17
20
|
def write
|
18
21
|
if File.exist?(@dir)
|
19
22
|
FileWriter.write File.join(@dir, 'index.html'), @index
|
@@ -0,0 +1,178 @@
|
|
1
|
+
@charset "UTF-8";
|
2
|
+
|
3
|
+
/*
|
4
|
+
* Dark theme for Coco.
|
5
|
+
*/
|
6
|
+
|
7
|
+
table.source {
|
8
|
+
border-collapse:collapse;
|
9
|
+
border-spacing: 0;
|
10
|
+
}
|
11
|
+
|
12
|
+
table.index tr {
|
13
|
+
height: 1.8em;
|
14
|
+
}
|
15
|
+
|
16
|
+
table.index td {
|
17
|
+
padding-left: 0.5em;
|
18
|
+
}
|
19
|
+
|
20
|
+
html {
|
21
|
+
background-color: #505050;
|
22
|
+
color: #F5F5F5;
|
23
|
+
}
|
24
|
+
|
25
|
+
body {
|
26
|
+
margin: 0;
|
27
|
+
}
|
28
|
+
|
29
|
+
h2 {
|
30
|
+
padding: 10px;
|
31
|
+
background-color: #6A9FB5;
|
32
|
+
color: #F5F5F5;
|
33
|
+
font-size: 1.1em;
|
34
|
+
}
|
35
|
+
|
36
|
+
a {
|
37
|
+
color: #F5F5F5;
|
38
|
+
text-decoration: none;
|
39
|
+
}
|
40
|
+
|
41
|
+
p {
|
42
|
+
margin: 1em;
|
43
|
+
}
|
44
|
+
|
45
|
+
p.menu a {
|
46
|
+
font-weight: bold;
|
47
|
+
}
|
48
|
+
|
49
|
+
p.date {
|
50
|
+
font-size: 80%;
|
51
|
+
}
|
52
|
+
|
53
|
+
table {
|
54
|
+
width: 100%;
|
55
|
+
}
|
56
|
+
|
57
|
+
table td {
|
58
|
+
border-width: 0;
|
59
|
+
}
|
60
|
+
|
61
|
+
table.source td {
|
62
|
+
padding-top: 0;
|
63
|
+
padding-bottom: 0;
|
64
|
+
padding-left: 0;
|
65
|
+
}
|
66
|
+
|
67
|
+
thead {
|
68
|
+
font-weight: bold;
|
69
|
+
background-color: #404040;
|
70
|
+
text-align: center;
|
71
|
+
}
|
72
|
+
|
73
|
+
td,
|
74
|
+
td a {
|
75
|
+
color: #B0B0B0;
|
76
|
+
}
|
77
|
+
|
78
|
+
td b,
|
79
|
+
td a b {
|
80
|
+
color: #F5F5F5;
|
81
|
+
}
|
82
|
+
|
83
|
+
tr.never {
|
84
|
+
background-color: #505050;
|
85
|
+
}
|
86
|
+
|
87
|
+
tr.hit {
|
88
|
+
background-color: #506939;
|
89
|
+
}
|
90
|
+
|
91
|
+
tr.hit:hover {
|
92
|
+
background-color: #90A959;
|
93
|
+
}
|
94
|
+
|
95
|
+
tr.miss {
|
96
|
+
background-color: #AC4142;
|
97
|
+
}
|
98
|
+
|
99
|
+
tr.miss:hover {
|
100
|
+
background-color: #E65758;
|
101
|
+
}
|
102
|
+
|
103
|
+
td.yellow, td.red, td.black, td.green {
|
104
|
+
width: 45px;
|
105
|
+
}
|
106
|
+
|
107
|
+
td.yellow {
|
108
|
+
background-color: #F4BF75;
|
109
|
+
color: #202020;
|
110
|
+
}
|
111
|
+
|
112
|
+
td.red {
|
113
|
+
background-color: #AC4142;
|
114
|
+
color: #F5F5F5;
|
115
|
+
}
|
116
|
+
|
117
|
+
td.black {
|
118
|
+
background-color: #404040;
|
119
|
+
color: #F5F5F5;
|
120
|
+
}
|
121
|
+
|
122
|
+
td.green {
|
123
|
+
background-color: #90A959;
|
124
|
+
color: #F5F5F5;
|
125
|
+
}
|
126
|
+
|
127
|
+
td.percentage {
|
128
|
+
text-align: right;
|
129
|
+
padding-right: 20px;
|
130
|
+
}
|
131
|
+
|
132
|
+
td.line-num,
|
133
|
+
td.line-hits,
|
134
|
+
td.line-source {
|
135
|
+
color: #F5F5F5;
|
136
|
+
}
|
137
|
+
|
138
|
+
td.line-num,
|
139
|
+
td.line-hits {
|
140
|
+
width: 10%;
|
141
|
+
text-align: right;
|
142
|
+
}
|
143
|
+
|
144
|
+
td.line-source {
|
145
|
+
padding-right: 0;
|
146
|
+
}
|
147
|
+
|
148
|
+
td.line-num {
|
149
|
+
padding-right: 5px;
|
150
|
+
}
|
151
|
+
|
152
|
+
td.line-hits {
|
153
|
+
padding-right: 20px;
|
154
|
+
}
|
155
|
+
|
156
|
+
th {
|
157
|
+
padding-bottom: 5px;
|
158
|
+
padding-top: 5px;
|
159
|
+
}
|
160
|
+
|
161
|
+
pre {
|
162
|
+
margin: 6px 0;
|
163
|
+
}
|
164
|
+
|
165
|
+
.summary {
|
166
|
+
font-size: 150%;
|
167
|
+
color: #F5F5F5;
|
168
|
+
}
|
169
|
+
|
170
|
+
.summary-rate, .summary-uncovered, .summary-files {
|
171
|
+
background-color: #6A9FB5;
|
172
|
+
padding: 5px 10px;
|
173
|
+
margin-right: 20px;
|
174
|
+
}
|
175
|
+
|
176
|
+
#bis {
|
177
|
+
display: none;
|
178
|
+
}
|