[DRE-commits] [SCM] rcov.git branch, master, updated. upstream/0.9.11-17-g9d1ee6e

Paul van Tilburg paulvt at debian.org
Tue May 29 13:51:27 UTC 2012


The following commit has been merged in the master branch:
commit 3ba72059d5f32f77df76a444c660c6c277fc516a
Author: Paul van Tilburg <paulvt at debian.org>
Date:   Tue May 29 14:38:47 2012 +0200

    Imported Upstream version 1.0

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a9cb6e9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+.config
+test/actual_coverage
+test/coverage.info
+test/sample_05.rb
+ext/rcovrt/Makefile
+ext/rcovrt/callsite.o
+ext/rcovrt/rcovrt.bundle
+ext/rcovrt/rcovrt.o
+InstalledFiles
+TAGS
+coverage
+pkg
+.DS_Store
+*.gem
+tags
+ext/rcovrt/rcovrt.so
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..46953e5
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,4 @@
+before_install: bundle init --gemspec=rcov.gemspec
+script: rake -Ilib
+rvm:
+- 1.8.7
diff --git a/README.markdown b/README.markdown
new file mode 100644
index 0000000..2bbc56f
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,130 @@
+# RCov - Code Coverage for Ruby
+
+## Why? What?
+
+This is our fork of Mauricio Fernandez's RCov (maintained by [Relevance] [2]).
+
+__NOTE:__ This fork __does not__ work on Ruby 1.9.x.  For coverage on Ruby 1.9 look at [SimpleCov] [3].
+
+[![Build Status](https://secure.travis-ci.org/relevance/rcov.png?branch=master)](http://travis-ci.org/relevance/rcov)
+
+## Install
+
+    gem install rcov
+
+## Bugs and Issues
+
+[RCov Issues on GitHub] [1]
+
+  [1]: http://github.com/relevance/rcov/issues/ "RCov Issues"
+  [2]: http://thinkrelevance.com "Relevance"
+  [3]: https://github.com/colszowka/simplecov
+
+## More Info
+
+rcov copyright (c) 2004-2012 Mauricio Fernandez <mfp at acm.org>
+rcov copyright (c) 2008-2012 Aaron Bedra and Relevance Inc.
+
+## rcov README
+
+`Rcov` is a code coverage tool for `Ruby`. It is commonly used for viewing
+overall test coverage of target code. It features:
+
+* cross-referenced XHTML and several kinds of text reports
+* support for easy automation with Rake
+* colorblind-friendliness
+
+## Requirements
+
+* Ruby 1.8.6 or higher
+* (recommended) C compiler: you can also use rcov without the rcovrt
+  extension but rcov will be two orders of magnitude slower. The
+  extension requires Ruby 1.8.6 or higher.
+
+## Normal install
+
+De-compress the archive and enter its top directory.
+Then type:
+
+	($ su)
+	# ruby setup.rb
+
+This simple step installs rcov under the default location for Ruby
+libraries.  You can also customize the installation by supplying some
+options to setup.rb.  Try `ruby setup.rb --help`.
+
+A normal (rcovrt-enabled) install requires Ruby >= 1.8.6 and a working
+C toolchain; if you cannot compile Ruby extensions proceed as
+described below.
+
+## Install without the rcovrt extension
+
+	($su )
+	# ruby setup.rb all --without-ext
+
+will install rcov without building the rcovrt extension.
+
+## Usage
+
+In the common scenario, your tests are under `test/` and the target code
+(whose coverage you want) is in `lib/`. In that case, all you have to do
+is use rcov to run the tests (instead of testrb), and a number of
+XHTML files with the code coverage information will be generated, e.g.
+
+	rcov -Ilib test/*.rb
+
+will execute all the `.rb` files under `test/` and generate the code
+coverage report for the target code (i.e. for the files in `lib/`) under
+`coverage/`. The target code needs not be under `lib/`; rcov will detect
+is as long as it is `require`d by the tests. rcov is smart enough to
+ignore "uninteresting" files: the tests themselves, files installed in
+Ruby's standard locations, etc.  See `rcov --help` for the list of
+regexps rcov matches filenames against.
+
+rcov can also be used from `Rake`; see `doc/readme_for_rake` or the `RDoc`
+documentation for more information.  The `Rakefile` included in rcov's
+sources holds a few tasks that run rcov on itself, producing a number
+of reports. You can try
+
+	rake rcov
+
+  preferably after a full install or
+
+	ruby setup.rb config
+	ruby setup.rb setup
+
+so that the rcovrt extension can be used to speed up the process. This
+will generate a cross-referenced XHTML report under `coverage/`.
+
+rcov can output information in several formats, and perform different
+kinds of analyses in addition to plain code coverage.  See `rcov --help`
+for a description of the available options.
+
+## License
+
+rcov is licensed under the same terms as Ruby. See LICENSE.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of ePark Labs nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Rakefile b/Rakefile
index 637a423..15b115b 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,103 +1,15 @@
-$:.unshift "lib" if File.directory? "lib"
-require 'rcov/rcovtask'
-require 'rcov/version'
 require 'rake/testtask'
-require 'rake/rdoctask'
-require 'rake/gempackagetask'
 require 'rake/clean'
-
-# Use the specified rcov executable instead of the one in $PATH
-# (this way we get a sort of informal functional test).
-# This could also be specified from the command like, e.g.
-#   rake rcov RCOVPATH=/path/to/myrcov
-ENV["RCOVPATH"] = "bin/rcov"
-
-# The following task is largely equivalent to:
-# Rcov::RcovTask.new
-desc "Create a cross-referenced code coverage report."
-Rcov::RcovTask.new do |t|
-  t.test_files = FileList['test/*_test.rb']
-  t.ruby_opts << "-Ilib:ext/rcovrt" # in order to use this rcov
-  t.rcov_opts << "--xrefs"  # comment to disable cross-references
-  t.verbose = true
-end
-
-desc "Analyze code coverage for the FileStatistics class."
-Rcov::RcovTask.new(:rcov_sourcefile) do |t|
-  t.test_files = FileList['test/file_statistics_test.rb']
-  t.verbose = true
-  t.rcov_opts << "--test-unit-only"
-  t.ruby_opts << "-Ilib:ext/rcovrt" # in order to use this rcov
-  t.output_dir = "coverage.sourcefile"
-end
-
-Rcov::RcovTask.new(:rcov_ccanalyzer) do |t|
-  t.test_files = FileList['test/code_coverage_analyzer_test.rb']
-  t.verbose = true
-  t.rcov_opts << "--test-unit-only"
-  t.ruby_opts << "-Ilib:ext/rcovrt" # in order to use this rcov
-  t.output_dir = "coverage.ccanalyzer"
-end
+require 'rcov/rcovtask'
+require 'rcov/version'
 
 desc "Run the unit tests with rcovrt."
-if RUBY_PLATFORM == 'java'
-  Rake::TestTask.new(:test_rcovrt => ["lib/rcovrt.jar"]) do |t|
-    t.libs << "lib"
-    t.ruby_opts << "--debug"
-    t.test_files = FileList['test/*_test.rb']
-    t.verbose = true
-  end
-
-  file "lib/rcovrt.jar" => FileList["ext/java/**/*.java"] do |t|
-    rm_f "lib/rcovrt.jar"
-    mkdir_p "pkg/classes"
-    sh "javac -classpath #{Java::JavaLang::System.getProperty('java.class.path')} -d pkg/classes #{t.prerequisites.join(' ')}"
-    sh "jar cf #{t.name} -C pkg/classes ."
-  end
-else
-  Rake::TestTask.new(:test_rcovrt => ["ext/rcovrt/rcovrt.so"]) do |t|
-    system("cd ext/rcovrt && make clean && rm Makefile")
-    t.libs << "ext/rcovrt"
-    t.test_files = FileList['test/*_test.rb']
-    t.verbose = true
-  end
-end
-
-file "ext/rcovrt/rcovrt.so" => FileList["ext/rcovrt/*.c"] do
-  ruby "setup.rb config"
-  ruby "setup.rb setup"
-end
-
-desc "Run the unit tests in pure-Ruby mode ."
-Rake::TestTask.new(:test_pure_ruby) do |t|
+Rake::TestTask.new(:test_rcovrt) do |t|
+  system("cd ext/rcovrt && make clean && rm Makefile")
+  system("cd ext/rcovrt && ruby extconf.rb && make")
   t.libs << "ext/rcovrt"
-  t.test_files = FileList['test/turn_off_rcovrt.rb', 'test/*_test.rb']
+  t.test_files = FileList['test/*_test.rb']
   t.verbose = true
 end
 
-desc "Run the unit tests"
-task :test => [:test_rcovrt]
-
-desc "install by setup.rb"
-task :install do
-  sh "sudo ruby setup.rb install"
-end
-
-task :default => :test
-
-begin
-  %w{sdoc sdoc-helpers rdiscount}.each { |name| gem name }
-  require 'sdoc_helpers'
-rescue LoadError => ex
-  puts "sdoc support not enabled:"
-  puts ex.inspect
-end
-
-require 'rake/rdoctask'
-Rake::RDocTask.new do |rdoc|
-  version = File.exist?('VERSION') ? File.read('VERSION') : ''
-  rdoc.rdoc_dir = 'rdoc'
-  rdoc.title = "rcov #{version}"
-  rdoc.rdoc_files.include('README*')
-  rdoc.rdoc_files.include('lib/**/*.rb')
-end
+task :default => [:test_rcovrt]
diff --git a/bin/rcov b/bin/rcov
index 4a9f95e..9f809c7 100755
--- a/bin/rcov
+++ b/bin/rcov
@@ -1,5 +1,6 @@
 #!/usr/bin/env ruby
 # -*- coding: iso-8859-1 -*-
+
 # rcov Copyright (c) 2004-2006 Mauricio Fernandez <mfp at acm.org>
 #
 # rcov originally based on 
@@ -10,6 +11,11 @@
 #
 # See LEGAL and LICENSE for additional licensing information.
 #
+if RUBY_VERSION =~ /1.9/
+  puts "** Ruby 1.9 is not supported. Please switch to simplecov **"
+  exit 1
+end
+
 require 'cgi'
 require 'rbconfig'
 require 'optparse'
@@ -27,6 +33,7 @@ options.profiling = false
 options.destdir = nil
 options.loadpaths = []
 options.textmode = false
+options.custom_formatters = []
 options.skip = Rcov::BaseFormatter::DEFAULT_OPTS[:ignore]
 options.include = []
 options.html = true
@@ -178,6 +185,21 @@ EOF
   opts.on("--text-coverage", "Dump coverage info to stdout, using", "ANSI color sequences unless -n.") do
     options.textmode = :coverage
   end
+
+  opts.on("--require LIB", "Require an additional lib before running") do |file|
+	require file
+  end
+
+  opts.on("--custom-formatter EXPR", "Generate additional output using a",
+          "custom formatter class. The expression",
+		  "is evaluated as Ruby code and should",
+          "return a Class object") do |class_expr|
+    formatter = instance_eval class_expr
+    unless formatter.is_a? Class
+      raise "--custom-formatter expression must return a Class object. Got a #{formatter.class.name}"
+    end
+    options.custom_formatters << formatter
+  end
   
   opts.on("--gcc", "Dump uncovered line in GCC error format.") do
     options.gcc_output = true
@@ -395,6 +417,10 @@ if options.html
   end
 end
 
+options.custom_formatters.each do |formatter|
+  formatters << make_formatter[formatter]
+end
+
 textual_formatters = { :counts => Rcov::FullTextReport, :coverage => Rcov::FullTextReport,
                       :gcc => Rcov::FullTextReport, :annotate => Rcov::RubyAnnotation,
                       :summary => Rcov::TextSummary, :report => Rcov::TextReport,
@@ -503,9 +529,6 @@ $rcov_code_coverage_analyzer.install_hook
 
 #{{{ Load scripts
 begin
-  if RUBY_VERSION =~ /1.9/
-    puts "** WARNING: Ruby 1.9 Support is experimental at best. Don't expect correct results! **"
-  end
   pending_scripts = ARGV.clone
   ARGV.replace extra_args
   until pending_scripts.empty?
diff --git a/ext/java/src/CallsiteHook.java b/ext/java/src/CallsiteHook.java
new file mode 100644
index 0000000..9911e2a
--- /dev/null
+++ b/ext/java/src/CallsiteHook.java
@@ -0,0 +1,137 @@
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.jruby.Ruby;
+import org.jruby.RubyArray;
+import org.jruby.RubyHash;
+import org.jruby.runtime.Frame;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.RubyEvent;
+import org.jruby.runtime.builtin.IRubyObject;
+
+public class CallsiteHook extends RcovHook {
+  
+  private static CallsiteHook callsiteHook;
+
+  public static CallsiteHook getCallsiteHook() {
+    if (callsiteHook == null) {
+      callsiteHook = new CallsiteHook();
+    }
+    return callsiteHook;
+  }
+  
+  private boolean active;
+  private RubyHash defsites;
+  private RubyHash callsites;
+  
+  private CallsiteHook() {
+    super();
+  }
+  
+  public boolean isActive() {
+    return active;
+  }
+  
+  public boolean isInterestedInEvent(RubyEvent event) {
+    return event == RubyEvent.CALL || event == RubyEvent.C_CALL;
+  }
+  
+  public RubyArray getCallsiteInfo(Ruby runtime) {
+    RubyArray info = runtime.newArray();
+    info.add(getCallsites(runtime));
+    info.add(getDefsites(runtime));
+    return info;
+  }
+  
+  public void setActive(boolean active) {
+    this.active = active;
+  }
+  
+  public RubyHash resetDefsites() {
+    defsites.clear();
+    return defsites;
+  }
+  
+  public void eventHandler(ThreadContext context, String event, String file, int line, String name, IRubyObject type) {
+    RubyArray currentMethod = context.getRuntime().newArray();
+    currentMethod.add(context.getFrameKlazz());
+    currentMethod.add(context.getRuntime().newSymbol(name));
+    
+    RubyArray fileLoc = context.getRuntime().newArray();
+    fileLoc.add(file);
+    fileLoc.add(Long.valueOf(line));
+    defsites = getDefsites(context.getRuntime());
+    
+    if (!context.isWithinTrace()) {
+      context.setWithinTrace(true);
+      defsites.put(currentMethod, fileLoc);
+      callsites = getCallsites(context.getRuntime());
+      
+      if (!callsites.containsKey(currentMethod)) {
+        callsites.put(currentMethod, RubyHash.newHash(context.getRuntime()));
+      }
+      
+      RubyHash hash = (RubyHash) callsites.get(currentMethod);
+      RubyArray callerArray = customBacktrace(context);
+      
+      if (!hash.containsKey(callerArray)) {
+        hash.put(callerArray, Long.valueOf(0));
+      }
+      
+      Long count = (Long) hash.get(callerArray);
+      long itCount = count.longValue() + 1L;
+      hash.put(callerArray, Long.valueOf(itCount));
+      context.setWithinTrace(false);
+    }
+  }
+  
+  private RubyArray customBacktrace(ThreadContext context) {
+    Frame[] frames = context.createBacktrace(1, false);
+    RubyArray ary = context.getRuntime().newArray();
+    ary.addAll(formatBacktrace(context.getRuntime(), frames[frames.length - 1]));
+    return context.getRuntime().newArray((IRubyObject) ary);
+  }
+  
+  /*
+   * TODO: The logic in this method really needs to be wrapped in a backtrace
+   * object or something. Then I could fix the file path issues that cause
+   * test failures.
+   * @param runtime
+   * @param backtrace
+   * @return
+   */
+  private RubyArray formatBacktrace(Ruby runtime, Frame backtrace) {
+    RubyArray ary = runtime.newArray();
+    
+    if (backtrace == null) {
+      ary.add(runtime.getNil());
+      ary.add(runtime.getNil());
+      ary.add("");
+      ary.add(Long.valueOf(0));
+    } else {
+      ary.add(backtrace.getKlazz());
+      ary.add((backtrace.getName() == null ? runtime.getNil() : runtime.newSymbol( backtrace.getName())));
+      ary.add(backtrace.getFile());
+      //Add 1 to compensate for the zero offset in the Frame elements.
+      ary.add(backtrace.getLine() + 1);
+    }
+    
+    return ary;
+  }
+  
+  private RubyHash getCallsites(Ruby runtime) {
+    if (this.callsites == null) {
+      this.callsites = RubyHash.newHash(runtime);
+    }
+    
+    return this.callsites;
+  }
+  
+  private RubyHash getDefsites(Ruby runtime) {
+    if (this.defsites == null) {
+      this.defsites = RubyHash.newHash(runtime);
+    }
+    
+    return this.defsites;
+  }
+}
diff --git a/ext/java/src/CoverageHook.java b/ext/java/src/CoverageHook.java
new file mode 100644
index 0000000..17f8d55
--- /dev/null
+++ b/ext/java/src/CoverageHook.java
@@ -0,0 +1,117 @@
+import org.jruby.Ruby;
+import org.jruby.RubyArray;
+import org.jruby.RubyHash;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.RubyEvent;
+import org.jruby.runtime.builtin.IRubyObject;
+
+public class CoverageHook extends RcovHook {
+  
+  private static CoverageHook hook;
+  
+  public static CoverageHook getCoverageHook() {
+    if (hook == null) {
+      hook = new CoverageHook();
+    }
+    
+    return hook;
+  }
+  
+  private boolean active;
+  private RubyHash cover;
+  
+  private CoverageHook() {
+    super();
+  }
+  
+  public boolean isActive() {
+    return active;
+  }
+  
+  public void setActive(boolean active) {
+    this.active = active;
+  }
+  
+  public void eventHandler(ThreadContext context, String event, String file, int line, String name, IRubyObject type) {
+    //Line numbers are 1s based.  Arrays are zero based.  We need to compensate for that.
+    line -= 1;
+    
+    // Make sure that we have SCRIPT_LINES__ and it's a hash
+    RubyHash scriptLines = getScriptLines(context.getRuntime());
+    if (scriptLines == null || !scriptLines.containsKey(file)) {
+      return;
+    }
+    
+    // make sure the file's source lines are in SCRIPT_LINES__
+    cover = getCover(context.getRuntime());
+    RubyArray lines = (RubyArray) scriptLines.get(file);
+    if (lines == null || cover == null){
+      return;
+    }
+    
+    // make sure file's counts are in COVER and set to zero
+    RubyArray counts = (RubyArray) cover.get(file);
+    if (counts == null) {
+      counts = context.getRuntime().newArray();
+      for (int i = 0; i < lines.size(); i++) {
+        counts.add(Long.valueOf(0));
+      }
+      cover.put(file, counts);
+    }
+    
+    // in the case of code generation (one example is instance_eval for routes optimization)
+    // We could get here and see that we are not matched up with what we expect
+    if (counts.size() <= line ) {
+      for (int i=counts.size(); i<= line; i++) {
+        counts.add(Long.valueOf(0));
+      }
+    }
+    
+    if (!context.isWithinTrace()) {
+      try {
+        context.setWithinTrace(true);
+        // update counts in COVER
+        Long count = (Long) counts.get(line);
+        if (count == null) {
+          count = Long.valueOf(0);
+        }
+        count = Long.valueOf(count.longValue() + 1);
+        counts.set(line , count);
+      }
+      finally{
+        context.setWithinTrace(false);
+      }
+    }
+  }
+  
+  public boolean isInterestedInEvent(RubyEvent event) {
+    return event == RubyEvent.CALL || event == RubyEvent.LINE || event == RubyEvent.RETURN || event == RubyEvent.CLASS || event == RubyEvent.C_RETURN || event == RubyEvent.C_CALL;
+  }
+  
+  /*
+   * Returns the COVER hash, setting up the COVER constant if necessary.
+   * @param runtime
+   * @return
+   */
+  public RubyHash getCover(Ruby runtime) {
+    if (cover == null) {
+      cover = RubyHash.newHash(runtime);
+    }
+    
+    return cover;
+  }
+  
+  public RubyHash getScriptLines(Ruby runtime) {
+    IRubyObject scriptLines = runtime.getObject().getConstantAt("SCRIPT_LINES__");
+    if (scriptLines instanceof RubyHash) {
+      return (RubyHash) scriptLines;
+    } else {
+      return null;
+    }
+  }
+  
+  public IRubyObject resetCoverage(Ruby runtime) {
+    getCover(runtime).clear();
+    return runtime.getNil();
+  }
+}
diff --git a/ext/java/src/RcovHook.java b/ext/java/src/RcovHook.java
new file mode 100644
index 0000000..61a5371
--- /dev/null
+++ b/ext/java/src/RcovHook.java
@@ -0,0 +1,9 @@
+import org.jruby.runtime.EventHook;
+
+public abstract class RcovHook extends EventHook {
+  /** returns true if the hook is set */
+  abstract boolean isActive();
+
+  /** used to mark the hook set or unset */
+  abstract void setActive(boolean active);
+}
diff --git a/ext/java/src/RcovrtService.java b/ext/java/src/RcovrtService.java
new file mode 100644
index 0000000..d540985
--- /dev/null
+++ b/ext/java/src/RcovrtService.java
@@ -0,0 +1,130 @@
+import org.jruby.Ruby;
+import org.jruby.RubyArray;
+import org.jruby.RubyFixnum;
+import org.jruby.RubyHash;
+import org.jruby.RubyModule;
+import org.jruby.RubyObjectAdapter;
+import org.jruby.RubySymbol;
+import org.jruby.exceptions.RaiseException;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.runtime.load.BasicLibraryService;
+import org.jruby.javasupport.JavaEmbedUtils;
+import org.jruby.javasupport.JavaUtil;
+
+public class RcovrtService implements BasicLibraryService {
+  
+  private static RubyObjectAdapter rubyApi;
+  
+  public boolean basicLoad(Ruby runtime) {
+    RubyModule rcov = runtime.getOrCreateModule("Rcov");
+    RubyModule rcov__ = runtime.defineModuleUnder("RCOV__", rcov);
+    IRubyObject sl = runtime.getObject().getConstantAt("SCRIPT_LINES__");
+    
+    if (sl == null) {
+        runtime.getObject().setConstant("SCRIPT_LINES__", RubyHash.newHash(runtime));
+    }
+    
+    rubyApi = JavaEmbedUtils.newObjectAdapter();
+    rcov__.defineAnnotatedMethods(RcovrtService.class);
+    return true;
+  }
+  
+  @JRubyMethod(name="reset_callsite", meta = true)
+  public static IRubyObject resetCallsite(IRubyObject recv) {
+    CallsiteHook hook = CallsiteHook.getCallsiteHook();
+    if (hook.isActive()) {
+      throw RaiseException.createNativeRaiseException(recv.getRuntime(),
+        new RuntimeException("Cannot reset the callsite info in the middle of a traced run."));
+    }
+    return hook.resetDefsites();
+  }
+  
+  @JRubyMethod(name="reset_coverage", meta = true)
+  public static IRubyObject resetCoverage(IRubyObject recv) {
+    CoverageHook hook = CoverageHook.getCoverageHook();
+    if (hook.isActive()) {
+      throw RaiseException.createNativeRaiseException(recv.getRuntime(),
+        new RuntimeException("Cannot reset the coverage info in the middle of a traced run."));
+    }
+    return hook.resetCoverage(recv.getRuntime());
+  }
+  
+  @JRubyMethod(name="remove_coverage_hook", meta = true)
+  public static IRubyObject removeCoverageHook(IRubyObject recv) {
+    return removeRcovHook(recv, CoverageHook.getCoverageHook());
+  }
+  
+  @JRubyMethod(name="install_coverage_hook", meta = true)
+  public static IRubyObject installCoverageHook(IRubyObject recv) {
+    return installRcovHook(recv, CoverageHook.getCoverageHook());
+  }
+  
+  /*
+     TODO: I think this is broken. I'm not sure why, but recreating
+     cover all the time seems bad.
+  */
+  @JRubyMethod(name="generate_coverage_info", meta = true)
+  public static IRubyObject generateCoverageInfo(IRubyObject recv) {
+    Ruby run = recv.getRuntime();
+    RubyHash cover = (RubyHash)CoverageHook.getCoverageHook().getCover(run);
+    RubyHash xcover = RubyHash.newHash(run);
+    RubyArray keys = cover.keys();
+    RubyArray temp;
+    ThreadContext  ctx = run.getCurrentContext();
+    for (int i=0; i < keys.length().getLongValue(); i++) {
+      IRubyObject key = keys.aref(JavaUtil.convertJavaToRuby(run, Long.valueOf(i)));
+      temp = ((RubyArray)cover.op_aref(ctx, key)).aryDup();
+      xcover.op_aset(ctx,key, temp);
+    }
+    RubyModule rcov__ = (RubyModule) recv.getRuntime().getModule("Rcov").getConstant("RCOV__");
+    
+    if (rcov__.const_defined_p(ctx, RubySymbol.newSymbol(recv.getRuntime(), "COVER")).isTrue()) {
+        rcov__.remove_const(ctx, recv.getRuntime().newString("COVER"));
+    }
+    rcov__.defineConstant( "COVER", xcover );
+    
+    return xcover;
+  }
+  
+  @JRubyMethod(name="remove_callsite_hook", meta = true)
+  public static IRubyObject removeCallsiteHook(IRubyObject recv) {
+    return removeRcovHook( recv, CallsiteHook.getCallsiteHook() );
+  }
+  
+  @JRubyMethod(name="install_callsite_hook", meta = true)
+  public static IRubyObject installCallsiteHook(IRubyObject recv) {
+    return installRcovHook( recv, CallsiteHook.getCallsiteHook() );
+  }
+  
+  @JRubyMethod(name="generate_callsite_info", meta = true)
+  public static IRubyObject generateCallsiteInfo(IRubyObject recv) {
+    return CallsiteHook.getCallsiteHook().getCallsiteInfo( recv.getRuntime() ).dup();
+  }
+  
+  @JRubyMethod(name="ABI", meta = true)
+  public static IRubyObject getAbi(IRubyObject recv) {
+    RubyArray ary = recv.getRuntime().newArray();
+    ary.add(RubyFixnum.int2fix( recv.getRuntime(), 2L));
+    ary.add(RubyFixnum.int2fix( recv.getRuntime(), 0L));
+    ary.add(RubyFixnum.int2fix( recv.getRuntime(), 0L));
+    return ary;
+  }
+  
+  private static IRubyObject removeRcovHook(IRubyObject recv, RcovHook hook) {
+    hook.setActive(false);
+    recv.getRuntime().removeEventHook(hook);
+    return recv.getRuntime().getFalse();
+  }
+  
+  private static IRubyObject installRcovHook( IRubyObject recv, RcovHook hook ) {
+    if (!hook.isActive()) {
+      hook.setActive(true);
+      recv.getRuntime().addEventHook(hook);
+      return recv.getRuntime().getTrue();
+    } else {
+      return recv.getRuntime().getFalse();
+    }
+  }
+}
diff --git a/ext/rcovrt/1.8/callsite.c b/ext/rcovrt/1.8/callsite.c
index e70b243..bedf70a 100644
--- a/ext/rcovrt/1.8/callsite.c
+++ b/ext/rcovrt/1.8/callsite.c
@@ -4,17 +4,15 @@
 #include <st.h>
 #include <stdlib.h>
 
-static char callsite_hook_set_p;
-
 typedef struct {
   char *sourcefile;
   unsigned int sourceline;
   VALUE curr_meth;
-} type_def_site;       
+} type_def_site;
 
+static char callsite_hook_set_p;
 static VALUE caller_info = 0;
 static VALUE method_def_site_info = 0;
-
 static caller_stack_len = 1;
 
 static VALUE record_callsite_info(VALUE args) {
@@ -28,23 +26,20 @@ static VALUE record_callsite_info(VALUE args) {
   curr_meth = pargs[1];
   count_hash = rb_hash_aref(caller_info, curr_meth);
 
-  if(TYPE(count_hash) != T_HASH) { 
-    /* Qnil, anything else should be impossible unless somebody's been
-     * messing with ObjectSpace */
+  if (TYPE(count_hash) != T_HASH) {
     count_hash = rb_hash_new();
     rb_hash_aset(caller_info, curr_meth, count_hash);
   }
 
   count = rb_hash_aref(count_hash, caller_ary);
 
-  if(count == Qnil) 
-          count = INT2FIX(0);
+  if (count == Qnil) count = INT2FIX(0);
 
   count = INT2FIX(FIX2UINT(count) + 1);
   rb_hash_aset(count_hash, caller_ary, count);
   /*
-  printf("CALLSITE: %s -> %s   %d\n", RSTRING(rb_inspect(curr_meth))->ptr,
-                  RSTRING(rb_inspect(caller_ary))->ptr, FIX2INT(count));
+    printf("CALLSITE: %s -> %s   %d\n", RSTRING(rb_inspect(curr_meth))->ptr,
+    RSTRING(rb_inspect(caller_ary))->ptr, FIX2INT(count));
   */
 
   return Qnil;
@@ -55,17 +50,16 @@ static VALUE record_method_def_site(VALUE args) {
   VALUE def_site_info;
   VALUE hash;
 
-  if(RTEST(rb_hash_aref(method_def_site_info, pargs->curr_meth)))
-    return Qnil;
+  if (RTEST(rb_hash_aref(method_def_site_info, pargs->curr_meth))) return Qnil;
   def_site_info = rb_ary_new();
   rb_ary_push(def_site_info, rb_str_new2(pargs->sourcefile));
   rb_ary_push(def_site_info, INT2NUM(pargs->sourceline+1));
   rb_hash_aset(method_def_site_info, pargs->curr_meth, def_site_info);
   /*
-  printf("DEFSITE: %s:%d  for %s\n", pargs->sourcefile, pargs->sourceline+1,
-                  RSTRING(rb_inspect(pargs->curr_meth))->ptr);
+    printf("DEFSITE: %s:%d  for %s\n", pargs->sourcefile, pargs->sourceline+1,
+    RSTRING(rb_inspect(pargs->curr_meth))->ptr);
   */
-  
+
   return Qnil;
 }
 
@@ -78,18 +72,17 @@ static VALUE callsite_custom_backtrace(int lev) {
 
   ary = rb_ary_new();
 
-  if (frame->last_func == ID_ALLOCATOR) {
-    frame = frame->prev;
-  }
+  if (frame->last_func == ID_ALLOCATOR) frame = frame->prev;
 
   for (; frame && (n = frame->node); frame = frame->prev) {
     if (frame->prev && frame->prev->last_func) {
       if (frame->prev->node == n) continue;
+
       level = rb_ary_new();
       klass = frame->prev->last_class ? frame->prev->last_class : Qnil;
-      if(TYPE(klass) == T_ICLASS) {
-        klass = CLASS_OF(klass);
-      }
+
+      if (TYPE(klass) == T_ICLASS) klass = CLASS_OF(klass);
+
       rb_ary_push(level, klass);
       rb_ary_push(level, ID2SYM(frame->prev->last_func));
       rb_ary_push(level, rb_str_new2(n->nd_file));
@@ -102,14 +95,14 @@ static VALUE callsite_custom_backtrace(int lev) {
       rb_ary_push(level, rb_str_new2(n->nd_file));
       rb_ary_push(level, INT2NUM(nd_line(n)));
     }
+
     rb_ary_push(ary, level);
-    if(--lev == 0)
-      break;
+    if (--lev == 0) break;
   }
-  
+
   return ary;
 }
-  
+
 static void coverage_event_callsite_hook(rb_event_t event, NODE *node, VALUE self,  ID mid, VALUE klass) {
   VALUE caller_ary;
   VALUE curr_meth;
@@ -117,49 +110,40 @@ static void coverage_event_callsite_hook(rb_event_t event, NODE *node, VALUE sel
   int status;
 
   caller_ary = callsite_custom_backtrace(caller_stack_len);
-  
-  if(TYPE(klass) == T_ICLASS) {
-    klass = CLASS_OF(klass);
-  }
+
+  if (TYPE(klass) == T_ICLASS) klass = CLASS_OF(klass);
 
   curr_meth = rb_ary_new();
   rb_ary_push(curr_meth, klass);
   rb_ary_push(curr_meth, ID2SYM(mid));
-
   args[0] = caller_ary;
   args[1] = curr_meth;
   rb_protect(record_callsite_info, (VALUE)args, &status);
 
-  if(!status && node) {
-    type_def_site args;        
-    
+  if (!status && node) {
+    type_def_site args;
     args.sourcefile = node->nd_file;
     args.sourceline = nd_line(node) - 1;
     args.curr_meth = curr_meth;
     rb_protect(record_method_def_site, (VALUE)&args, NULL);
   }
 
-  if(status)
-    rb_gv_set("$!", Qnil);
+  if (status) rb_gv_set("$!", Qnil);
 }
 
 static VALUE cov_install_callsite_hook(VALUE self) {
-  if(!callsite_hook_set_p) {
-    if(TYPE(caller_info) != T_HASH)
-      caller_info = rb_hash_new();
+  if (!callsite_hook_set_p) {
+    if (TYPE(caller_info) != T_HASH) caller_info = rb_hash_new();
     callsite_hook_set_p = 1;
     rb_add_event_hook(coverage_event_callsite_hook, RUBY_EVENT_CALL);
-    
     return Qtrue;
-  } 
-  else
-    return Qfalse;
+  } else return Qfalse;
 }
 
 static VALUE cov_remove_callsite_hook(VALUE self) {
-  if(!callsite_hook_set_p) 
+  if (!callsite_hook_set_p) {
     return Qfalse;
-  else {
+  } else {
     rb_remove_event_hook(coverage_event_callsite_hook);
     callsite_hook_set_p = 0;
     return Qtrue;
@@ -168,7 +152,6 @@ static VALUE cov_remove_callsite_hook(VALUE self) {
 
 static VALUE cov_generate_callsite_info(VALUE self) {
   VALUE ret;
-
   ret = rb_ary_new();
   rb_ary_push(ret, caller_info);
   rb_ary_push(ret, method_def_site_info);
@@ -176,7 +159,7 @@ static VALUE cov_generate_callsite_info(VALUE self) {
 }
 
 static VALUE cov_reset_callsite(VALUE self) {
-  if(callsite_hook_set_p) {
+  if (callsite_hook_set_p) {
     rb_raise(rb_eRuntimeError, "Cannot reset the callsite info in the middle of a traced run.");
     return Qnil;
   }
@@ -193,22 +176,24 @@ void Init_rcov_callsite() {
   ID id_coverage__ = rb_intern("RCOV__");
   ID id_script_lines__ = rb_intern("SCRIPT_LINES__");
 
-  if(rb_const_defined(rb_cObject, id_rcov)) 
+  if (rb_const_defined(rb_cObject, id_rcov)) {
     mRcov = rb_const_get(rb_cObject, id_rcov);
-  else
+  } else {
     mRcov = rb_define_module("Rcov");
-  
-  if(rb_const_defined(mRcov, id_coverage__))
+  }
+
+  if(rb_const_defined(mRcov, id_coverage__)) {
     mRCOV__ = rb_const_get_at(mRcov, id_coverage__);
-  else
+  } else {
     mRCOV__ = rb_define_module_under(mRcov, "RCOV__");
+  }
 
   callsite_hook_set_p = 0;
   caller_info = rb_hash_new();
   method_def_site_info = rb_hash_new();
   rb_gc_register_address(&caller_info);
   rb_gc_register_address(&method_def_site_info);
- 
+
   rb_define_singleton_method(mRCOV__, "install_callsite_hook", cov_install_callsite_hook, 0);
   rb_define_singleton_method(mRCOV__, "remove_callsite_hook", cov_remove_callsite_hook, 0);
   rb_define_singleton_method(mRCOV__, "generate_callsite_info", cov_generate_callsite_info, 0);
diff --git a/ext/rcovrt/1.8/rcovrt.c b/ext/rcovrt/1.8/rcovrt.c
index 2927df8..0acf9fc 100644
--- a/ext/rcovrt/1.8/rcovrt.c
+++ b/ext/rcovrt/1.8/rcovrt.c
@@ -6,7 +6,6 @@
 #include <assert.h>
 
 #define COVERAGE_DEBUG_EVENTS 0
-
 #define RCOVRT_VERSION_MAJOR 2
 #define RCOVRT_VERSION_MINOR 0
 #define RCOVRT_VERSION_REV   0
@@ -24,41 +23,36 @@ struct cov_array {
 };
 
 static struct cov_array *cached_array = 0;
-static char *cached_file = 0; 
+static char *cached_file = 0;
 
 static struct cov_array * coverage_increase_counter_uncached(char *sourcefile, unsigned int sourceline, char mark_only) {
   struct cov_array *carray = NULL;
- 
-  if(sourcefile == NULL) {
-    /* "can't happen", just ignore and avoid segfault */
+
+  if (sourcefile == NULL) {
     return NULL;
-  } 
-  else if(!st_lookup(coverinfo, (st_data_t)sourcefile, (st_data_t*)&carray)) {
+  } else if (!st_lookup(coverinfo, (st_data_t)sourcefile, (st_data_t*)&carray)) {
     VALUE arr;
-    
     arr = rb_hash_aref(oSCRIPT_LINES__, rb_str_new2(sourcefile));
-    if(NIL_P(arr)) 
-      return 0;
+
+    if (NIL_P(arr)) return 0;
+
     rb_check_type(arr, T_ARRAY);
     carray = calloc(1, sizeof(struct cov_array));
     carray->ptr = calloc(RARRAY(arr)->len, sizeof(unsigned int));
     carray->len = RARRAY(arr)->len;
     st_insert(coverinfo, (st_data_t)strdup(sourcefile), (st_data_t) carray);
-  } 
-  else {
-    /* recovered carray, sanity check */
+  } else {
     assert(carray && "failed to create valid carray");
   }
 
-  if(mark_only) {
+  if (mark_only) {
     if (carray && carray->len > sourceline) {
-      if(!carray->ptr[sourceline])
+      if (!carray->ptr[sourceline])
         carray->ptr[sourceline] = 1;
     } else {
-      #if COVERAGE_DEBUG_EVENTS
-        printf("DEBUG: %s carray->len:%d sourceline:%d\n",
-               sourcefile, carray->len, sourceline);
-      #endif
+#if COVERAGE_DEBUG_EVENTS
+      printf("DEBUG: %s carray->len:%d sourceline:%d\n", sourcefile, carray->len, sourceline);
+#endif
     }
   } else {
     if (carray && carray->len > sourceline) {
@@ -73,17 +67,15 @@ static void coverage_mark_caller() {
   struct FRAME *frame = ruby_frame;
   NODE *n;
 
-  if (frame->last_func == ID_ALLOCATOR) {
-    frame = frame->prev;
-  }
+  if (frame->last_func == ID_ALLOCATOR) frame = frame->prev;
+
   for (; frame && (n = frame->node); frame = frame->prev) {
     if (frame->prev && frame->prev->last_func) {
       if (frame->prev->node == n) {
         if (frame->prev->last_func == frame->last_func) continue;
       }
       coverage_increase_counter_uncached(n->nd_file, nd_line(n) - 1, 1);
-    }
-    else {
+    } else {
       coverage_increase_counter_uncached(n->nd_file, nd_line(n) - 1, 1);
     }
     break;
@@ -91,10 +83,11 @@ static void coverage_mark_caller() {
 }
 
 static void coverage_increase_counter_cached(char *sourcefile, int sourceline) {
-  if(cached_file == sourcefile && cached_array && cached_array->len > sourceline) {
+  if (cached_file == sourcefile && cached_array && cached_array->len > sourceline) {
     cached_array->ptr[sourceline]++;
     return;
   }
+
   cached_file = sourcefile;
   cached_array = coverage_increase_counter_uncached(sourcefile, sourceline, 0);
 }
@@ -103,74 +96,65 @@ static void coverage_event_coverage_hook(rb_event_t event, NODE *node, VALUE sel
   char *sourcefile;
   unsigned int sourceline;
   static unsigned int in_hook = 0;
- 
-  if(in_hook) {
-    return;
-  }
+
+  if (in_hook) return;
 
   in_hook++;
 
-  #if COVERAGE_DEBUG_EVENTS
-    do {
-      int status;
-      VALUE old_exception;
-      old_exception = rb_gv_get("$!");
-      rb_protect(rb_inspect, klass, &status);
-      if(!status) {
-        printf("EVENT: %d %s %s %s %d\n", event,
-               klass ? RSTRING(rb_inspect(klass))->ptr : "", 
-               mid ? (mid == ID_ALLOCATOR ? "ID_ALLOCATOR" : rb_id2name(mid))
-               : "unknown",
-               node ? node->nd_file : "", node ? nd_line(node) : 0);
-      } 
-      else {
-        printf("EVENT: %d %s %s %d\n", event,
-               mid ? (mid == ID_ALLOCATOR ? "ID_ALLOCATOR" : rb_id2name(mid)) 
-               : "unknown",
-               node ? node->nd_file : "", node ? nd_line(node) : 0);
-      }
-      
-      rb_gv_set("$!", old_exception);
-    } while (0); 
-  #endif
+#if COVERAGE_DEBUG_EVENTS
+  do {
+    int status;
+    VALUE old_exception;
+    old_exception = rb_gv_get("$!");
+    rb_protect(rb_inspect, klass, &status);
+
+    if (!status) {
+      printf("EVENT: %d %s %s %s %d\n", event,
+             klass ? RSTRING(rb_inspect(klass))->ptr : "",
+             mid ? (mid == ID_ALLOCATOR ? "ID_ALLOCATOR" : rb_id2name(mid))
+             : "unknown",
+             node ? node->nd_file : "", node ? nd_line(node) : 0);
+    } else {
+      printf("EVENT: %d %s %s %d\n", event,
+             mid ? (mid == ID_ALLOCATOR ? "ID_ALLOCATOR" : rb_id2name(mid))
+             : "unknown",
+             node ? node->nd_file : "", node ? nd_line(node) : 0);
+    }
 
-  if(event & RUBY_EVENT_C_CALL) {
-    coverage_mark_caller();
-  }
-  
-  if(event & (RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN | RUBY_EVENT_CLASS)) {
+    rb_gv_set("$!", old_exception);
+  } while (0);
+#endif
+
+  if (event & RUBY_EVENT_C_CALL) coverage_mark_caller();
+
+  if (event & (RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN | RUBY_EVENT_CLASS)) {
     in_hook--;
     return;
   }
-  
-  if(node == NULL) {
+
+  if (node == NULL) {
     in_hook--;
-      return;
+    return;
   }
-  
+
   sourcefile = node->nd_file;
   sourceline = nd_line(node) - 1;
-  
   coverage_increase_counter_cached(sourcefile, sourceline);
-  
-  if(event & RUBY_EVENT_CALL)
-    coverage_mark_caller();
+
+  if (event & RUBY_EVENT_CALL) coverage_mark_caller();
   in_hook--;
 }
 
 static VALUE cov_install_coverage_hook(VALUE self) {
-  if(!coverage_hook_set_p) {
-    if(!coverinfo)
-      coverinfo = st_init_strtable();
+  if (!coverage_hook_set_p) {
+    if (!coverinfo) coverinfo = st_init_strtable();
     coverage_hook_set_p = 1;
     /* TODO: allow C_CALL too, since it's supported already
      * the overhead is around ~30%, tested on typo */
     rb_add_event_hook(coverage_event_coverage_hook, RUBY_EVENT_ALL & ~RUBY_EVENT_C_CALL & ~RUBY_EVENT_C_RETURN & ~RUBY_EVENT_CLASS);
-    
+
     return Qtrue;
-  }
-  else
-    return Qfalse;
+  } else return Qfalse;
 }
 
 static int populate_cover(st_data_t key, st_data_t value, st_data_t cover) {
@@ -179,24 +163,25 @@ static int populate_cover(st_data_t key, st_data_t value, st_data_t cover) {
   VALUE rval;
   struct cov_array *carray;
   unsigned int i;
- 
+
   rcover = (VALUE)cover;
   carray = (struct cov_array *) value;
   rkey = rb_str_new2((char*) key);
   rval = rb_ary_new2(carray->len);
 
-  for(i = 0; i < carray->len; i++)
+  for (i = 0; i < carray->len; i++) {
     RARRAY(rval)->ptr[i] = UINT2NUM(carray->ptr[i]);
+  }
 
   RARRAY(rval)->len = carray->len;
   rb_hash_aset(rcover, rkey, rval);
-  
+
   return ST_CONTINUE;
 }
 
 static int free_table(st_data_t key, st_data_t value, st_data_t ignored) {
   struct cov_array *carray;
- 
+
   carray = (struct cov_array *) value;
   free((char *)key);
   free(carray->ptr);
@@ -206,9 +191,9 @@ static int free_table(st_data_t key, st_data_t value, st_data_t ignored) {
 }
 
 static VALUE cov_remove_coverage_hook(VALUE self) {
-  if(!coverage_hook_set_p) 
+  if (!coverage_hook_set_p) {
     return Qfalse;
-  else {
+  } else {
     rb_remove_event_hook(coverage_event_coverage_hook);
     coverage_hook_set_p = 0;
     return Qtrue;
@@ -218,14 +203,11 @@ static VALUE cov_remove_coverage_hook(VALUE self) {
 static VALUE cov_generate_coverage_info(VALUE self) {
   VALUE cover;
 
-  if(rb_const_defined_at(mRCOV__, id_cover)) {
-    rb_mod_remove_const(mRCOV__, ID2SYM(id_cover));
-  }
+  if (rb_const_defined_at(mRCOV__, id_cover)) rb_mod_remove_const(mRCOV__, ID2SYM(id_cover));
 
   cover = rb_hash_new();
 
-  if(coverinfo)
-    st_foreach(coverinfo, populate_cover, cover);
+  if (coverinfo) st_foreach(coverinfo, populate_cover, cover);
 
   rb_define_const(mRCOV__, "COVER", cover);
 
@@ -233,14 +215,14 @@ static VALUE cov_generate_coverage_info(VALUE self) {
 }
 
 static VALUE cov_reset_coverage(VALUE self) {
-  if(coverage_hook_set_p) {
+  if (coverage_hook_set_p) {
     rb_raise(rb_eRuntimeError, "Cannot reset the coverage info in the middle of a traced run.");
     return Qnil;
   }
 
   cached_array = 0;
   cached_file = 0;
-  st_foreach(coverinfo, free_table, Qnil); 
+  st_foreach(coverinfo, free_table, Qnil);
   st_free_table(coverinfo);
   coverinfo = 0;
 
@@ -249,12 +231,12 @@ static VALUE cov_reset_coverage(VALUE self) {
 
 static VALUE cov_ABI(VALUE self) {
   VALUE ret;
-  
+
   ret = rb_ary_new();
   rb_ary_push(ret, INT2FIX(RCOVRT_VERSION_MAJOR));
   rb_ary_push(ret, INT2FIX(RCOVRT_VERSION_MINOR));
   rb_ary_push(ret, INT2FIX(RCOVRT_VERSION_REV));
-  
+
   return ret;
 }
 
@@ -262,33 +244,35 @@ void Init_rcovrt() {
   ID id_rcov = rb_intern("Rcov");
   ID id_coverage__ = rb_intern("RCOV__");
   ID id_script_lines__ = rb_intern("SCRIPT_LINES__");
- 
+
   id_cover = rb_intern("COVER");
-  
-  if(rb_const_defined(rb_cObject, id_rcov)) 
+
+  if (rb_const_defined(rb_cObject, id_rcov)) {
     mRcov = rb_const_get(rb_cObject, id_rcov);
-  else
+  } else {
     mRcov = rb_define_module("Rcov");
-  
-  if(rb_const_defined(mRcov, id_coverage__))
+  }
+
+  if (rb_const_defined(mRcov, id_coverage__)) {
     mRCOV__ = rb_const_get_at(mRcov, id_coverage__);
-  else
+  } else {
     mRCOV__ = rb_define_module_under(mRcov, "RCOV__");
-  
-  if(rb_const_defined(rb_cObject, id_script_lines__))
+  }
+
+  if (rb_const_defined(rb_cObject, id_script_lines__)) {
     oSCRIPT_LINES__ = rb_const_get(rb_cObject, rb_intern("SCRIPT_LINES__"));
-  else {
+  } else {
     oSCRIPT_LINES__ = rb_hash_new();
     rb_const_set(rb_cObject, id_script_lines__, oSCRIPT_LINES__);
   }
-  
+
   coverage_hook_set_p = 0;
-  
+
   rb_define_singleton_method(mRCOV__, "install_coverage_hook", cov_install_coverage_hook, 0);
   rb_define_singleton_method(mRCOV__, "remove_coverage_hook",  cov_remove_coverage_hook, 0);
   rb_define_singleton_method(mRCOV__, "generate_coverage_info", cov_generate_coverage_info, 0);
   rb_define_singleton_method(mRCOV__, "reset_coverage", cov_reset_coverage, 0);
   rb_define_singleton_method(mRCOV__, "ABI", cov_ABI, 0);
-  
+
   Init_rcov_callsite();
 }
diff --git a/ext/rcovrt/1.9/callsite.c b/ext/rcovrt/1.9/callsite.c
deleted file mode 100644
index 4052647..0000000
--- a/ext/rcovrt/1.9/callsite.c
+++ /dev/null
@@ -1,234 +0,0 @@
-#include <ruby.h>
-#include <ruby/st.h>
-#include <stdlib.h>
-
-#define DEBUG 0
-
-static char callsite_hook_set_p;
-
-typedef struct {
-  const char *sourcefile;
-  unsigned int sourceline;
-  VALUE curr_meth;
-} type_def_site;       
-
-static VALUE caller_info = 0;
-static VALUE method_def_site_info = 0;
-
-static int caller_stack_len = 1;
-
-static VALUE record_callsite_info(VALUE args) {
-  VALUE caller_ary;
-  VALUE curr_meth;
-  VALUE count_hash;
-  VALUE count;
-  VALUE *pargs = (VALUE *)args;
-
-  caller_ary = pargs[0];
-  curr_meth = pargs[1];
-  count_hash = rb_hash_aref(caller_info, curr_meth);
-  
-  if(TYPE(count_hash) != T_HASH) { 
-    /* Qnil, anything else should be impossible unless somebody's been
-     * messing with ObjectSpace */
-    count_hash = rb_hash_new();
-    rb_hash_aset(caller_info, curr_meth, count_hash);
-  }
-  
-  count = rb_hash_aref(count_hash, caller_ary);
-  
-  if(count == Qnil) 
-    count = INT2FIX(0);
-  
-  count = INT2FIX(FIX2UINT(count) + 1);
-  rb_hash_aset(count_hash, caller_ary, count);
-
-  if(DEBUG == 1)
-    printf("CALLSITE: %s -> %s   %d\n", RSTRING_PTR(rb_inspect(curr_meth)), RSTRING_PTR(rb_inspect(caller_ary)), FIX2INT(count));
-
-  return Qnil;
-}
-
-static VALUE record_method_def_site(VALUE args) {
-  type_def_site *pargs = (type_def_site *)args;
-  VALUE def_site_info;
-
-  if( RTEST(rb_hash_aref(method_def_site_info, pargs->curr_meth)) )
-    return Qnil;
-  
-  def_site_info = rb_ary_new();
-  rb_ary_push(def_site_info, rb_str_new2(pargs->sourcefile));
-  rb_ary_push(def_site_info, INT2NUM(pargs->sourceline+1));
-  rb_hash_aset(method_def_site_info, pargs->curr_meth, def_site_info);
-
-  if(DEBUG == 1)
-    printf("DEFSITE: %s:%d  for %s\n", pargs->sourcefile, pargs->sourceline+1, RSTRING_PTR(rb_inspect(pargs->curr_meth)));
-  
-  return Qnil;
-}
-
-static VALUE callsite_custom_backtrace(int lev) {
-  ID id;
-  VALUE klass;
-  VALUE klass_path;
-  VALUE eval_string;
-  
-  rb_frame_method_id_and_class(&id, &klass);
-  
-  if (id == ID_ALLOCATOR)
-    return Qnil;
-  
-  if (klass) {
-    if (TYPE(klass) == T_ICLASS) {
-      klass = RBASIC(klass)->klass;
-    }
-    else if (FL_TEST(klass, FL_SINGLETON)) {
-      klass = rb_iv_get(klass, "__attached__");
-    }
-  }
-  // rb_sprintf("\"#<Class:%s>\"", RSTRING_PTR(klass_path))
-  
-  /*
-  klass = class << klass; self end unless klass === eval("self", binding)
-  */
-  
-  klass_path = rb_class_path(klass);
-  VALUE reciever = rb_funcall(rb_binding_new(), rb_intern("eval"), 1, rb_str_new2("self"));
-  
-  if (rb_funcall(klass, rb_intern("=="), 1, reciever) == Qtrue) {
-    klass_path = rb_sprintf("\"#<Class:%s>\"", RSTRING_PTR(klass_path));
-    OBJ_FREEZE(klass_path);
-  }
-  
-  eval_string = rb_sprintf("caller[%d, 1].map do |line|\nmd = /^([^:]*)(?::(\\d+)(?::in `(?:block in )?(.*)'))?/.match(line)\nraise \"Bad backtrace format\" unless md\n[%s, md[3] ? md[3].to_sym : nil, md[1], (md[2] || '').to_i]\nend", lev, RSTRING_PTR(klass_path));
-  return rb_eval_string(RSTRING_PTR(eval_string));
-}
-
-static void coverage_event_callsite_hook(rb_event_flag_t event, VALUE node,  VALUE self, ID mid, VALUE klass) {
-  VALUE caller_ary;
-  VALUE curr_meth;
-  VALUE args[2];
-  int status;
-
-  caller_ary = callsite_custom_backtrace(caller_stack_len);
-
-  VALUE klass_path;
-  curr_meth = rb_ary_new();
-   
-  rb_frame_method_id_and_class(&mid, &klass);
-  
-  if (mid == ID_ALLOCATOR)
-    return; //Qnil;
-  if (klass) {
-    if (TYPE(klass) == T_ICLASS) {
-      klass = RBASIC(klass)->klass;
-    }
-    else if (FL_TEST(klass, FL_SINGLETON)) {
-      klass = rb_iv_get(klass, "__attached__");
-    }
-  }
-  
-  /*
-  klass = class << klass; self end unless klass === eval("self", binding)
-  */
-  
-  klass_path = rb_class_path(klass);
-  VALUE reciever = rb_funcall(rb_binding_new(), rb_intern("eval"), 1, rb_str_new2("self"));
-
-  if (rb_funcall(klass, rb_intern("=="), 1, reciever) == Qtrue) {
-    klass_path = rb_sprintf("#<Class:%s>", RSTRING_PTR(klass_path));
-    OBJ_FREEZE(klass_path);
-  }
-    
-  rb_ary_push(curr_meth, klass_path);
-  rb_ary_push(curr_meth, ID2SYM(mid));
-
-  args[0] = caller_ary;
-  args[1] = curr_meth;
-  rb_protect(record_callsite_info, (VALUE)args, &status);
-
-  if(!status) {
-    type_def_site args;
-
-    args.sourcefile = rb_sourcefile();
-    args.sourceline = rb_sourceline();
-    args.curr_meth = curr_meth;
-    rb_protect(record_method_def_site, (VALUE)&args, NULL);
-  }
-
-  if(status)
-    rb_gv_set("$!", Qnil);
-}
-
-static VALUE cov_install_callsite_hook(VALUE self) {
-  if(!callsite_hook_set_p) {
-    if(TYPE(caller_info) != T_HASH)
-      caller_info = rb_hash_new();
-    callsite_hook_set_p = 1;
-    VALUE something = 0;
-    rb_add_event_hook(coverage_event_callsite_hook, 
-                      RUBY_EVENT_CALL, something);
-    return Qtrue;
-  } 
-  else
-    return Qfalse;
-}
-
-static VALUE cov_remove_callsite_hook(VALUE self) {
-  if(!callsite_hook_set_p) 
-    return Qfalse;
-  else {
-    rb_remove_event_hook(coverage_event_callsite_hook);
-    callsite_hook_set_p = 0;
-    return Qtrue;
-  }
-}
-
-static VALUE cov_generate_callsite_info(VALUE self) {
-  VALUE ret;
-
-  ret = rb_ary_new();
-  rb_ary_push(ret, caller_info);
-  rb_ary_push(ret, method_def_site_info);
-  return ret;
-}
-
-static VALUE cov_reset_callsite(VALUE self) {
-  if(callsite_hook_set_p) {
-    rb_raise(rb_eRuntimeError, "Cannot reset the callsite info in the middle of a traced run.");
-    return Qnil;
-  }
-  
-  caller_info = rb_hash_new();
-  method_def_site_info = rb_hash_new();
-  return Qnil;
-}
-
-void Init_rcov_callsite() {
-  VALUE mRcov;
-  VALUE mRCOV__;
-  ID id_rcov = rb_intern("Rcov");
-  ID id_coverage__ = rb_intern("RCOV__");
-  // ID id_script_lines__ = rb_intern("SCRIPT_LINES__");
-  
-  if(rb_const_defined(rb_cObject, id_rcov)) 
-    mRcov = rb_const_get(rb_cObject, id_rcov);
-  else
-    mRcov = rb_define_module("Rcov");
-  
-  if(rb_const_defined(mRcov, id_coverage__))
-    mRCOV__ = rb_const_get_at(mRcov, id_coverage__);
-  else
-    mRCOV__ = rb_define_module_under(mRcov, "RCOV__");
-
-  callsite_hook_set_p = 0;
-  caller_info = rb_hash_new();
-  method_def_site_info = rb_hash_new();
-  rb_gc_register_address(&caller_info);
-  rb_gc_register_address(&method_def_site_info);
-  
-  rb_define_singleton_method(mRCOV__, "install_callsite_hook", cov_install_callsite_hook, 0);
-  rb_define_singleton_method(mRCOV__, "remove_callsite_hook", cov_remove_callsite_hook, 0);
-  rb_define_singleton_method(mRCOV__, "generate_callsite_info", cov_generate_callsite_info, 0);
-  rb_define_singleton_method(mRCOV__, "reset_callsite", cov_reset_callsite, 0);
-}
diff --git a/ext/rcovrt/1.9/rcovrt.c b/ext/rcovrt/1.9/rcovrt.c
deleted file mode 100644
index 70da5e8..0000000
--- a/ext/rcovrt/1.9/rcovrt.c
+++ /dev/null
@@ -1,264 +0,0 @@
-#include <ruby.h>
-#include <ruby/st.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#define COVERAGE_DEBUG_EVENTS 0
-
-#define RCOVRT_VERSION_MAJOR 2
-#define RCOVRT_VERSION_MINOR 0
-#define RCOVRT_VERSION_REV   0
-
-static VALUE mRcov;
-static VALUE mRCOV__;
-static VALUE oSCRIPT_LINES__;
-static ID id_cover;
-static st_table* coverinfo = 0;
-static char coverage_hook_set_p;
-
-struct cov_array {
-  unsigned int len;
-  unsigned int *ptr;
-};
-
-static struct cov_array *cached_array = 0;
-static char *cached_file = 0; 
-
-static struct cov_array * coverage_increase_counter_uncached(char *sourcefile, unsigned int sourceline, char mark_only) {
-  struct cov_array *carray = NULL;
- 
-  if(sourcefile == NULL) {
-    /* "can't happen", just ignore and avoid segfault */
-    return NULL;
-  } 
-  else if(!st_lookup(coverinfo, (st_data_t)sourcefile, (st_data_t*)&carray)) {
-    VALUE arr;
-
-    arr = rb_hash_aref(oSCRIPT_LINES__, rb_str_new2(sourcefile));
-    if(NIL_P(arr)) 
-      return 0;
-    rb_check_type(arr, T_ARRAY);
-    carray = calloc(1, sizeof(struct cov_array));
-    carray->ptr = calloc(RARRAY_LEN(arr), sizeof(unsigned int));
-    carray->len = RARRAY_LEN(arr);
-    st_insert(coverinfo, (st_data_t)strdup(sourcefile), (st_data_t) carray);
-  } 
-  else {
-    /* recovered carray, sanity check */
-    assert(carray && "failed to create valid carray");
-  }
-
-  if(mark_only) {
-    if(!carray->ptr[sourceline])
-      carray->ptr[sourceline] = 1;
-  } 
-  else {
-    if (carray && carray->len > sourceline) {
-      carray->ptr[sourceline]++;
-    }
-  }
-
-  return carray;
-}
-
-static void coverage_mark_caller() {
-  coverage_increase_counter_uncached(rb_sourcefile(), rb_sourceline(), 1);
-}
-
-static void coverage_increase_counter_cached(char *sourcefile, int sourceline) {
-  if(cached_file == sourcefile && cached_array && cached_array->len > sourceline) {
-    cached_array->ptr[sourceline]++;
-    return;
-  }
-  cached_file = sourcefile;
-  cached_array = coverage_increase_counter_uncached(sourcefile, sourceline, 0);
-}
-
-static void coverage_event_coverage_hook(rb_event_flag_t event, VALUE node, VALUE self, ID mid, VALUE klass) {
-  char *sourcefile;
-  unsigned int sourceline;
-  static unsigned int in_hook = 0;
- 
-  if(in_hook) {
-    return;
-  }
-
-  in_hook++;
-
-  #if COVERAGE_DEBUG_EVENTS
-  do {
-    int status;
-    VALUE old_exception;
-    old_exception = rb_gv_get("$!");
-    rb_protect(rb_inspect, klass, &status);
-    if(!status) {
-      printf("EVENT: %d %s %s %s %d\n", event,
-             klass ? RSTRING(rb_inspect(klass))->ptr : "", 
-             mid ? (mid == ID_ALLOCATOR ? "ID_ALLOCATOR" : rb_id2name(mid))
-             : "unknown",
-             node ? node->nd_file : "", node ? nd_line(node) : 0);
-    } 
-    else {
-      printf("EVENT: %d %s %s %d\n", event,
-             mid ? (mid == ID_ALLOCATOR ? "ID_ALLOCATOR" : rb_id2name(mid)) 
-             : "unknown",
-             node ? node->nd_file : "", node ? nd_line(node) : 0);
-    }
-    rb_gv_set("$!", old_exception);
-  } while (0); 
-  #endif
-
-  if(event & RUBY_EVENT_C_CALL) {
-    coverage_mark_caller();
-  }
-  if(event & (RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN | RUBY_EVENT_CLASS)) {
-    in_hook--;
-    return;
-  }
-  
-  sourcefile = rb_sourcefile();
-  sourceline = rb_sourceline();
-  
-  if (0 == sourceline || 0 == sourcefile) {
-    in_hook--;
-    return;
-  }
-  
-  coverage_increase_counter_cached(sourcefile, sourceline);
-  if(event & RUBY_EVENT_CALL)
-    coverage_mark_caller();
-  in_hook--;
-}
-
-static VALUE cov_install_coverage_hook(VALUE self) {
-  if(!coverage_hook_set_p) {
-    if(!coverinfo)
-      coverinfo = st_init_strtable();
-    coverage_hook_set_p = 1;
-    /* TODO: allow C_CALL too, since it's supported already
-     * the overhead is around ~30%, tested on typo */
-    VALUE holder = 0;
-    rb_add_event_hook(coverage_event_coverage_hook, 
-                      RUBY_EVENT_ALL & ~RUBY_EVENT_C_CALL &
-                      ~RUBY_EVENT_C_RETURN & ~RUBY_EVENT_CLASS, holder);
-    return Qtrue;
-  }
-  else
-    return Qfalse;
-}
-
-static int populate_cover(st_data_t key, st_data_t value, st_data_t cover) {
-  VALUE rcover;
-  VALUE rkey;
-  VALUE rval;
-  struct cov_array *carray;
-  unsigned int i;
-  
-  rcover = (VALUE)cover;
-  carray = (struct cov_array *) value;
-  rkey = rb_str_new2((char*) key);
-  rval = rb_ary_new2(carray->len);
-  for(i = 0; i < carray->len; i++)
-    rb_ary_push(rval, UINT2NUM(carray->ptr[i]));
-  
-  rb_hash_aset(rcover, rkey, rval);
-  
-  return ST_CONTINUE;
-}
-
-static int free_table(st_data_t key, st_data_t value, st_data_t ignored) {
-  struct cov_array *carray;
-  
-  carray = (struct cov_array *) value;
-  free((char *)key);
-  free(carray->ptr);
-  free(carray);
-  
-  return ST_CONTINUE;
-}
-
-static VALUE cov_remove_coverage_hook(VALUE self) {
-  if(!coverage_hook_set_p) 
-    return Qfalse;
-  else {
-    rb_remove_event_hook(coverage_event_coverage_hook);
-    coverage_hook_set_p = 0;
-    return Qtrue;
-  }
-}
-
-static VALUE cov_generate_coverage_info(VALUE self) {
-  VALUE cover;
-
-  if(rb_const_defined_at(mRCOV__, id_cover)) {
-    rb_mod_remove_const(mRCOV__, ID2SYM(id_cover));
-  }
-
-  cover = rb_hash_new();
-  if(coverinfo)
-    st_foreach(coverinfo, populate_cover, cover);
-  rb_define_const(mRCOV__, "COVER", cover);
-
-  return cover;
-}
-
-static VALUE cov_reset_coverage(VALUE self) {
-  if(coverage_hook_set_p) {
-    rb_raise(rb_eRuntimeError, "Cannot reset the coverage info in the middle of a traced run.");
-    return Qnil;
-  }
-
-  cached_array = 0;
-  cached_file = 0;
-  st_foreach(coverinfo, free_table, Qnil); 
-  st_free_table(coverinfo);
-  coverinfo = 0;
-
-  return Qnil;
-}
-
-static VALUE cov_ABI(VALUE self) {
-  VALUE ret;
-
-  ret = rb_ary_new();
-  rb_ary_push(ret, INT2FIX(RCOVRT_VERSION_MAJOR));
-  rb_ary_push(ret, INT2FIX(RCOVRT_VERSION_MINOR));
-  rb_ary_push(ret, INT2FIX(RCOVRT_VERSION_REV));
-
-  return ret;
-}
-
-void Init_rcovrt() {
-  ID id_rcov = rb_intern("Rcov");
-  ID id_coverage__ = rb_intern("RCOV__");
-  ID id_script_lines__ = rb_intern("SCRIPT_LINES__");
-  
-  id_cover = rb_intern("COVER");
-  
-  if(rb_const_defined(rb_cObject, id_rcov)) 
-    mRcov = rb_const_get(rb_cObject, id_rcov);
-  else
-    mRcov = rb_define_module("Rcov");
-  
-  if(rb_const_defined(mRcov, id_coverage__))
-    mRCOV__ = rb_const_get_at(mRcov, id_coverage__);
-  else
-    mRCOV__ = rb_define_module_under(mRcov, "RCOV__");
-  
-  if(rb_const_defined(rb_cObject, id_script_lines__))
-    oSCRIPT_LINES__ = rb_const_get(rb_cObject, rb_intern("SCRIPT_LINES__"));
-  else {
-    oSCRIPT_LINES__ = rb_hash_new();
-    rb_const_set(rb_cObject, id_script_lines__, oSCRIPT_LINES__);
-  }
-  
-  coverage_hook_set_p = 0;
-  
-  rb_define_singleton_method(mRCOV__, "install_coverage_hook", cov_install_coverage_hook, 0);
-  rb_define_singleton_method(mRCOV__, "remove_coverage_hook", cov_remove_coverage_hook, 0);
-  rb_define_singleton_method(mRCOV__, "generate_coverage_info", cov_generate_coverage_info, 0);
-  rb_define_singleton_method(mRCOV__, "reset_coverage", cov_reset_coverage, 0);
-  rb_define_singleton_method(mRCOV__, "ABI", cov_ABI, 0);
-  
-  Init_rcov_callsite();
-}
diff --git a/ext/rcovrt/extconf.rb b/ext/rcovrt/extconf.rb
index 137977e..0a9c634 100644
--- a/ext/rcovrt/extconf.rb
+++ b/ext/rcovrt/extconf.rb
@@ -1,3 +1,8 @@
+if RUBY_VERSION =~ /1.9/
+  puts "**** Ruby 1.9 is not supported. Please switch to simplecov ****"
+  Kernel.exit 1
+end
+
 require 'mkmf'
 
 dir_config("gcov")
@@ -5,17 +10,7 @@ if ENV["USE_GCOV"] and Config::CONFIG['CC'] =~ /gcc/ and
   have_library("gcov", "__gcov_open")
 
   $CFLAGS << " -fprofile-arcs -ftest-coverage"
-  if RUBY_VERSION =~ /1.9/
-    $CFLAGS << ' -DRUBY_19_COMPATIBILITY'
-    create_makefile("rcovrt", "1.9/")
-  else
-    create_makefile("rcovrt", "1.8/")
-  end
+  create_makefile("rcovrt", "1.8/")
 else
-  if RUBY_VERSION =~ /1.9/
-    $CFLAGS << ' -DRUBY_19_COMPATIBILITY'
-    create_makefile("rcovrt", "1.9/")
-  else
-    create_makefile("rcovrt", "1.8/")
-  end
+  create_makefile("rcovrt", "1.8/")
 end
diff --git a/lib/rcov/formatters/html_erb_template.rb b/lib/rcov/formatters/html_erb_template.rb
index 5aa8b45..072d572 100644
--- a/lib/rcov/formatters/html_erb_template.rb
+++ b/lib/rcov/formatters/html_erb_template.rb
@@ -19,10 +19,10 @@ module Rcov
       end
 
       def coverage_threshold_classes(percentage)
-        return 110 if percentage == 100
-        return (1..10).find_all{|i| i * 10 > percentage}.map{|i| i.to_i * 10} * " " 
+        return '_110' if percentage == 100
+        return (1..10).find_all{|i| i * 10 > percentage}.map{|i| "_#{i*10}"} * " "
       end
-      
+
       def code_coverage_html(code_coverage_percentage, is_total=false)
         %{<div class="percent_graph_legend"><tt class='#{ is_total ? 'coverage_total' : ''}'>#{ "%3.2f" % code_coverage_percentage }%</tt></div>
           <div class="percent_graph">
@@ -34,11 +34,11 @@ module Rcov
       def file_filter_classes(file_path)
         file_path.split('/')[0..-2] * " "
       end
-      
+
       def relative_filename(path)
         @path_relativizer[path]
       end
-    
+
       def line_css(line_number)
         case fileinfo.coverage[line_number]
         when true
@@ -55,8 +55,8 @@ module Rcov
       end
 
       def get_binding
-        binding 
+        binding
       end
     end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rcov/formatters/html_profiling.rb b/lib/rcov/formatters/html_profiling.rb
new file mode 100644
index 0000000..2f3fded
--- /dev/null
+++ b/lib/rcov/formatters/html_profiling.rb
@@ -0,0 +1,51 @@
+module Rcov
+  module Formatters
+    class HTMLProfiling < HTMLCoverage
+      DEFAULT_OPTS = { :destdir => "profiling" }
+
+      def initialize(opts = {})
+        options = DEFAULT_OPTS.clone.update(opts)
+        super(options)
+        @max_cache = {}
+        @median_cache = {}
+      end
+
+      def default_title
+        "Bogo-profile information"
+      end
+
+      def default_color
+        if @color
+          "rgb(179,205,255)"
+        else
+          "rgb(255, 255, 255)"
+        end
+      end
+
+      def output_color_table?
+        false
+      end
+
+      def span_class(sourceinfo, marked, count)
+        full_scale_range = @fsr # dB
+        nz_count = sourceinfo.counts.select{ |x| x && x != 0 }
+        nz_count << 1 # avoid div by 0
+        max = @max_cache[sourceinfo] ||= nz_count.max
+        median = @median_cache[sourceinfo] ||= 1.0 * nz_count.sort[nz_count.size/2]
+        max ||= 2
+        max = 2 if max == 1
+
+        if marked == true
+          count = 1 if !count || count == 0
+          idx = 50 + 1.0 * (500/full_scale_range) * Math.log(count/median) / Math.log(10)
+          idx = idx.to_i
+          idx = 0 if idx < 0
+          idx = 100 if idx > 100
+          "run#{idx}"
+        else
+          nil
+        end
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/rcov/formatters/ruby_annotation.rb b/lib/rcov/formatters/ruby_annotation.rb
new file mode 100644
index 0000000..8f716e5
--- /dev/null
+++ b/lib/rcov/formatters/ruby_annotation.rb
@@ -0,0 +1,110 @@
+module Rcov
+  module Formatters
+    class RubyAnnotation < BaseFormatter
+      DEFAULT_OPTS = { :destdir => "coverage" }
+
+      def initialize(opts = {})
+        options = DEFAULT_OPTS.clone.update(opts)
+        super(options)
+        @dest = options[:destdir]
+        @do_callsites = true
+        @do_cross_references = true
+        @mangle_filename = Hash.new{|h,base|
+          h[base] = Pathname.new(base).cleanpath.to_s.gsub(%r{^\w:[/\\]}, "").gsub(/\./, "_").gsub(/[\\\/]/, "-") + ".rb"
+        }
+      end
+
+      def execute
+        return if @files.empty?
+        FileUtils.mkdir_p @dest
+        each_file_pair_sorted do |filename, fileinfo|
+          create_file(File.join(@dest, mangle_filename(filename)), fileinfo)
+        end
+      end
+
+      private
+
+      def format_lines(file)
+        result = ""
+        format_line = "%#{file.num_lines.to_s.size}d"
+        file.num_lines.times do |i|
+          line = file.lines[i].chomp
+          marked = file.coverage[i]
+          count = file.counts[i]
+          result << create_cross_refs(file.name, i+1, line, marked) + "\n"
+        end
+        result
+      end
+
+      def create_cross_refs(filename, lineno, linetext, marked)
+        return linetext unless @callsite_analyzer && @do_callsites
+        ref_blocks = []
+        _get_defsites(ref_blocks, filename, lineno, linetext, ">>") do |ref|
+          if ref.file
+            ref.file.sub!(%r!^./!, '')
+            where = "at #{mangle_filename(ref.file)}:#{ref.line}"
+          else
+            where = "(C extension/core)"
+          end
+          "#{ref.klass}##{ref.mid} " + where + ""
+        end
+        _get_callsites(ref_blocks, filename, lineno, linetext, "<<") do |ref| # "
+          ref.file.sub!(%r!^./!, '')
+          "#{mangle_filename(ref.file||'C code')}:#{ref.line} " +
+          "in #{ref.klass}##{ref.mid}"
+        end
+
+        create_cross_reference_block(linetext, ref_blocks, marked)
+      end
+
+      def create_cross_reference_block(linetext, ref_blocks, marked)
+        codelen = 75
+        if ref_blocks.empty?
+          if marked
+            return "%-#{codelen}s #o" % linetext
+          else
+            return linetext
+          end
+        end
+        ret = ""
+        @cross_ref_idx ||= 0
+        @known_files ||= sorted_file_pairs.map{|fname, finfo| normalize_filename(fname)}
+        ret << "%-#{codelen}s # " % linetext
+        ref_blocks.each do |refs, toplabel, label_proc|
+          unless !toplabel || toplabel.empty?
+            ret << toplabel << " "
+          end
+          refs.each do |dst|
+            dstfile = normalize_filename(dst.file) if dst.file
+            dstline = dst.line
+            label = label_proc.call(dst)
+            if dst.file && @known_files.include?(dstfile)
+              ret << "[[" << label << "]], "
+            else
+              ret << label << ", "
+            end
+          end
+        end
+
+        ret
+      end
+
+      def create_file(destfile, fileinfo)
+        #body = format_lines(fileinfo)
+        #File.open(destfile, "w") do |f|
+        #f.puts body
+        #f.puts footer(fileinfo)
+        #end
+      end
+
+      def footer(fileinfo)
+        s  = "# Total lines    : %d\n" % fileinfo.num_lines
+        s << "# Lines of code  : %d\n" % fileinfo.num_code_lines
+        s << "# Total coverage : %3.1f%%\n" % [ fileinfo.total_coverage*100 ]
+        s << "# Code coverage  : %3.1f%%\n\n" % [ fileinfo.code_coverage*100 ]
+        # prevents false positives on Emacs
+        s << "# Local " "Variables:\n" "# mode: " "rcov-xref\n" "# End:\n"
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/rcov/templates/detail.html.erb b/lib/rcov/templates/detail.html.erb
index 77ba11c..c080671 100644
--- a/lib/rcov/templates/detail.html.erb
+++ b/lib/rcov/templates/detail.html.erb
@@ -39,9 +39,9 @@
         </tbody>
       </table>
     </div>
-    
+
     <h3>Key</h3>
-    
+
     <div class="key"><pre><span class='marked'>Code reported as executed by Ruby looks like this...</span><span class='marked1'>and this: this line is also marked as covered.</span><span class='inferred'>Lines considered as run by rcov, but not reported by Ruby, look like this,</span><span class='inferred1'>and this: these lines were inferred by rcov (using simple heuristics).</span><span class='uncovered'>Finally, here's a line marked as not executed.</span></pre></div>
 
     <h3>Coverage Details</h3>
@@ -51,8 +51,9 @@
         <% fileinfo.num_lines.times do |i| %>
           <% line = fileinfo.lines[i].chomp %>
           <% count = fileinfo.counts[i] %>
+          <% width = fileinfo.num_lines.to_s.length %>
           <tr class="<%= line_css(i) %>">
-            <td><pre><a name="line<%= i.next %>"><%= i.next %></a> <%= CGI::escapeHTML(line) %></pre></td>
+            <td><pre><a name="line<%= i.next %>"><%= i.next.to_s.rjust(width) %></a> <%= CGI::escapeHTML(line) %></pre></td>
           </tr>
         <% end %>
       </tbody>
diff --git a/lib/rcov/templates/index.html.erb b/lib/rcov/templates/index.html.erb
index 30942a4..c003565 100644
--- a/lib/rcov/templates/index.html.erb
+++ b/lib/rcov/templates/index.html.erb
@@ -31,12 +31,12 @@
         <label>Code Coverage Threshold:</label>
         <select id="coverage_filter" class="filter">
           <option value="all_coverage">Show All</option>
-          <% (1..10).each do |i| %><option value="<%= i * 10 %>">< <%= i * 10 %>% Coverage</option><% end %>
-          <option value="110">= 100% Coverage</option>
+          <% (1..10).each do |i| %><option value="_<%= i * 10 %>">< <%= i * 10 %>% Coverage</option><% end %>
+          <option value="_110">= 100% Coverage</option>
         </select>
       </fieldset>
     </div>
-    
+
     <div class="report_table_wrapper">
       <table class='report' id='report_table'>
         <thead>
@@ -70,22 +70,26 @@
         </tbody>
       </table>
     </div>
-    
+
     <p>Generated on <%= generated_on %> with <a href="<%= rcov::UPSTREAM_URL %>">rcov <%= rcov::VERSION %></a></p>
 
     <script type="text/javascript">
-      $(document).ready(function(){$("#report_table").tablesorter({widgets: ['zebra'], textExtraction: 'complex'});});
+      $(document).ready(function(){
+          $("#report_table").tablesorter({widgets: ['zebra'], textExtraction: 'complex'});
+        }
+      );
       $('.filter').change(function(){
-        ff = $('#file_filter').val();
-        cf = $('#coverage_filter').val();
-        $('table#report_table tbody tr').each(function(i){ 
-          if ((this.className.split(" ").indexOf(ff) > -1) && (this.className.split(" ").indexOf(cf) > -1)) {
-            this.style.display = "";
-          } else {
-            this.style.display = "none";
-          };
+        ff = '.' + $('#file_filter').val();
+        cf = '.' + $('#coverage_filter').val();
+        rows = 'table#report_table tbody tr';
+        // Hide all rows that don't match the filters
+        $(rows).not(cf).map(function() { $(this).hide(); });
+        $(rows).not(ff).map(function() { $(this).hide(); });
+        // Show and restripe all rows that match both filters
+        $(rows).filter(cf).filter(ff).each(function() {
+          $(this).show();
           restripe();
-        })
+        });
       })
     </script>
 
diff --git a/lib/rcov/version.rb b/lib/rcov/version.rb
index ba38ae7..fe29e03 100644
--- a/lib/rcov/version.rb
+++ b/lib/rcov/version.rb
@@ -1,10 +1,6 @@
-# rcov Copyright (c) 2004-2006 Mauricio Fernandez <mfp at acm.org>
-#
-# See LICENSE for licensing information.
-
 module Rcov
-  VERSION = "0.9.11"
-  RELEASE_DATE = "2010-02-28"
+  VERSION = "1.0.0"
+  RELEASE_DATE = "2012-02-01"
   RCOVRT_ABI = [2,0,0]
   UPSTREAM_URL = "http://github.com/relevance/rcov"
 end
diff --git a/metadata.yml b/metadata.yml
deleted file mode 100644
index 24186db..0000000
--- a/metadata.yml
+++ /dev/null
@@ -1,140 +0,0 @@
---- !ruby/object:Gem::Specification 
-name: rcov
-version: !ruby/object:Gem::Version 
-  hash: 45
-  prerelease: false
-  segments: 
-  - 0
-  - 9
-  - 11
-  version: 0.9.11
-platform: ruby
-authors: 
-- Relevance
-- Chad Humphries (spicycode)
-- Aaron Bedra (abedra)
-- Jay McGaffigan(hooligan495)
-- Mauricio Fernandez
-autorequire: 
-bindir: bin
-cert_chain: 
-date: 2009-12-29 00:00:00 -05:00
-default_executable: 
-dependencies: []
-
-description: rcov is a code coverage tool for Ruby. It is commonly used for viewing overall test unit coverage of target code.  It features fast execution (20-300 times faster than previous tools), multiple analysis modes, XHTML and several kinds of text reports, easy automation with Rake via a RcovTask, fairly accurate coverage information through code linkage inference using simple heuristics, colorblind-friendliness...
-email: opensource at thinkrelevance.com
-executables: 
-- rcov
-extensions: 
-- ext/rcovrt/extconf.rb
-extra_rdoc_files: []
-
-files: 
-- bin/rcov
-- lib/rcov.rb
-- lib/rcov/lowlevel.rb
-- lib/rcov/version.rb
-- lib/rcov/rcovtask.rb
-- lib/rcov/formatters.rb
-- lib/rcov/call_site_analyzer.rb
-- lib/rcov/code_coverage_analyzer.rb
-- lib/rcov/coverage_info.rb
-- lib/rcov/differential_analyzer.rb
-- lib/rcov/file_statistics.rb
-- lib/rcov/formatters/base_formatter.rb
-- lib/rcov/formatters/full_text_report.rb
-- lib/rcov/formatters/html_erb_template.rb
-- lib/rcov/formatters/html_coverage.rb
-- lib/rcov/formatters/text_coverage_diff.rb
-- lib/rcov/formatters/text_report.rb
-- lib/rcov/formatters/text_summary.rb
-- lib/rcov/formatters/failure_report.rb
-- lib/rcov/templates/index.html.erb
-- lib/rcov/templates/detail.html.erb
-- lib/rcov/templates/screen.css
-- lib/rcov/templates/print.css
-- lib/rcov/templates/rcov.js
-- lib/rcov/templates/jquery-1.3.2.min.js
-- lib/rcov/templates/jquery.tablesorter.min.js
-- ext/rcovrt/extconf.rb
-- ext/rcovrt/1.8/rcovrt.c
-- ext/rcovrt/1.9/rcovrt.c
-- ext/rcovrt/1.8/callsite.c
-- ext/rcovrt/1.9/callsite.c
-- LICENSE
-- Rakefile
-- doc/readme_for_rake.markdown
-- doc/readme_for_vim.markdown
-- doc/readme_for_emacs.markdown
-- doc/readme_for_api.markdown
-- THANKS
-- test/functional_test.rb
-- test/file_statistics_test.rb
-- test/assets/sample_03.rb
-- test/assets/sample_05-new.rb
-- test/code_coverage_analyzer_test.rb
-- test/assets/sample_04.rb
-- test/assets/sample_02.rb
-- test/assets/sample_05-old.rb
-- test/assets/sample_01.rb
-- test/turn_off_rcovrt.rb
-- test/call_site_analyzer_test.rb
-- test/assets/sample_05.rb
-- test/assets/sample_06.rb
-- editor-extensions/rcov.vim
-- test/test_helper.rb
-- test/expected_coverage/diff-gcc-all.out
-- test/expected_coverage/diff-gcc-diff.out
-- test/expected_coverage/diff-gcc-original.out
-- test/expected_coverage/diff-no-color.out
-- test/expected_coverage/diff.out
-- test/expected_coverage/gcc-text.out
-- test/expected_coverage/sample_03_rb.html
-- test/expected_coverage/sample_03_rb.rb
-- test/expected_coverage/sample_04_rb.html
-- editor-extensions/rcov.el
-- setup.rb
-- BLURB
-has_rdoc: true
-homepage: http://github.com/relevance/rcov
-licenses: []
-
-post_install_message: 
-rdoc_options: 
-- --title
-- rcov code coverage tool
-require_paths: 
-- lib
-required_ruby_version: !ruby/object:Gem::Requirement 
-  none: false
-  requirements: 
-  - - ">"
-    - !ruby/object:Gem::Version 
-      hash: 31
-      segments: 
-      - 0
-      - 0
-      - 0
-      version: 0.0.0
-required_rubygems_version: !ruby/object:Gem::Requirement 
-  none: false
-  requirements: 
-  - - ">="
-    - !ruby/object:Gem::Version 
-      hash: 3
-      segments: 
-      - 0
-      version: "0"
-requirements: []
-
-rubyforge_project: 
-rubygems_version: 1.3.7
-signing_key: 
-specification_version: 1
-summary: Code coverage analysis tool for Ruby
-test_files: 
-- test/functional_test.rb
-- test/file_statistics_test.rb
-- test/code_coverage_analyzer_test.rb
-- test/call_site_analyzer_test.rb
diff --git a/rcov-java.gemspec b/rcov-java.gemspec
new file mode 100644
index 0000000..2c725fa
--- /dev/null
+++ b/rcov-java.gemspec
@@ -0,0 +1,36 @@
+$:.push File.expand_path("../lib", __FILE__)
+require "rcov/version"
+
+Gem::Specification.new do |s|
+  s.name = %q{rcov}
+  s.version = Rcov::VERSION
+  s.required_rubygems_version = nil if s.respond_to? :required_rubygems_version=
+    s.authors = ["Relevance",
+                 "Chad Humphries (spicycode)",
+                 "Aaron Bedra (abedra)",
+                 "Jay McGaffigan(hooligan495)",
+                 "Mauricio Fernandez"]
+  s.date = %q{2012-02-01}
+  s.description = %q{rcov is a code coverage tool for Ruby.}
+  s.email = %q{aaron at aaronbedra.com}
+  s.files = Dir.glob('lib/**/*.rb') + Dir.glob('ext/java/**/*.java')
+  s.extensions = ["ext/rcovrt/extconf.rb"]
+  s.executables = ["rcov"]
+  s.homepage = %q{http://github.com/relevance/rcov}
+  s.rdoc_options = ["--title", "rcov code coverage tool"]
+  s.require_paths = ["lib"]
+  s.required_ruby_version = Gem::Requirement.new("> 0.0.0")
+  s.summary = %q{Code coverage analysis tool for Ruby}
+  s.test_files = ["test/functional_test.rb",
+                  "test/file_statistics_test.rb",
+                  "test/code_coverage_analyzer_test.rb",
+                  "test/call_site_analyzer_test.rb"]
+  if s.respond_to? :specification_version then
+    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+    s.specification_version = 1
+    if current_version >= 3 then
+    else
+    end
+  else
+  end
+end
diff --git a/rcov.gemspec b/rcov.gemspec
new file mode 100644
index 0000000..57634c5
--- /dev/null
+++ b/rcov.gemspec
@@ -0,0 +1,23 @@
+$:.push File.expand_path("../lib", __FILE__)
+require "rcov/version"
+
+Gem::Specification.new do |s|
+  s.name = %q{rcov}
+  s.summary = %q{Code coverage analysis tool for Ruby}
+  s.description = %q{rcov is a code coverage tool for Ruby.}
+  s.version = Rcov::VERSION
+  s.date = %q{2012-02-01}
+  s.homepage = %q{http://github.com/relevance/rcov}
+  s.authors = ["Aaron Bedra (abedra)",
+               "Chad Humphries (spicycode)",
+               "Jay McGaffigan(hooligan495)",
+               "Relevance Inc",
+               "Mauricio Fernandez"]
+  s.email = %q{aaron at aaronbedra.com}
+  s.files = Dir.glob('lib/**/*.rb') + Dir.glob('lib/rcov/templates/*') + Dir.glob('ext/rcovrt/**/*.{c,h,rb}')
+  s.extensions = ["ext/rcovrt/extconf.rb"]
+  s.executables = ["rcov"]
+  s.require_paths = ["lib"]
+  s.rdoc_options = ["--title", "rcov code coverage tool"]
+  s.add_development_dependency 'rake', '~> 0.9.2'
+end
diff --git a/setup.rb b/setup.rb
deleted file mode 100644
index 279aa34..0000000
--- a/setup.rb
+++ /dev/null
@@ -1,1588 +0,0 @@
-#
-# setup.rb
-#
-# Copyright (c) 2000-2005 Minero Aoki
-#
-# This program is free software.
-# You can distribute/modify this program under the terms of
-# the GNU LGPL, Lesser General Public License version 2.1.
-#
-
-unless Enumerable.method_defined?(:map)   # Ruby 1.4.6
-  module Enumerable
-    alias map collect
-  end
-end
-
-unless File.respond_to?(:read)   # Ruby 1.6
-  def File.read(fname)
-    open(fname) {|f|
-      return f.read
-    }
-  end
-end
-
-unless Errno.const_defined?(:ENOTEMPTY)   # Windows?
-  module Errno
-    class ENOTEMPTY
-      # We do not raise this exception, implementation is not needed.
-    end
-  end
-end
-
-def File.binread(fname)
-  open(fname, 'rb') {|f|
-    return f.read
-  }
-end
-
-# for corrupted Windows' stat(2)
-def File.dir?(path)
-  File.directory?((path[-1,1] == '/') ? path : path + '/')
-end
-
-
-class ConfigTable
-
-  include Enumerable
-
-  def initialize(rbconfig)
-    @rbconfig = rbconfig
-    @items = []
-    @table = {}
-    # options
-    @install_prefix = nil
-    @config_opt = nil
-    @verbose = true
-    @no_harm = false
-  end
-
-  attr_accessor :install_prefix
-  attr_accessor :config_opt
-
-  attr_writer :verbose
-
-  def verbose?
-    @verbose
-  end
-
-  attr_writer :no_harm
-
-  def no_harm?
-    @no_harm
-  end
-
-  def [](key)
-    lookup(key).resolve(self)
-  end
-
-  def []=(key, val)
-    lookup(key).set val
-  end
-
-  def names
-    @items.map {|i| i.name }
-  end
-
-  def each(&block)
-    @items.each(&block)
-  end
-
-  def key?(name)
-    @table.key?(name)
-  end
-
-  def lookup(name)
-    @table[name] or setup_rb_error "no such config item: #{name}"
-  end
-
-  def add(item)
-    @items.push item
-    @table[item.name] = item
-  end
-
-  def remove(name)
-    item = lookup(name)
-    @items.delete_if {|i| i.name == name }
-    @table.delete_if {|name, i| i.name == name }
-    item
-  end
-
-  def load_script(path, inst = nil)
-    if File.file?(path)
-      MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
-    end
-  end
-
-  def savefile
-    '.config'
-  end
-
-  def load_savefile
-    begin
-      File.foreach(savefile()) do |line|
-        k, v = *line.split(/=/, 2)
-        self[k] = v.strip
-      end
-    rescue Errno::ENOENT
-      setup_rb_error $!.message + "\n#{File.basename($0)} config first"
-    end
-  end
-
-  def save
-    @items.each {|i| i.value }
-    File.open(savefile(), 'w') {|f|
-      @items.each do |i|
-        f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
-      end
-    }
-  end
-
-  def load_standard_entries
-    standard_entries(@rbconfig).each do |ent|
-      add ent
-    end
-  end
-
-  def standard_entries(rbconfig)
-    c = rbconfig
-
-    rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
-
-    major = c['MAJOR'].to_i
-    minor = c['MINOR'].to_i
-    teeny = c['TEENY'].to_i
-    version = "#{major}.#{minor}"
-
-    # ruby ver. >= 1.4.4?
-    newpath_p = ((major >= 2) or
-                 ((major == 1) and
-                  ((minor >= 5) or
-                   ((minor == 4) and (teeny >= 4)))))
-
-    if c['rubylibdir']
-      # V > 1.6.3
-      libruby         = "#{c['prefix']}/lib/ruby"
-      librubyver      = c['rubylibdir']
-      librubyverarch  = c['archdir']
-      siteruby        = c['sitedir']
-      siterubyver     = c['sitelibdir']
-      siterubyverarch = c['sitearchdir']
-    elsif newpath_p
-      # 1.4.4 <= V <= 1.6.3
-      libruby         = "#{c['prefix']}/lib/ruby"
-      librubyver      = "#{c['prefix']}/lib/ruby/#{version}"
-      librubyverarch  = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
-      siteruby        = c['sitedir']
-      siterubyver     = "$siteruby/#{version}"
-      siterubyverarch = "$siterubyver/#{c['arch']}"
-    else
-      # V < 1.4.4
-      libruby         = "#{c['prefix']}/lib/ruby"
-      librubyver      = "#{c['prefix']}/lib/ruby/#{version}"
-      librubyverarch  = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
-      siteruby        = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
-      siterubyver     = siteruby
-      siterubyverarch = "$siterubyver/#{c['arch']}"
-    end
-    parameterize = lambda {|path|
-      path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
-    }
-
-    if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
-      makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
-    else
-      makeprog = 'make'
-    end
-
-    [
-      ExecItem.new('installdirs', 'std/site/home',
-                   'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
-          {|val, table|
-            case val
-            when 'std'
-              table['rbdir'] = '$librubyver'
-              table['sodir'] = '$librubyverarch'
-            when 'site'
-              table['rbdir'] = '$siterubyver'
-              table['sodir'] = '$siterubyverarch'
-            when 'home'
-              setup_rb_error '$HOME was not set' unless ENV['HOME']
-              table['prefix'] = ENV['HOME']
-              table['rbdir'] = '$libdir/ruby'
-              table['sodir'] = '$libdir/ruby'
-            end
-          },
-      PathItem.new('prefix', 'path', c['prefix'],
-                   'path prefix of target environment'),
-      PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
-                   'the directory for commands'),
-      PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
-                   'the directory for libraries'),
-      PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
-                   'the directory for shared data'),
-      PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
-                   'the directory for man pages'),
-      PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
-                   'the directory for system configuration files'),
-      PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
-                   'the directory for local state data'),
-      PathItem.new('libruby', 'path', libruby,
-                   'the directory for ruby libraries'),
-      PathItem.new('librubyver', 'path', librubyver,
-                   'the directory for standard ruby libraries'),
-      PathItem.new('librubyverarch', 'path', librubyverarch,
-                   'the directory for standard ruby extensions'),
-      PathItem.new('siteruby', 'path', siteruby,
-          'the directory for version-independent aux ruby libraries'),
-      PathItem.new('siterubyver', 'path', siterubyver,
-                   'the directory for aux ruby libraries'),
-      PathItem.new('siterubyverarch', 'path', siterubyverarch,
-                   'the directory for aux ruby binaries'),
-      PathItem.new('rbdir', 'path', '$siterubyver',
-                   'the directory for ruby scripts'),
-      PathItem.new('sodir', 'path', '$siterubyverarch',
-                   'the directory for ruby extentions'),
-      PathItem.new('rubypath', 'path', rubypath,
-                   'the path to set to #! line'),
-      ProgramItem.new('rubyprog', 'name', rubypath,
-                      'the ruby program using for installation'),
-      ProgramItem.new('makeprog', 'name', makeprog,
-                      'the make program to compile ruby extentions'),
-      SelectItem.new('shebang', 'all/ruby/never', 'ruby',
-                     'shebang line (#!) editing mode'),
-      BoolItem.new('without-ext', 'yes/no', 'no',
-                   'does not compile/install ruby extentions')
-    ]
-  end
-  private :standard_entries
-
-  def load_multipackage_entries
-    multipackage_entries().each do |ent|
-      add ent
-    end
-  end
-
-  def multipackage_entries
-    [
-      PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
-                               'package names that you want to install'),
-      PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
-                               'package names that you do not want to install')
-    ]
-  end
-  private :multipackage_entries
-
-  ALIASES = {
-    'std-ruby'         => 'librubyver',
-    'stdruby'          => 'librubyver',
-    'rubylibdir'       => 'librubyver',
-    'archdir'          => 'librubyverarch',
-    'site-ruby-common' => 'siteruby',     # For backward compatibility
-    'site-ruby'        => 'siterubyver',  # For backward compatibility
-    'bin-dir'          => 'bindir',
-    'bin-dir'          => 'bindir',
-    'rb-dir'           => 'rbdir',
-    'so-dir'           => 'sodir',
-    'data-dir'         => 'datadir',
-    'ruby-path'        => 'rubypath',
-    'ruby-prog'        => 'rubyprog',
-    'ruby'             => 'rubyprog',
-    'make-prog'        => 'makeprog',
-    'make'             => 'makeprog'
-  }
-
-  def fixup
-    ALIASES.each do |ali, name|
-      @table[ali] = @table[name]
-    end
-    @items.freeze
-    @table.freeze
-    @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
-  end
-
-  def parse_opt(opt)
-    m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
-    m.to_a[1,2]
-  end
-
-  def dllext
-    @rbconfig['DLEXT']
-  end
-
-  def value_config?(name)
-    lookup(name).value?
-  end
-
-  class Item
-    def initialize(name, template, default, desc)
-      @name = name.freeze
-      @template = template
-      @value = default
-      @default = default
-      @description = desc
-    end
-
-    attr_reader :name
-    attr_reader :description
-
-    attr_accessor :default
-    alias help_default default
-
-    def help_opt
-      "--#{@name}=#{@template}"
-    end
-
-    def value?
-      true
-    end
-
-    def value
-      @value
-    end
-
-    def resolve(table)
-      @value.gsub(%r<\$([^/]+)>) { table[$1] }
-    end
-
-    def set(val)
-      @value = check(val)
-    end
-
-    private
-
-    def check(val)
-      setup_rb_error "config: --#{name} requires argument" unless val
-      val
-    end
-  end
-
-  class BoolItem < Item
-    def config_type
-      'bool'
-    end
-
-    def help_opt
-      "--#{@name}"
-    end
-
-    private
-
-    def check(val)
-      return 'yes' unless val
-      case val
-      when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
-      when /\An(o)?\z/i, /\Af(alse)\z/i  then 'no'
-      else
-        setup_rb_error "config: --#{@name} accepts only yes/no for argument"
-      end
-    end
-  end
-
-  class PathItem < Item
-    def config_type
-      'path'
-    end
-
-    private
-
-    def check(path)
-      setup_rb_error "config: --#{@name} requires argument"  unless path
-      path[0,1] == '$' ? path : File.expand_path(path)
-    end
-  end
-
-  class ProgramItem < Item
-    def config_type
-      'program'
-    end
-  end
-
-  class SelectItem < Item
-    def initialize(name, selection, default, desc)
-      super
-      @ok = selection.split('/')
-    end
-
-    def config_type
-      'select'
-    end
-
-    private
-
-    def check(val)
-      unless @ok.include?(val.strip)
-        setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
-      end
-      val.strip
-    end
-  end
-
-  class ExecItem < Item
-    def initialize(name, selection, desc, &block)
-      super name, selection, nil, desc
-      @ok = selection.split('/')
-      @action = block
-    end
-
-    def config_type
-      'exec'
-    end
-
-    def value?
-      false
-    end
-
-    def resolve(table)
-      setup_rb_error "$#{name()} wrongly used as option value"
-    end
-
-    undef set
-
-    def evaluate(val, table)
-      v = val.strip.downcase
-      unless @ok.include?(v)
-        setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
-      end
-      @action.call v, table
-    end
-  end
-
-  class PackageSelectionItem < Item
-    def initialize(name, template, default, help_default, desc)
-      super name, template, default, desc
-      @help_default = help_default
-    end
-
-    attr_reader :help_default
-
-    def config_type
-      'package'
-    end
-
-    private
-
-    def check(val)
-      unless File.dir?("packages/#{val}")
-        setup_rb_error "config: no such package: #{val}"
-      end
-      val
-    end
-  end
-
-  class MetaConfigEnvironment
-    def initialize(config, installer)
-      @config = config
-      @installer = installer
-    end
-
-    def config_names
-      @config.names
-    end
-
-    def config?(name)
-      @config.key?(name)
-    end
-
-    def bool_config?(name)
-      @config.lookup(name).config_type == 'bool'
-    end
-
-    def path_config?(name)
-      @config.lookup(name).config_type == 'path'
-    end
-
-    def value_config?(name)
-      @config.lookup(name).config_type != 'exec'
-    end
-
-    def add_config(item)
-      @config.add item
-    end
-
-    def add_bool_config(name, default, desc)
-      @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
-    end
-
-    def add_path_config(name, default, desc)
-      @config.add PathItem.new(name, 'path', default, desc)
-    end
-
-    def set_config_default(name, default)
-      @config.lookup(name).default = default
-    end
-
-    def remove_config(name)
-      @config.remove(name)
-    end
-
-    # For only multipackage
-    def packages
-      raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
-      @installer.packages
-    end
-
-    # For only multipackage
-    def declare_packages(list)
-      raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
-      @installer.packages = list
-    end
-  end
-
-end   # class ConfigTable
-
-
-# This module requires: #verbose?, #no_harm?
-module FileOperations
-
-  def mkdir_p(dirname, prefix = nil)
-    dirname = prefix + File.expand_path(dirname) if prefix
-    $stderr.puts "mkdir -p #{dirname}" if verbose?
-    return if no_harm?
-
-    # Does not check '/', it's too abnormal.
-    dirs = File.expand_path(dirname).split(%r<(?=/)>)
-    if /\A[a-z]:\z/i =~ dirs[0]
-      disk = dirs.shift
-      dirs[0] = disk + dirs[0]
-    end
-    dirs.each_index do |idx|
-      path = dirs[0..idx].join('')
-      Dir.mkdir path unless File.dir?(path)
-    end
-  end
-
-  def rm_f(path)
-    $stderr.puts "rm -f #{path}" if verbose?
-    return if no_harm?
-    force_remove_file path
-  end
-
-  def rm_rf(path)
-    $stderr.puts "rm -rf #{path}" if verbose?
-    return if no_harm?
-    remove_tree path
-  end
-
-  def remove_tree(path)
-    if File.symlink?(path)
-      remove_file path
-    elsif File.dir?(path)
-      remove_tree0 path
-    else
-      force_remove_file path
-    end
-  end
-
-  def remove_tree0(path)
-    Dir.foreach(path) do |ent|
-      next if ent == '.'
-      next if ent == '..'
-      entpath = "#{path}/#{ent}"
-      if File.symlink?(entpath)
-        remove_file entpath
-      elsif File.dir?(entpath)
-        remove_tree0 entpath
-      else
-        force_remove_file entpath
-      end
-    end
-    begin
-      Dir.rmdir path
-    rescue Errno::ENOTEMPTY
-      # directory may not be empty
-    end
-  end
-
-  def move_file(src, dest)
-    force_remove_file dest
-    begin
-      File.rename src, dest
-    rescue
-      File.open(dest, 'wb') {|f|
-        f.write File.binread(src)
-      }
-      File.chmod File.stat(src).mode, dest
-      File.unlink src
-    end
-  end
-
-  def force_remove_file(path)
-    begin
-      remove_file path
-    rescue
-    end
-  end
-
-  def remove_file(path)
-    File.chmod 0777, path
-    File.unlink path
-  end
-
-  def install(from, dest, mode, prefix = nil)
-    $stderr.puts "install #{from} #{dest}" if verbose?
-    return if no_harm?
-
-    realdest = prefix ? prefix + File.expand_path(dest) : dest
-    realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
-    str = File.binread(from)
-    if diff?(str, realdest)
-      verbose_off {
-        rm_f realdest if File.exist?(realdest)
-      }
-      File.open(realdest, 'wb') {|f|
-        f.write str
-      }
-      File.chmod mode, realdest
-
-      File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
-        if prefix
-          f.puts realdest.sub(prefix, '')
-        else
-          f.puts realdest
-        end
-      }
-    end
-  end
-
-  def diff?(new_content, path)
-    return true unless File.exist?(path)
-    new_content != File.binread(path)
-  end
-
-  def command(*args)
-    $stderr.puts args.join(' ') if verbose?
-    system(*args) or raise RuntimeError,
-        "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
-  end
-
-  def ruby(*args)
-    command config('rubyprog'), *args
-  end
-  
-  def make(task = nil)
-    command(*[config('makeprog'), task].compact)
-  end
-
-  def extdir?(dir)
-    File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
-  end
-
-  def files_of(dir)
-    Dir.open(dir) {|d|
-      return d.select {|ent| File.file?("#{dir}/#{ent}") }
-    }
-  end
-
-  DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
-
-  def directories_of(dir)
-    Dir.open(dir) {|d|
-      return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
-    }
-  end
-
-end
-
-
-# This module requires: #srcdir_root, #objdir_root, #relpath
-module HookScriptAPI
-
-  def get_config(key)
-    @config[key]
-  end
-
-  alias config get_config
-
-  # obsolete: use metaconfig to change configuration
-  def set_config(key, val)
-    @config[key] = val
-  end
-
-  #
-  # srcdir/objdir (works only in the package directory)
-  #
-
-  def curr_srcdir
-    "#{srcdir_root()}/#{relpath()}"
-  end
-
-  def curr_objdir
-    "#{objdir_root()}/#{relpath()}"
-  end
-
-  def srcfile(path)
-    "#{curr_srcdir()}/#{path}"
-  end
-
-  def srcexist?(path)
-    File.exist?(srcfile(path))
-  end
-
-  def srcdirectory?(path)
-    File.dir?(srcfile(path))
-  end
-  
-  def srcfile?(path)
-    File.file?(srcfile(path))
-  end
-
-  def srcentries(path = '.')
-    Dir.open("#{curr_srcdir()}/#{path}") {|d|
-      return d.to_a - %w(. ..)
-    }
-  end
-
-  def srcfiles(path = '.')
-    srcentries(path).select {|fname|
-      File.file?(File.join(curr_srcdir(), path, fname))
-    }
-  end
-
-  def srcdirectories(path = '.')
-    srcentries(path).select {|fname|
-      File.dir?(File.join(curr_srcdir(), path, fname))
-    }
-  end
-
-end
-
-
-class ToplevelInstaller
-
-  Version   = '3.4.1'
-  Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
-
-  TASKS = [
-    [ 'all',      'do config, setup, then install' ],
-    [ 'config',   'saves your configurations' ],
-    [ 'show',     'shows current configuration' ],
-    [ 'setup',    'compiles ruby extentions and others' ],
-    [ 'install',  'installs files' ],
-    [ 'test',     'run all tests in test/' ],
-    [ 'clean',    "does `make clean' for each extention" ],
-    [ 'distclean',"does `make distclean' for each extention" ]
-  ]
-
-  def ToplevelInstaller.invoke
-    config = ConfigTable.new(load_rbconfig())
-    config.load_standard_entries
-    config.load_multipackage_entries if multipackage?
-    config.fixup
-    klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
-    klass.new(File.dirname($0), config).invoke
-  end
-
-  def ToplevelInstaller.multipackage?
-    File.dir?(File.dirname($0) + '/packages')
-  end
-
-  def ToplevelInstaller.load_rbconfig
-    if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
-      ARGV.delete(arg)
-      load File.expand_path(arg.split(/=/, 2)[1])
-      $".push 'rbconfig.rb'
-    else
-      require 'rbconfig'
-    end
-    ::Config::CONFIG
-  end
-
-  def initialize(ardir_root, config)
-    @ardir = File.expand_path(ardir_root)
-    @config = config
-    # cache
-    @valid_task_re = nil
-  end
-
-  def config(key)
-    @config[key]
-  end
-
-  def inspect
-    "#<#{self.class} #{__id__()}>"
-  end
-
-  def invoke
-    run_metaconfigs
-    case task = parsearg_global()
-    when nil, 'all'
-      parsearg_config
-      init_installers
-      exec_config
-      exec_setup
-      exec_install
-    else
-      case task
-      when 'config', 'test'
-        ;
-      when 'clean', 'distclean'
-        @config.load_savefile if File.exist?(@config.savefile)
-      else
-        @config.load_savefile
-      end
-      __send__ "parsearg_#{task}"
-      init_installers
-      __send__ "exec_#{task}"
-    end
-  end
-  
-  def run_metaconfigs
-    @config.load_script "#{@ardir}/metaconfig"
-  end
-
-  def init_installers
-    @installer = Installer.new(@config, @ardir, File.expand_path('.'))
-  end
-
-  #
-  # Hook Script API bases
-  #
-
-  def srcdir_root
-    @ardir
-  end
-
-  def objdir_root
-    '.'
-  end
-
-  def relpath
-    '.'
-  end
-
-  #
-  # Option Parsing
-  #
-
-  def parsearg_global
-    while arg = ARGV.shift
-      case arg
-      when /\A\w+\z/
-        setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
-        return arg
-      when '-q', '--quiet'
-        @config.verbose = false
-      when '--verbose'
-        @config.verbose = true
-      when '--help'
-        print_usage $stdout
-        exit 0
-      when '--version'
-        puts "#{File.basename($0)} version #{Version}"
-        exit 0
-      when '--copyright'
-        puts Copyright
-        exit 0
-      else
-        setup_rb_error "unknown global option '#{arg}'"
-      end
-    end
-    nil
-  end
-
-  def valid_task?(t)
-    valid_task_re() =~ t
-  end
-
-  def valid_task_re
-    @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
-  end
-
-  def parsearg_no_options
-    unless ARGV.empty?
-      task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
-      setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
-    end
-  end
-
-  alias parsearg_show       parsearg_no_options
-  alias parsearg_setup      parsearg_no_options
-  alias parsearg_test       parsearg_no_options
-  alias parsearg_clean      parsearg_no_options
-  alias parsearg_distclean  parsearg_no_options
-
-  def parsearg_config
-    evalopt = []
-    set = []
-    @config.config_opt = []
-    while i = ARGV.shift
-      if /\A--?\z/ =~ i
-        @config.config_opt = ARGV.dup
-        break
-      end
-      name, value = *@config.parse_opt(i)
-      if @config.value_config?(name)
-        @config[name] = value
-      else
-        evalopt.push [name, value]
-      end
-      set.push name
-    end
-    evalopt.each do |name, value|
-      @config.lookup(name).evaluate value, @config
-    end
-    # Check if configuration is valid
-    set.each do |n|
-      @config[n] if @config.value_config?(n)
-    end
-  end
-
-  def parsearg_install
-    @config.no_harm = false
-    @config.install_prefix = ''
-    while a = ARGV.shift
-      case a
-      when '--no-harm'
-        @config.no_harm = true
-      when /\A--prefix=/
-        path = a.split(/=/, 2)[1]
-        path = File.expand_path(path) unless path[0,1] == '/'
-        @config.install_prefix = path
-      else
-        setup_rb_error "install: unknown option #{a}"
-      end
-    end
-  end
-
-  def print_usage(out)
-    out.puts 'Typical Installation Procedure:'
-    out.puts "  $ ruby #{File.basename $0} config"
-    out.puts "  $ ruby #{File.basename $0} setup"
-    out.puts "  # ruby #{File.basename $0} install (may require root privilege)"
-    out.puts
-    out.puts 'Detailed Usage:'
-    out.puts "  ruby #{File.basename $0} <global option>"
-    out.puts "  ruby #{File.basename $0} [<global options>] <task> [<task options>]"
-
-    fmt = "  %-24s %s\n"
-    out.puts
-    out.puts 'Global options:'
-    out.printf fmt, '-q,--quiet',   'suppress message outputs'
-    out.printf fmt, '   --verbose', 'output messages verbosely'
-    out.printf fmt, '   --help',    'print this message'
-    out.printf fmt, '   --version', 'print version and quit'
-    out.printf fmt, '   --copyright',  'print copyright and quit'
-    out.puts
-    out.puts 'Tasks:'
-    TASKS.each do |name, desc|
-      out.printf fmt, name, desc
-    end
-
-    fmt = "  %-24s %s [%s]\n"
-    out.puts
-    out.puts 'Options for CONFIG or ALL:'
-    @config.each do |item|
-      out.printf fmt, item.help_opt, item.description, item.help_default
-    end
-    out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
-    out.puts
-    out.puts 'Options for INSTALL:'
-    out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
-    out.printf fmt, '--prefix=path',  'install path prefix', ''
-    out.puts
-  end
-
-  #
-  # Task Handlers
-  #
-
-  def exec_config
-    @installer.exec_config
-    @config.save   # must be final
-  end
-
-  def exec_setup
-    @installer.exec_setup
-  end
-
-  def exec_install
-    @installer.exec_install
-  end
-
-  def exec_test
-    @installer.exec_test
-  end
-
-  def exec_show
-    @config.each do |i|
-      printf "%-20s %s\n", i.name, i.value if i.value?
-    end
-  end
-
-  def exec_clean
-    @installer.exec_clean
-  end
-
-  def exec_distclean
-    @installer.exec_distclean
-  end
-
-end   # class ToplevelInstaller
-
-
-class ToplevelInstallerMulti < ToplevelInstaller
-
-  include FileOperations
-
-  def initialize(ardir_root, config)
-    super
-    @packages = directories_of("#{@ardir}/packages")
-    raise 'no package exists' if @packages.empty?
-    @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
-  end
-
-  def run_metaconfigs
-    @config.load_script "#{@ardir}/metaconfig", self
-    @packages.each do |name|
-      @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
-    end
-  end
-
-  attr_reader :packages
-
-  def packages=(list)
-    raise 'package list is empty' if list.empty?
-    list.each do |name|
-      raise "directory packages/#{name} does not exist"\
-              unless File.dir?("#{@ardir}/packages/#{name}")
-    end
-    @packages = list
-  end
-
-  def init_installers
-    @installers = {}
-    @packages.each do |pack|
-      @installers[pack] = Installer.new(@config,
-                                       "#{@ardir}/packages/#{pack}",
-                                       "packages/#{pack}")
-    end
-    with    = extract_selection(config('with'))
-    without = extract_selection(config('without'))
-    @selected = @installers.keys.select {|name|
-                  (with.empty? or with.include?(name)) \
-                      and not without.include?(name)
-                }
-  end
-
-  def extract_selection(list)
-    a = list.split(/,/)
-    a.each do |name|
-      setup_rb_error "no such package: #{name}"  unless @installers.key?(name)
-    end
-    a
-  end
-
-  def print_usage(f)
-    super
-    f.puts 'Inluded packages:'
-    f.puts '  ' + @packages.sort.join(' ')
-    f.puts
-  end
-
-  #
-  # Task Handlers
-  #
-
-  def exec_config
-    run_hook 'pre-config'
-    each_selected_installers {|inst| inst.exec_config }
-    run_hook 'post-config'
-    @config.save   # must be final
-  end
-
-  def exec_setup
-    run_hook 'pre-setup'
-    each_selected_installers {|inst| inst.exec_setup }
-    run_hook 'post-setup'
-  end
-
-  def exec_install
-    run_hook 'pre-install'
-    each_selected_installers {|inst| inst.exec_install }
-    run_hook 'post-install'
-  end
-
-  def exec_test
-    run_hook 'pre-test'
-    each_selected_installers {|inst| inst.exec_test }
-    run_hook 'post-test'
-  end
-
-  def exec_clean
-    rm_f @config.savefile
-    run_hook 'pre-clean'
-    each_selected_installers {|inst| inst.exec_clean }
-    run_hook 'post-clean'
-  end
-
-  def exec_distclean
-    rm_f @config.savefile
-    run_hook 'pre-distclean'
-    each_selected_installers {|inst| inst.exec_distclean }
-    run_hook 'post-distclean'
-  end
-
-  #
-  # lib
-  #
-
-  def each_selected_installers
-    Dir.mkdir 'packages' unless File.dir?('packages')
-    @selected.each do |pack|
-      $stderr.puts "Processing the package `#{pack}' ..." if verbose?
-      Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
-      Dir.chdir "packages/#{pack}"
-      yield @installers[pack]
-      Dir.chdir '../..'
-    end
-  end
-
-  def run_hook(id)
-    @root_installer.run_hook id
-  end
-
-  # module FileOperations requires this
-  def verbose?
-    @config.verbose?
-  end
-
-  # module FileOperations requires this
-  def no_harm?
-    @config.no_harm?
-  end
-
-end   # class ToplevelInstallerMulti
-
-
-class Installer
-
-  FILETYPES = %w( bin lib ext data conf man )
-
-  include FileOperations
-  include HookScriptAPI
-
-  def initialize(config, srcroot, objroot)
-    @config = config
-    @srcdir = File.expand_path(srcroot)
-    @objdir = File.expand_path(objroot)
-    @currdir = '.'
-  end
-
-  def inspect
-    "#<#{self.class} #{File.basename(@srcdir)}>"
-  end
-
-  def noop(rel)
-  end
-
-  #
-  # Hook Script API base methods
-  #
-
-  def srcdir_root
-    @srcdir
-  end
-
-  def objdir_root
-    @objdir
-  end
-
-  def relpath
-    @currdir
-  end
-
-  #
-  # Config Access
-  #
-
-  # module FileOperations requires this
-  def verbose?
-    @config.verbose?
-  end
-
-  # module FileOperations requires this
-  def no_harm?
-    @config.no_harm?
-  end
-
-  def verbose_off
-    begin
-      save, @config.verbose = @config.verbose?, false
-      yield
-    ensure
-      @config.verbose = save
-    end
-  end
-
-  #
-  # TASK config
-  #
-
-  def exec_config
-    exec_task_traverse 'config'
-  end
-
-  alias config_dir_bin noop
-  alias config_dir_lib noop
-
-  def config_dir_ext(rel)
-    extconf if extdir?(curr_srcdir())
-  end
-
-  alias config_dir_data noop
-  alias config_dir_conf noop
-  alias config_dir_man noop
-
-  def extconf
-    ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
-  end
-
-  #
-  # TASK setup
-  #
-
-  def exec_setup
-    exec_task_traverse 'setup'
-  end
-
-  def setup_dir_bin(rel)
-    files_of(curr_srcdir()).each do |fname|
-      update_shebang_line "#{curr_srcdir()}/#{fname}"
-    end
-  end
-
-  alias setup_dir_lib noop
-
-  def setup_dir_ext(rel)
-    make if extdir?(curr_srcdir()) and File.exist?("#{curr_srcdir()}/Makefile")
-  end
-
-  alias setup_dir_data noop
-  alias setup_dir_conf noop
-  alias setup_dir_man noop
-
-  def update_shebang_line(path)
-    return if no_harm?
-    return if config('shebang') == 'never'
-    old = Shebang.load(path)
-    if old
-      $stderr.puts "warning: #{path}: Shebang line includes too many args.  It is not portable and your program may not work." if old.args.size > 1
-      new = new_shebang(old)
-      return if new.to_s == old.to_s
-    else
-      return unless config('shebang') == 'all'
-      new = Shebang.new(config('rubypath'))
-    end
-    $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
-    open_atomic_writer(path) {|output|
-      File.open(path, 'rb') {|f|
-        f.gets if old   # discard
-        output.puts new.to_s
-        output.print f.read
-      }
-    }
-  end
-
-  def new_shebang(old)
-    if /\Aruby/ =~ File.basename(old.cmd)
-      Shebang.new(config('rubypath'), old.args)
-    elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
-      puts "Skipping shebang rename"
-      # We don't want this to happen anymore, it doesn't make sense
-      # Shebang.new(config('rubypath'), old.args[1..-1])
-      old
-    else
-      return old unless config('shebang') == 'all'
-      Shebang.new(config('rubypath'))
-    end
-  end
-
-  def open_atomic_writer(path, &block)
-    tmpfile = File.basename(path) + '.tmp'
-    begin
-      File.open(tmpfile, 'wb', &block)
-      File.rename tmpfile, File.basename(path)
-    ensure
-      File.unlink tmpfile if File.exist?(tmpfile)
-    end
-  end
-
-  class Shebang
-    def Shebang.load(path)
-      line = nil
-      File.open(path) {|f|
-        line = f.gets
-      }
-      return nil unless /\A#!/ =~ line
-      parse(line)
-    end
-
-    def Shebang.parse(line)
-      cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
-      new(cmd, args)
-    end
-
-    def initialize(cmd, args = [])
-      @cmd = cmd
-      @args = args
-    end
-
-    attr_reader :cmd
-    attr_reader :args
-
-    def to_s
-      "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
-    end
-  end
-
-  #
-  # TASK install
-  #
-
-  def exec_install
-    rm_f 'InstalledFiles'
-    exec_task_traverse 'install'
-  end
-
-  def install_dir_bin(rel)
-    install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
-  end
-
-  def install_dir_lib(rel)
-    install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
-  end
-
-  def install_dir_ext(rel)
-    return unless extdir?(curr_srcdir())
-    install_files rubyextentions('.'),
-                  "#{config('sodir')}/#{File.dirname(rel)}",
-                  0555
-  end
-
-  def install_dir_data(rel)
-    install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
-  end
-
-  def install_dir_conf(rel)
-    # FIXME: should not remove current config files
-    # (rename previous file to .old/.org)
-    install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
-  end
-
-  def install_dir_man(rel)
-    install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
-  end
-
-  def install_files(list, dest, mode)
-    mkdir_p dest, @config.install_prefix
-    list.each do |fname|
-      install fname, dest, mode, @config.install_prefix
-    end
-  end
-
-  def libfiles
-    glob_reject(%w(*.y *.output), targetfiles())
-  end
-
-  def rubyextentions(dir)
-    ents = glob_select("*.#{@config.dllext}", targetfiles())
-    if ents.empty?
-      setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
-    end
-    ents
-  end
-
-  def targetfiles
-    mapdir(existfiles() - hookfiles())
-  end
-
-  def mapdir(ents)
-    ents.map {|ent|
-      if File.exist?(ent)
-      then ent                         # objdir
-      else "#{curr_srcdir()}/#{ent}"   # srcdir
-      end
-    }
-  end
-
-  # picked up many entries from cvs-1.11.1/src/ignore.c
-  JUNK_FILES = %w( 
-    core RCSLOG tags TAGS .make.state
-    .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
-    *~ *.old *.bak *.BAK *.orig *.rej _$* *$
-
-    *.org *.in .*
-  )
-
-  def existfiles
-    glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
-  end
-
-  def hookfiles
-    %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
-      %w( config setup install clean ).map {|t| sprintf(fmt, t) }
-    }.flatten
-  end
-
-  def glob_select(pat, ents)
-    re = globs2re([pat])
-    ents.select {|ent| re =~ ent }
-  end
-
-  def glob_reject(pats, ents)
-    re = globs2re(pats)
-    ents.reject {|ent| re =~ ent }
-  end
-
-  GLOB2REGEX = {
-    '.' => '\.',
-    '$' => '\$',
-    '#' => '\#',
-    '*' => '.*'
-  }
-
-  def globs2re(pats)
-    /\A(?:#{
-      pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
-    })\z/
-  end
-
-  #
-  # TASK test
-  #
-
-  TESTDIR = 'test'
-
-  def exec_test
-    unless File.directory?('test')
-      $stderr.puts 'no test in this package' if verbose?
-      return
-    end
-    $stderr.puts 'Running tests...' if verbose?
-    begin
-      require 'test/unit'
-    rescue LoadError
-      setup_rb_error 'test/unit cannot loaded.  You need Ruby 1.8 or later to invoke this task.'
-    end
-    runner = Test::Unit::AutoRunner.new(true)
-    runner.to_run << TESTDIR
-    runner.run
-  end
-
-  #
-  # TASK clean
-  #
-
-  def exec_clean
-    exec_task_traverse 'clean'
-    rm_f @config.savefile
-    rm_f 'InstalledFiles'
-  end
-
-  alias clean_dir_bin noop
-  alias clean_dir_lib noop
-  alias clean_dir_data noop
-  alias clean_dir_conf noop
-  alias clean_dir_man noop
-
-  def clean_dir_ext(rel)
-    return unless extdir?(curr_srcdir())
-    make 'clean' if File.file?('Makefile')
-  end
-
-  #
-  # TASK distclean
-  #
-
-  def exec_distclean
-    exec_task_traverse 'distclean'
-    rm_f @config.savefile
-    rm_f 'InstalledFiles'
-  end
-
-  alias distclean_dir_bin noop
-  alias distclean_dir_lib noop
-
-  def distclean_dir_ext(rel)
-    return unless extdir?(curr_srcdir())
-    make 'distclean' if File.file?('Makefile')
-  end
-
-  alias distclean_dir_data noop
-  alias distclean_dir_conf noop
-  alias distclean_dir_man noop
-
-  #
-  # Traversing
-  #
-
-  def exec_task_traverse(task)
-    run_hook "pre-#{task}"
-    FILETYPES.each do |type|
-      if type == 'ext' and config('without-ext') == 'yes'
-        $stderr.puts 'skipping ext/* by user option' if verbose?
-        next
-      end
-      traverse task, type, "#{task}_dir_#{type}"
-    end
-    run_hook "post-#{task}"
-  end
-
-  def traverse(task, rel, mid)
-    dive_into(rel) {
-      run_hook "pre-#{task}"
-      __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
-      directories_of(curr_srcdir()).each do |d|
-        traverse task, "#{rel}/#{d}", mid
-      end
-      run_hook "post-#{task}"
-    }
-  end
-
-  def dive_into(rel)
-    return unless File.dir?("#{@srcdir}/#{rel}")
-
-    dir = File.basename(rel)
-    Dir.mkdir dir unless File.dir?(dir)
-    prevdir = Dir.pwd
-    Dir.chdir dir
-    $stderr.puts '---> ' + rel if verbose?
-    @currdir = rel
-    yield
-    Dir.chdir prevdir
-    $stderr.puts '<--- ' + rel if verbose?
-    @currdir = File.dirname(rel)
-  end
-
-  def run_hook(id)
-    path = [ "#{curr_srcdir()}/#{id}",
-             "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
-    return unless path
-    begin
-      instance_eval File.read(path), path, 1
-    rescue
-      raise if $DEBUG
-      setup_rb_error "hook #{path} failed:\n" + $!.message
-    end
-  end
-
-end   # class Installer
-
-
-class SetupError < StandardError; end
-
-def setup_rb_error(msg)
-  raise SetupError, msg
-end
-
-if $0 == __FILE__
-  begin
-    ToplevelInstaller.invoke
-  rescue SetupError
-    raise if $DEBUG
-    $stderr.puts $!.message
-    $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
-    exit 1
-  end
-end
diff --git a/test/code_coverage_analyzer_test.rb b/test/code_coverage_analyzer_test.rb
index 96636e3..b54aaf2 100644
--- a/test/code_coverage_analyzer_test.rb
+++ b/test/code_coverage_analyzer_test.rb
@@ -24,8 +24,8 @@ EOF
   def test_refine_coverage_info
     analyzer = Rcov::CodeCoverageAnalyzer.new
     cover = [1, 1, nil, nil, 0, 5, 5, 5, 0]
-    line_info, marked_info,
-      count_info = analyzer.instance_eval{ refine_coverage_info(LINES, cover) }
+
+    line_info, marked_info, count_info = analyzer.instance_eval{ refine_coverage_info(LINES, cover) }
     assert_equal(LINES, line_info)
     assert_equal([true] * 2 + [false] * 3 + [true] * 3 + [false], marked_info)
     assert_equal([1, 1, 0, 0, 0, 5, 5, 5, 0], count_info)
@@ -39,6 +39,7 @@ EOF
   def test_raw_coverage_info
     sample_file = File.join(File.dirname(__FILE__), "assets/sample_01.rb")
     lines = File.readlines(sample_file)
+
     analyzer = Rcov::CodeCoverageAnalyzer.new
     analyzer.run_hooked{ load sample_file }
 
@@ -48,8 +49,12 @@ EOF
     assert_equal(lines, line_info)
     assert_equal([true, true, false, false, true, false, true], cov_info)
     assert_equal([1, 2, 0, 0, 1, 0, 11], count_info) unless RUBY_PLATFORM =~ /java/
-    # JRUBY reports an if x==blah as hitting this type of line once, JRUBY also optimizes this stuff so you'd have to run with --debug to get "extra" information.  MRI hits it twice.
+
+    # JRUBY reports an if x==blah as hitting this type of line once,
+    # JRUBY also optimizes this stuff so you'd have to run with
+    # --debug to get "extra" information. MRI hits it twice.
     assert_equal([1, 3, 0, 0, 1, 0, 13], count_info) if RUBY_PLATFORM =~ /java/
+
     analyzer.reset
     assert_equal(nil, analyzer.data(sample_file))
     assert_equal([], analyzer.analyzed_files)
@@ -60,6 +65,7 @@ EOF
     lines = ["puts a", "foo", "bar"] * 3
     coverage = [true] * 3 + [false] * 6
     counts = [1] * 3 + [0] * 6
+
     nlines, ncoverage, ncounts = analyzer.instance_eval do
       script_lines_workaround(lines, coverage, counts)
     end
@@ -74,9 +80,11 @@ EOF
     lines = ["puts a", "foo", "bar"] * 2 + ["puts a", "foo", "baz"]
     coverage = [true] * 9
     counts = [1] * 9
+
     nlines, ncoverage, ncounts = analyzer.instance_eval do
       script_lines_workaround(lines, coverage, counts)
     end
+
     assert_equal(lines, nlines)
     assert_equal(coverage, ncoverage)
     assert_equal(counts, ncounts)
@@ -85,58 +93,75 @@ EOF
   def test_if_elsif_reports_correctly
     sample_file = File.join(File.dirname(__FILE__), "assets/sample_06.rb")
     lines = File.readlines(sample_file)
+
     analyzer = Rcov::CodeCoverageAnalyzer.new
     analyzer.run_hooked{ load sample_file }
+
     assert_equal(lines, SCRIPT_LINES__[sample_file][0, lines.size])
     assert(analyzer.analyzed_files.include?(sample_file))
+
     line_info, cov_info, count_info = analyzer.data(sample_file)
     assert_equal(lines, line_info)
     assert_equal([true, true, false, true, true, false, false, false], cov_info) unless RUBY_PLATFORM == "java"
   end
 
   def test_differential_coverage_data
-    sample_file = File.join(File.dirname(__FILE__), "assets/sample_01.rb")
-    lines = File.readlines(sample_file)
     analyzer = Rcov::CodeCoverageAnalyzer.new
-    analyzer.run_hooked{ load sample_file }
-    line_info, cov_info, count_info = analyzer.data(sample_file)
-    assert_equal([1, 2, 0, 0, 1, 0, 11], count_info) if RUBY_VERSION =~ /1.9/
-
-    analyzer.reset
-    #set_trace_func proc { |event, file, line, id, binding, classname| printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname if (file =~ /sample_02.rb/) }     
-
     sample_file = File.join(File.dirname(__FILE__), "assets/sample_02.rb")
     analyzer.run_hooked{ load sample_file }
     line_info, cov_info, count_info = analyzer.data(sample_file)
+
     if RUBY_PLATFORM == "java"
       assert_equal([8, 3, 0, 0, 0], count_info) 
     else
-      assert_equal([8, 1, 0, 0, 0], count_info) unless  RUBY_VERSION =~ /1.9/
-      assert_equal([4, 1, 0, 0, 4], count_info) if RUBY_VERSION =~ /1.9/
+      assert_equal([8, 1, 0, 0, 0], count_info)
     end
 
     analyzer.reset
     assert_equal([], analyzer.analyzed_files)
     analyzer.run_hooked{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
     line_info, cov_info, count_info = analyzer.data(sample_file)
+
     if RUBY_PLATFORM == "java"
-      assert_equal([0, 1, 3, 1, 0], count_info) unless RUBY_VERSION =~ /1.9/
+      assert_equal([0, 1, 3, 1, 0], count_info)
     else
-      assert_equal([0, 1, 1, 1, 0], count_info) unless RUBY_VERSION =~ /1.9/
-      assert_equal([0, 2, 1, 0, 0], count_info) if RUBY_VERSION =~ /1.9/
+      if RUBY_VERSION == "1.8.7" 
+        assert_equal([0, 1, 2, 0, 0], count_info)
+      else
+        assert_equal([0, 1, 1, 1, 0], count_info)
+      end
     end
+
     analyzer.run_hooked do
       10.times{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
     end
+
     line_info, cov_info, count_info = analyzer.data(sample_file)
-    assert_equal([0, 11, 33, 11, 0], count_info) if RUBY_PLATFORM == "java"
-    assert_equal([0, 11, 11, 11, 0], count_info) unless RUBY_PLATFORM == "java"
+    if RUBY_PLATFORM == "java"
+      assert_equal([0, 11, 33, 11, 0], count_info) 
+    else
+      if RUBY_VERSION == "1.8.7"
+        assert_equal([0, 11, 22, 0, 0], count_info) 
+      else
+        assert_equal([0, 11, 11, 11, 0], count_info) 
+      end
+    end
+
     10.times{ analyzer.run_hooked{ Rcov::Test::Temporary::Sample02.foo(1, 1) } }
     line_info, cov_info, count_info = analyzer.data(sample_file)
-    assert_equal([0, 21, 63, 21, 0], count_info) if RUBY_PLATFORM == "java"
-    assert_equal([0, 21, 21, 21, 0], count_info) unless RUBY_PLATFORM == "java"
+    
+    if RUBY_PLATFORM == "java"
+      assert_equal([0, 21, 63, 21, 0], count_info) 
+    else
+      if RUBY_VERSION == "1.8.7"
+        assert_equal([0, 21, 42, 0, 0], count_info)
+      else
+        assert_equal([0, 21, 21, 21, 0], count_info)
+      end
+    end
 
     count_info2 = nil
+
     10.times do |i|
       analyzer.run_hooked do
         Rcov::Test::Temporary::Sample02.foo(1, 1)
@@ -144,12 +169,18 @@ EOF
         line_info2, cov_info2, count_info2 = analyzer.data(sample_file)
       end
     end
+
     if RUBY_PLATFORM == "java"
       assert_equal([0, 25, 75, 25, 0], count_info)
       assert_equal([0, 31, 93, 31, 0], count_info2)
     else
-      assert_equal([0, 25, 25, 25, 0], count_info)
-      assert_equal([0, 31, 31, 31, 0], count_info2)
+      if RUBY_VERSION == "1.8.7"
+        assert_equal([0, 25, 50, 0, 0], count_info)
+        assert_equal([0, 31, 62, 0, 0], count_info2)
+      else
+        assert_equal([0, 25, 25, 25, 0], count_info)
+        assert_equal([0, 31, 31, 31, 0], count_info2)
+      end
     end
   end
 
@@ -162,9 +193,11 @@ EOF
 
     a1.run_hooked do
       100.times{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
+
       a2.run_hooked do
         10.times{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
       end
+
       100.times{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
     end
 
@@ -183,12 +216,18 @@ EOF
 
     _, _, counts1 = a1.data(sample_file)
     _, _, counts2 = a2.data(sample_file)
+
     if RUBY_PLATFORM == "java"
       assert_equal([0, 221, 663, 221, 0], counts1)    
       assert_equal([0, 121, 363, 121, 0], counts2)
     else
-      assert_equal([0, 221, 221, 221, 0], counts1)
-      assert_equal([0, 121, 121, 121, 0], counts2)
+      if RUBY_VERSION == "1.8.7"
+        assert_equal([0, 221, 442, 0, 0], counts1)
+        assert_equal([0, 121, 242, 0, 0], counts2)
+      else
+        assert_equal([0, 221, 221, 221, 0], counts1)
+        assert_equal([0, 121, 121, 121, 0], counts2)
+      end
     end
   end
   
@@ -206,15 +245,23 @@ EOF
       end
     end
 
-    assert_equal([0, 50, 50, 50, 0], a1.data(sample_file)[2]) unless RUBY_PLATFORM == "java"
-    assert_equal([0, 50, 150, 50, 0], a1.data(sample_file)[2]) if RUBY_PLATFORM == "java"
+
+    if RUBY_PLATFORM == "java"
+      assert_equal([0, 50, 150, 50, 0], a1.data(sample_file)[2]) 
+    else
+      if RUBY_VERSION == "1.8.7"
+        assert_equal([0, 50, 100, 0, 0], a1.data(sample_file)[2])
+      else
+        assert_equal([0, 50, 50, 50, 0], a1.data(sample_file)[2])
+      end
+    end
   end
 
   def test_compute_raw_difference
     first = {"a" => [1,1,1,1,1]}
     last =  {"a" => [2,1,5,2,1], "b" => [1,2,3,4,5]}
     a = Rcov::CodeCoverageAnalyzer.new
-    assert_equal({"a" => [1,0,4,1,0], "b" => [1,2,3,4,5]},
-                 a.instance_eval{ compute_raw_data_difference(first, last)} )
+
+    assert_equal({"a" => [1,0,4,1,0], "b" => [1,2,3,4,5]}, a.instance_eval{ compute_raw_data_difference(first, last)} )
   end
 end
diff --git a/test/expected_coverage/sample_04_rb.rb b/test/expected_coverage/sample_04_rb.rb
new file mode 100644
index 0000000..5b8082b
--- /dev/null
+++ b/test/expected_coverage/sample_04_rb.rb
@@ -0,0 +1,18 @@
+$: << File.dirname(__FILE__)                                                #o
+require 'sample_03'                                                         #o
+                                                                            #o
+klass = Rcov::Test::Temporary::Sample03                                     #o
+obj = klass.new                                                             #o
+obj.f1                                                                      # >> [[Rcov::Test::Temporary::Sample03#f1 at sample_03_rb.rb:3]], 
+obj.f2                                                                      # >> [[Rcov::Test::Temporary::Sample03#f2 at sample_03_rb.rb:7]], 
+obj.f3                                                                      # >> [[Rcov::Test::Temporary::Sample03#f3 at sample_03_rb.rb:9]], 
+#klass.g1 uncovered                                                         #o
+klass.g2                                                                    # >> [[#<Class:Rcov::Test::Temporary::Sample03>#g2 at sample_03_rb.rb:18]], 
+# Total lines    : 10
+# Lines of code  : 8
+# Total coverage : 100.0%
+# Code coverage  : 100.0%
+
+# Local Variables:
+# mode: rcov-xref
+# End:
diff --git a/test/test_github_gem.rb b/test/test_github_gem.rb
new file mode 100644
index 0000000..65a420b
--- /dev/null
+++ b/test/test_github_gem.rb
@@ -0,0 +1,21 @@
+require File.dirname(__FILE__) + '/test_helper'
+require 'yaml'
+require 'rubygems/specification'
+ 
+class TestGithubGem < Test::Unit::TestCase
+
+  def test_spec_should_validate
+    Dir.chdir(File.join(File.dirname(__FILE__), *%w[..])) do
+      data = File.read("rcov.gemspec")
+      spec = nil
+
+      if data !~ %r{!ruby/object:Gem::Specification}
+       Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
+      else
+       spec = YAML.load(data)
+      end
+
+      assert spec.validate
+    end
+  end
+end

-- 
rcov.git



More information about the Pkg-ruby-extras-commits mailing list