duvet 0.0.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/.document +5 -0
- data/.gitignore +24 -0
- data/LICENSE +20 -0
- data/README.md +31 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/bin/duvet +46 -0
- data/duvet.gemspec +72 -0
- data/lib/duvet.rb +86 -0
- data/lib/duvet/cov.rb +118 -0
- data/lib/duvet/covs.rb +118 -0
- data/lib/duvet/ext.rb +28 -0
- data/lib/duvet/resources/jquery.js +154 -0
- data/lib/duvet/resources/main.js +16 -0
- data/lib/duvet/resources/plugins.js +98 -0
- data/lib/duvet/resources/rcov.sass +161 -0
- data/lib/duvet/templates/file.erb +64 -0
- data/lib/duvet/templates/index.erb +58 -0
- data/test/helper.rb +10 -0
- data/test/test_duvet.rb +5 -0
- data/test_duvet/lib/klass.rb +25 -0
- data/test_duvet/lib/run.rb +21 -0
- data/test_duvet/test/test_all.rb +59 -0
- metadata +118 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Joshua Hawxwell
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# duvet
|
2
|
+
|
3
|
+
Install with
|
4
|
+
|
5
|
+
(sudo) gem install duvet
|
6
|
+
|
7
|
+
Then add this to the __very__ top of your `test/helper.rb` (or similar)
|
8
|
+
|
9
|
+
require 'duvet
|
10
|
+
Duvet.start
|
11
|
+
|
12
|
+
You can change the defaults by passing an options hash to Duvet.start, eg
|
13
|
+
|
14
|
+
Duvet.start({:dir => 'coverage', :filter => 'app/lib'})
|
15
|
+
|
16
|
+
`:dir` is the directory to write the coverage to.
|
17
|
+
`:filter` allows you to display only coverage for files that include the string.
|
18
|
+
|
19
|
+
## Note on Patches/Pull Requests
|
20
|
+
|
21
|
+
* Fork the project.
|
22
|
+
* Make your feature addition or bug fix.
|
23
|
+
* Add tests for it. This is important so I don't break it in a
|
24
|
+
future version unintentionally.
|
25
|
+
* Commit, do not mess with rakefile, version, or history.
|
26
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
27
|
+
* Send me a pull request. Bonus points for topic branches.
|
28
|
+
|
29
|
+
## Copyright
|
30
|
+
|
31
|
+
Copyright (c) 2010 Joshua Hawxwell. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "duvet"
|
8
|
+
gem.summary = %Q{Duvet a simple code coverage tool for 1.9}
|
9
|
+
gem.description = %Q{Duvet a simple code coverage tool for 1.9}
|
10
|
+
gem.email = "m@hawx.me"
|
11
|
+
gem.homepage = "http://github.com/hawx/duvet"
|
12
|
+
gem.authors = ["Joshua Hawxwell"]
|
13
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
gem.add_development_dependency "yard", ">= 0"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
24
|
+
test.libs << 'lib' << 'test'
|
25
|
+
test.pattern = 'test/**/test_*.rb'
|
26
|
+
test.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'rcov/rcovtask'
|
31
|
+
Rcov::RcovTask.new do |test|
|
32
|
+
test.libs << 'test'
|
33
|
+
test.pattern = 'test/**/test_*.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
task :rcov do
|
38
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
task :test => :check_dependencies
|
43
|
+
|
44
|
+
task :default => :test
|
45
|
+
|
46
|
+
begin
|
47
|
+
require 'yard'
|
48
|
+
YARD::Rake::YardocTask.new
|
49
|
+
rescue LoadError
|
50
|
+
task :yardoc do
|
51
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
52
|
+
end
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/bin/duvet
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# A command line tool for coverage testing, I'm not sure if this
|
4
|
+
# will even work but it is worth a try!
|
5
|
+
#
|
6
|
+
# Example:
|
7
|
+
# duvet test/test_class.rb
|
8
|
+
#
|
9
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
10
|
+
|
11
|
+
require 'clive'
|
12
|
+
require 'duvet'
|
13
|
+
|
14
|
+
opts = {:dir => 'cov', :style => 'rcov'}
|
15
|
+
c = Clive.new do
|
16
|
+
|
17
|
+
header "Usage: duvet [options] [paths]"
|
18
|
+
|
19
|
+
flag(:css, "PATH", "Use custom css file") do |i|
|
20
|
+
opts[:css] = i
|
21
|
+
end
|
22
|
+
|
23
|
+
flag(:s, :style, "ARG", "Choose style") do |i|
|
24
|
+
opts[:style] = i
|
25
|
+
end
|
26
|
+
|
27
|
+
flag(:d, :dir, "PATH", "Directory to write coverage results") do |i|
|
28
|
+
opts[:dir] = i
|
29
|
+
end
|
30
|
+
|
31
|
+
flag(:f, :filter, "FILTER", "Use a filter to see only needed results") do |i|
|
32
|
+
opts[:filter] = i
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
# Start coverage, then require paths
|
38
|
+
def run(paths, opts)
|
39
|
+
Duvet.start(opts)
|
40
|
+
paths.each do |p|
|
41
|
+
require p
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
args = c.parse(ARGV)
|
46
|
+
run(args, opts)
|
data/duvet.gemspec
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{duvet}
|
8
|
+
s.version = "0.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Joshua Hawxwell"]
|
12
|
+
s.date = %q{2010-09-01}
|
13
|
+
s.default_executable = %q{duvet}
|
14
|
+
s.description = %q{Duvet a simple code coverage tool for 1.9}
|
15
|
+
s.email = %q{m@hawx.me}
|
16
|
+
s.executables = ["duvet"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE",
|
19
|
+
"README.md"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".gitignore",
|
24
|
+
"LICENSE",
|
25
|
+
"README.md",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"bin/duvet",
|
29
|
+
"duvet.gemspec",
|
30
|
+
"lib/duvet.rb",
|
31
|
+
"lib/duvet/cov.rb",
|
32
|
+
"lib/duvet/covs.rb",
|
33
|
+
"lib/duvet/ext.rb",
|
34
|
+
"lib/duvet/resources/jquery.js",
|
35
|
+
"lib/duvet/resources/main.js",
|
36
|
+
"lib/duvet/resources/plugins.js",
|
37
|
+
"lib/duvet/resources/rcov.sass",
|
38
|
+
"lib/duvet/templates/file.erb",
|
39
|
+
"lib/duvet/templates/index.erb",
|
40
|
+
"test/helper.rb",
|
41
|
+
"test/test_duvet.rb",
|
42
|
+
"test_duvet/lib/klass.rb",
|
43
|
+
"test_duvet/lib/run.rb",
|
44
|
+
"test_duvet/test/test_all.rb"
|
45
|
+
]
|
46
|
+
s.homepage = %q{http://github.com/hawx/duvet}
|
47
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
48
|
+
s.require_paths = ["lib"]
|
49
|
+
s.rubygems_version = %q{1.3.7}
|
50
|
+
s.summary = %q{Duvet a simple code coverage tool for 1.9}
|
51
|
+
s.test_files = [
|
52
|
+
"test/helper.rb",
|
53
|
+
"test/test_duvet.rb"
|
54
|
+
]
|
55
|
+
|
56
|
+
if s.respond_to? :specification_version then
|
57
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
58
|
+
s.specification_version = 3
|
59
|
+
|
60
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
61
|
+
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
62
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
63
|
+
else
|
64
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
65
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
66
|
+
end
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
69
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
data/lib/duvet.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
# Add this to test/helper.rb at the before __anything__ else
|
4
|
+
#
|
5
|
+
# require 'duvet'
|
6
|
+
# Duvet.start
|
7
|
+
#
|
8
|
+
require 'coverage'
|
9
|
+
require 'ostruct'
|
10
|
+
require 'erubis'
|
11
|
+
require 'pathname'
|
12
|
+
require 'sass'
|
13
|
+
|
14
|
+
require 'duvet/ext'
|
15
|
+
require 'duvet/covs'
|
16
|
+
require 'duvet/cov'
|
17
|
+
|
18
|
+
|
19
|
+
module Duvet
|
20
|
+
|
21
|
+
attr_accessor :opts
|
22
|
+
|
23
|
+
DEFAULTS = {:dir => 'cov', :style => 'rcov'}
|
24
|
+
|
25
|
+
# Start tracking
|
26
|
+
def self.start(opts={})
|
27
|
+
@opts = DEFAULTS.merge(opts)
|
28
|
+
|
29
|
+
Coverage.start
|
30
|
+
@running = true
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get result
|
34
|
+
def self.result
|
35
|
+
cov = Coverage.result if running?
|
36
|
+
if @opts[:filter]
|
37
|
+
filtered = {}
|
38
|
+
cov.each do |k, v|
|
39
|
+
if k.include?(@opts[:filter])
|
40
|
+
filtered[k] = v
|
41
|
+
end
|
42
|
+
end
|
43
|
+
cov = filtered
|
44
|
+
end
|
45
|
+
@result ||= Duvet::Covs.new(cov)
|
46
|
+
ensure
|
47
|
+
@running = false
|
48
|
+
end
|
49
|
+
|
50
|
+
# Write results
|
51
|
+
def self.write
|
52
|
+
self.result.write(@opts[:dir], @opts[:style]) if running?
|
53
|
+
end
|
54
|
+
|
55
|
+
# Proc to call when exiting
|
56
|
+
# @todo Allow user to override block used
|
57
|
+
def self.at_exit
|
58
|
+
Proc.new { self.write }
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [Boolean] whether coverage is running
|
62
|
+
def self.running?
|
63
|
+
@running
|
64
|
+
end
|
65
|
+
|
66
|
+
# Reads the current version from VERSION
|
67
|
+
#
|
68
|
+
# @return [String] current version
|
69
|
+
def self.version
|
70
|
+
File.read( File.join(File.dirname(__FILE__), '..', 'VERSION') )
|
71
|
+
end
|
72
|
+
|
73
|
+
# @return [Hash] hash to merge for templating
|
74
|
+
def self.template_hash
|
75
|
+
{
|
76
|
+
'time' => Time.now,
|
77
|
+
'version' => self.version,
|
78
|
+
'name' => 'duvet'
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
at_exit do
|
85
|
+
Duvet.at_exit.call
|
86
|
+
end
|
data/lib/duvet/cov.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
module Duvet
|
2
|
+
class Cov
|
3
|
+
attr_accessor :cov, :path
|
4
|
+
|
5
|
+
def initialize(path, cov)
|
6
|
+
if path.include?(Dir.pwd)
|
7
|
+
@path = path.to_p.relative_path_from(Pathname.pwd)
|
8
|
+
else
|
9
|
+
@path = path.to_p
|
10
|
+
end
|
11
|
+
|
12
|
+
@cov = cov
|
13
|
+
write
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Integer] number of lines in file
|
17
|
+
def lines
|
18
|
+
@cov.length
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Array] all lines which can be executed
|
22
|
+
def code_lines
|
23
|
+
@cov.reject {|i| i.nil?}
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Integer] number of lines of code that can be executed
|
27
|
+
def lines_of_code
|
28
|
+
code_lines.length
|
29
|
+
end
|
30
|
+
|
31
|
+
# Gives a fraction from 0 to 1 of how many lines of code have
|
32
|
+
# been executed. It ignores all lines that couldn't be executed
|
33
|
+
# such as comments.
|
34
|
+
#
|
35
|
+
# @return [Integer] lines of code executed as a fraction
|
36
|
+
def code_coverage
|
37
|
+
ran_lines = code_lines.reject {|i| i.zero?}.length
|
38
|
+
ran_lines.to_f / lines_of_code.to_f
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [String] #code_coverage as ??.??%
|
42
|
+
def code_coverage_percent
|
43
|
+
"%.2f%" % (code_coverage*100)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Similar to #code_coverage but counts all lines, executable
|
47
|
+
# or not.
|
48
|
+
#
|
49
|
+
# @return [Integer] lines executed as a fraction
|
50
|
+
def total_coverage
|
51
|
+
ran_lines = @cov.reject {|i| i.nil? || i.zero?}.length
|
52
|
+
ran_lines.to_f / lines.to_f
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [String] #total_coverage as ??.??%
|
56
|
+
def total_coverage_percent
|
57
|
+
"%.2f%" % (total_coverage*100)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Creates a report showing the source code.
|
61
|
+
#
|
62
|
+
# @return [String] a report showing line number, source and
|
63
|
+
# times run
|
64
|
+
def source_report
|
65
|
+
source = @path.readlines
|
66
|
+
str = ""
|
67
|
+
source.zip(@cov).each_with_index do |a, i|
|
68
|
+
line, count = a[0], a[1]
|
69
|
+
str << "#{i}| #{line.gsub("\n", "")}"
|
70
|
+
str << " #=> #{count}" if count
|
71
|
+
str << "\n"
|
72
|
+
end
|
73
|
+
str
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [String]
|
77
|
+
def report
|
78
|
+
str = "For #{@path}\n\n" << source_report << "\n"
|
79
|
+
str << "total coverage: #{total_coverage}\n"
|
80
|
+
str << "code coverage: #{code_coverage}\n"
|
81
|
+
str
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [Hash] a hash of data for templating
|
85
|
+
def data
|
86
|
+
{
|
87
|
+
"file" => {
|
88
|
+
"path" => @path,
|
89
|
+
"url" => @path.file_name + '.html',
|
90
|
+
"source" => @path.readlines,
|
91
|
+
"lines" => lines,
|
92
|
+
"lines_code" => lines_of_code
|
93
|
+
},
|
94
|
+
"coverage" => {
|
95
|
+
"code" => code_coverage_percent,
|
96
|
+
"total" => total_coverage_percent,
|
97
|
+
"lines" => @cov
|
98
|
+
}
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
# Formats the coverage for the file to be written to a html
|
103
|
+
# file, then viewed in a web browser.
|
104
|
+
#
|
105
|
+
# @return [String]
|
106
|
+
def format
|
107
|
+
template = File.read(File.join( File.dirname(__FILE__), "templates", "file.erb" ))
|
108
|
+
e = Erubis::Eruby.new(template).result(Duvet.template_hash.merge(self.data))
|
109
|
+
e
|
110
|
+
end
|
111
|
+
|
112
|
+
def write(dir='cov')
|
113
|
+
f = File.new((dir.to_p + @path.file_name).to_s + '.html', "w" )
|
114
|
+
f.write(format)
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|