rkid 0.1
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/Manifest.txt +17 -0
- data/README.txt +5 -0
- data/Rakefile +24 -0
- data/TODO +4 -0
- data/bin/rkid +23 -0
- data/db/schema.rb +34 -0
- data/lib/rkid.rb +17 -0
- data/lib/rkid/analyzer.rb +80 -0
- data/lib/rkid/models.rb +94 -0
- data/lib/rkid/rake/task.rb +16 -0
- data/rkid.db +0 -0
- data/spec/fixtures/test_class.rb +9 -0
- data/spec/rkid/analyzer_spec.rb +40 -0
- data/spec/rkid/sample.db +0 -0
- data/spec/spec_helper.rb +12 -0
- data/test.db +0 -0
- data/test.html +0 -0
- metadata +90 -0
data/Manifest.txt
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Manifest.txt
|
2
|
+
README.txt
|
3
|
+
Rakefile
|
4
|
+
TODO
|
5
|
+
bin/rkid
|
6
|
+
db/schema.rb
|
7
|
+
lib/rkid.rb
|
8
|
+
lib/rkid/analyzer.rb
|
9
|
+
lib/rkid/models.rb
|
10
|
+
lib/rkid/rake/task.rb
|
11
|
+
rkid.db
|
12
|
+
spec/fixtures/test_class.rb
|
13
|
+
spec/rkid/analyzer_spec.rb
|
14
|
+
spec/rkid/sample.db
|
15
|
+
spec/spec_helper.rb
|
16
|
+
test.db
|
17
|
+
test.html
|
data/README.txt
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
Rkid is Rcov In Database
|
2
|
+
|
3
|
+
Until there is better packaging (see the todo), customize the following line for your needs:
|
4
|
+
|
5
|
+
ruby -S bin/rkid "/opt/local/lib/ruby/gems/1.8/gems/rspec-1.1.2/bin/spec" -- "/Users/nkallen/Sites/arel/spec/active_relation/unit/predicates/binary_spec.rb"
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + "/lib")
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake'
|
5
|
+
require 'hoe'
|
6
|
+
require 'activerecord'
|
7
|
+
require 'spec/rake/spectask'
|
8
|
+
require 'rkid'
|
9
|
+
require 'rkid/rake/task'
|
10
|
+
|
11
|
+
Spec::Rake::SpecTask.new do |t|
|
12
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
13
|
+
end
|
14
|
+
|
15
|
+
Hoe.new('Rkid', Rkid::VERSION) do |p|
|
16
|
+
p.name = "rkid"
|
17
|
+
p.author = "Nick Kallen"
|
18
|
+
p.description = "Rcov in Database"
|
19
|
+
p.email = 'nick@pivotallabs.com'
|
20
|
+
p.summary = "Rcov in Database"
|
21
|
+
p.url = ""
|
22
|
+
p.extra_deps << ['rspec']
|
23
|
+
p.extra_deps << ['rcov']
|
24
|
+
end
|
data/TODO
ADDED
data/bin/rkid
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rkid'
|
3
|
+
Rkid.env = 'production'
|
4
|
+
|
5
|
+
$ORIGINAL_ARGV = ARGV.clone
|
6
|
+
if idx = ARGV.index("--")
|
7
|
+
extra_args = ARGV[idx+1..-1]
|
8
|
+
ARGV.replace(ARGV[0,idx])
|
9
|
+
else
|
10
|
+
extra_args = []
|
11
|
+
end
|
12
|
+
|
13
|
+
at_exit {
|
14
|
+
Rkid::report
|
15
|
+
}
|
16
|
+
|
17
|
+
pending_scripts = ARGV.clone
|
18
|
+
ARGV.replace extra_args
|
19
|
+
until pending_scripts.empty?
|
20
|
+
prog = pending_scripts.shift
|
21
|
+
Rkid::prepare
|
22
|
+
load prog
|
23
|
+
end
|
data/db/schema.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
create_table :klasses, :force => true do |t|
|
3
|
+
t.string :name
|
4
|
+
end
|
5
|
+
add_index :klasses, :name, :unique => true
|
6
|
+
|
7
|
+
create_table :methods, :force => true do |t|
|
8
|
+
t.string :name
|
9
|
+
t.integer :klass_id, :defsite_id
|
10
|
+
end
|
11
|
+
add_index :methods, [:klass_id, :name, :defsite_id], :unique => true
|
12
|
+
|
13
|
+
create_table :files, :force => true do |t|
|
14
|
+
t.string :name
|
15
|
+
end
|
16
|
+
add_index :files, [:name], :unique => true
|
17
|
+
|
18
|
+
create_table :callsites, :force => true do |t|
|
19
|
+
t.integer :method_id, :count
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table :frames, :force => true do |t|
|
23
|
+
t.integer :line_id, :callsite_id, :level
|
24
|
+
end
|
25
|
+
add_index :frames, [:line_id, :callsite_id, :level], :unique => true
|
26
|
+
|
27
|
+
create_table :lines, :force => true do |t|
|
28
|
+
t.integer :times_called, :method_id, :file_id, :number
|
29
|
+
t.boolean :covered
|
30
|
+
t.string :body
|
31
|
+
end
|
32
|
+
add_index :lines, [:file_id, :number], :unique => true
|
33
|
+
|
34
|
+
end
|
data/lib/rkid.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module Rkid
|
4
|
+
VERSION = '0.1'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'activesupport'
|
9
|
+
require 'activerecord'
|
10
|
+
require 'rcov'
|
11
|
+
require 'sqlite3'
|
12
|
+
require 'rbconfig'
|
13
|
+
|
14
|
+
require 'rkid/analyzer'
|
15
|
+
require 'rkid/models'
|
16
|
+
|
17
|
+
Rkid.root = File.join(File.dirname(__FILE__), '..')
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Rkid
|
2
|
+
mattr_accessor :root, :env, :callsite_analyzer, :coverage_analyzer
|
3
|
+
|
4
|
+
IGNORE_FILES = [
|
5
|
+
/\A#{Regexp.escape(Pathname.new(Config::CONFIG["libdir"]).cleanpath.to_s)}/,
|
6
|
+
/\btc_[^.]*.rb/,
|
7
|
+
/\bgems\//,
|
8
|
+
/\bvendor\//,
|
9
|
+
/\A#{Regexp.escape(__FILE__)}\z/
|
10
|
+
]
|
11
|
+
|
12
|
+
def self.analyze(&block)
|
13
|
+
prepare
|
14
|
+
yield
|
15
|
+
report
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.prepare
|
19
|
+
self.coverage_analyzer, self.callsite_analyzer = Rcov::CodeCoverageAnalyzer.new, Rcov::CallSiteAnalyzer.new
|
20
|
+
callsite_analyzer.install_hook; coverage_analyzer.install_hook
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.report
|
24
|
+
callsite_analyzer.remove_hook; coverage_analyzer.remove_hook
|
25
|
+
prepare_connection_to_database
|
26
|
+
analyze_callsite(callsite_analyzer); analyze_coverage(coverage_analyzer)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def self.prepare_connection_to_database
|
32
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :dbfile => 'rkid.db')
|
33
|
+
load ::File.join(root, 'db/schema.rb')
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.analyze_callsite(callsite_analyzer)
|
37
|
+
total = callsite_analyzer.analyzed_classes.size
|
38
|
+
callsite_analyzer.analyzed_classes.each_with_index do |klass_name, i|
|
39
|
+
puts "Processing class '#{klass_name}', #{i+1} of #{total}"
|
40
|
+
klass = nil
|
41
|
+
|
42
|
+
callsite_analyzer.methods_for_class(klass_name).each do |method_name|
|
43
|
+
defsite = callsite_analyzer.defsite(klass_method = klass_name + "#" + method_name)
|
44
|
+
next if IGNORE_FILES.any? { |pattern| defsite.file =~ pattern }
|
45
|
+
|
46
|
+
klass ||= Klass.create('name' => klass_name)
|
47
|
+
defsite_file = File.create('name' => defsite.file)
|
48
|
+
defsite_line = Line.create('file_id' => defsite_file.id, 'number' => defsite.line)
|
49
|
+
method = Method.create(
|
50
|
+
'klass_id' => klass.id,
|
51
|
+
'name' => method_name,
|
52
|
+
'defsite_id' => defsite_line.id
|
53
|
+
)
|
54
|
+
callsite_analyzer.callsites(klass_method).each do |site, count|
|
55
|
+
callsite = Callsite.create('method_id' => method.id, 'count' => count)
|
56
|
+
site.backtrace.each_with_index do |frame, i|
|
57
|
+
file_name = file_name = frame[2]
|
58
|
+
next if IGNORE_FILES.any? { |pattern| file_name =~ pattern }
|
59
|
+
|
60
|
+
file = File.create('name' => file_name)
|
61
|
+
line = Line.create('file_id' => file.id, 'number' => frame[3])
|
62
|
+
Frame.create('callsite_id' => callsite.id, 'line_id' => line.id, 'level' => i)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.analyze_coverage(coverage_analyzer)
|
70
|
+
coverage_analyzer.analyzed_files.each do |file_name|
|
71
|
+
next if IGNORE_FILES.any? { |pattern| file_name =~ pattern }
|
72
|
+
|
73
|
+
lines, marked, count = coverage_analyzer.data(file_name)
|
74
|
+
lines.each_with_index do |body, i|
|
75
|
+
file = File.create('name' => file_name)
|
76
|
+
line = Line.create('file_id' => file.id, 'number' => i, 'body' => body, 'covered' => marked[i], 'times_called' => count[i])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/rkid/models.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
module Rkid
|
2
|
+
module FastCreate
|
3
|
+
def db
|
4
|
+
ActiveRecord::Base.connection.raw_connection
|
5
|
+
end
|
6
|
+
|
7
|
+
def insert(attributes)
|
8
|
+
insert = db.prepare <<-SQL
|
9
|
+
INSERT INTO #{table_name}
|
10
|
+
(#{attributes.keys.join(', ')}) VALUES (#{attributes.keys.collect { |c| ":#{c}" }.join(', ')})
|
11
|
+
SQL
|
12
|
+
insert.execute attributes
|
13
|
+
instantiate(attributes.merge('id' => db.last_insert_row_id))
|
14
|
+
end
|
15
|
+
|
16
|
+
def create(attributes)
|
17
|
+
begin
|
18
|
+
insert(attributes)
|
19
|
+
rescue SQLite3::SQLException
|
20
|
+
update(attributes)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Klass < ::ActiveRecord::Base
|
26
|
+
extend FastCreate
|
27
|
+
|
28
|
+
has_many :methods, :class_name => 'Method', :dependent => :destroy
|
29
|
+
|
30
|
+
def self.update(attributes)
|
31
|
+
find_by_name(attributes['name'])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Method < ::ActiveRecord::Base
|
36
|
+
extend FastCreate
|
37
|
+
|
38
|
+
belongs_to :klass
|
39
|
+
has_many :callsites, :dependent => :destroy
|
40
|
+
has_many :lines, :dependent => :destroy
|
41
|
+
belongs_to :defsite, :class_name => 'Line'
|
42
|
+
|
43
|
+
def self.update(attributes)
|
44
|
+
find_by_name_and_klass_id(attributes['name'], attributes['klass_id'])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class File < ::ActiveRecord::Base
|
49
|
+
extend FastCreate
|
50
|
+
|
51
|
+
has_many :lines, :order => :number, :dependent => :destroy
|
52
|
+
|
53
|
+
def self.update(attributes)
|
54
|
+
find_by_name(attributes['name'])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Callsite < ::ActiveRecord::Base
|
59
|
+
extend FastCreate
|
60
|
+
|
61
|
+
belongs_to :method
|
62
|
+
has_many :frames, :order => :level, :dependent => :destroy
|
63
|
+
has_many :lines, :through => :frames, :dependent => :destroy
|
64
|
+
end
|
65
|
+
|
66
|
+
class Frame < ::ActiveRecord::Base
|
67
|
+
extend FastCreate
|
68
|
+
|
69
|
+
belongs_to :callsite
|
70
|
+
belongs_to :line
|
71
|
+
belongs_to :callsite
|
72
|
+
end
|
73
|
+
|
74
|
+
class Line < ::ActiveRecord::Base
|
75
|
+
extend FastCreate
|
76
|
+
|
77
|
+
belongs_to :method
|
78
|
+
belongs_to :file
|
79
|
+
|
80
|
+
def self.update(attributes)
|
81
|
+
line = find_by_number_and_file_id(attributes['number'], attributes['file_id'])
|
82
|
+
assignments = attributes.keys.collect do |key|
|
83
|
+
"#{key} = :#{key}"
|
84
|
+
end.join ', '
|
85
|
+
update = db.prepare <<-SQL
|
86
|
+
UPDATE #{table_name} SET
|
87
|
+
#{assignments}
|
88
|
+
WHERE id = :id
|
89
|
+
SQL
|
90
|
+
update.execute attributes.except('covered').merge('id' => line.id)
|
91
|
+
line
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
|
4
|
+
module Rkid
|
5
|
+
class Task < Rake::TaskLib
|
6
|
+
def initialize
|
7
|
+
desc "Run specs with rkid"
|
8
|
+
task :rkid do
|
9
|
+
rkid_script = ::File.expand_path(::File.dirname(__FILE__) + '/../../../bin/rkid')
|
10
|
+
specs = FileList['spec/**/*_spec.rb'].collect { |fn| %["#{fn}"] }.join(' ')
|
11
|
+
|
12
|
+
system %(ruby #{rkid_script} `which spec` -- #{specs})
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/rkid.db
ADDED
Binary file
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe Rkid do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
require 'spec/fixtures/test_class.rb'
|
7
|
+
Rkid.env = 'test'
|
8
|
+
Rkid.analyze { TestedClass.new.tested_method }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '::analyze' do
|
12
|
+
before do
|
13
|
+
@file = Rkid::File.find_by_name("./spec/fixtures/test_class.rb")
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'records classes and methods' do
|
17
|
+
methods = Rkid::Klass.find_by_name('TestedClass').methods
|
18
|
+
methods.find_by_name('tested_method').should_not be_nil
|
19
|
+
methods.find_by_name('untested_method').should be_nil
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'records callsites of methods' do
|
23
|
+
method = Rkid::Klass.find_by_name('TestedClass').methods.find_by_name('tested_method')
|
24
|
+
callsite = method.callsites.first
|
25
|
+
callsite.count.should == 1
|
26
|
+
callsite.frames.first.line.number.should == 8
|
27
|
+
callsite.frames.first.line.file.name.should == "./spec/rkid/analyzer_spec.rb"
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'records the source of parsed files' do
|
31
|
+
@file.lines.first.body.should == File.open("./spec/fixtures/test_class.rb").readline
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'indicates whether lines are covered' do
|
35
|
+
@file.lines.first.should_not be_covered
|
36
|
+
@file.lines[1].should be_covered
|
37
|
+
@file.lines[-1].should_not be_covered
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/rkid/sample.db
ADDED
File without changes
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
$LOAD_PATH.unshift "#{dir}/../lib"
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'spec'
|
6
|
+
require 'pp'
|
7
|
+
require 'rkid'
|
8
|
+
Dir["#{dir}/matchers/*"].each { |m| require "#{dir}/matchers/#{File.basename(m)}" }
|
9
|
+
|
10
|
+
Spec::Runner.configure do |config|
|
11
|
+
config.mock_with :rr
|
12
|
+
end
|
data/test.db
ADDED
File without changes
|
data/test.html
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.4
|
3
|
+
specification_version: 1
|
4
|
+
name: rkid
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.1"
|
7
|
+
date: 2008-03-31 00:00:00 -07:00
|
8
|
+
summary: Rcov in Database
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: nick@pivotallabs.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project: rkid
|
14
|
+
description: Rcov in Database
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Nick Kallen
|
31
|
+
files:
|
32
|
+
- Manifest.txt
|
33
|
+
- README.txt
|
34
|
+
- Rakefile
|
35
|
+
- TODO
|
36
|
+
- bin/rkid
|
37
|
+
- db/schema.rb
|
38
|
+
- lib/rkid.rb
|
39
|
+
- lib/rkid/analyzer.rb
|
40
|
+
- lib/rkid/models.rb
|
41
|
+
- lib/rkid/rake/task.rb
|
42
|
+
- rkid.db
|
43
|
+
- spec/fixtures/test_class.rb
|
44
|
+
- spec/rkid/analyzer_spec.rb
|
45
|
+
- spec/rkid/sample.db
|
46
|
+
- spec/spec_helper.rb
|
47
|
+
- test.db
|
48
|
+
- test.html
|
49
|
+
test_files: []
|
50
|
+
|
51
|
+
rdoc_options:
|
52
|
+
- --main
|
53
|
+
- README.txt
|
54
|
+
extra_rdoc_files:
|
55
|
+
- Manifest.txt
|
56
|
+
- README.txt
|
57
|
+
executables:
|
58
|
+
- rkid
|
59
|
+
extensions: []
|
60
|
+
|
61
|
+
requirements: []
|
62
|
+
|
63
|
+
dependencies:
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: rspec
|
66
|
+
version_requirement:
|
67
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">"
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: 0.0.0
|
72
|
+
version:
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: rcov
|
75
|
+
version_requirement:
|
76
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 0.0.0
|
81
|
+
version:
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: hoe
|
84
|
+
version_requirement:
|
85
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.5.1
|
90
|
+
version:
|