On Wed, 04 Feb 2004 11:22:05 +0100, Robert Klemme wrote:

> 
> "Simon Strandgaard" <neoneye / adslhome.dk> schrieb im Newsbeitrag
> news:pan.2004.02.04.09.26.42.335507 / adslhome.dk...
>> On Wed, 04 Feb 2004 00:46:20 +0900, nobu.nokad wrote:
>> > At Wed, 4 Feb 2004 00:30:04 +0900,
>> > Simon Strandgaard wrote:
>> >> If I do "cat report.txt" then my terminal just scrolls for 10
> seconds,
>> >> which is much larger than what my terminal history can remember.
>> >> If I pipe it into "less" then the coloring disappears. How do you
> view
>> >> ANSI files?
>> >
>> > less -r
>>
>> Thanks..
>>
>> I have done some improvements to the original 'coverage.rb', so that
>> HTML is now generated. For an example have a look at:
>> http://neoneye.dk/parser.rb.coverage.html
>>
>> As you may notice comments/arrays appears as if they are not executed!
>> How can I fix this?
> 
> Dunno whether it's worth the effort.  I guess, comments could be fixed by
> identifying regions of comment lines and marking them as reached if the
> line above and below is reached.  For arrays you could try to find the
> matching "[" for a closing "]" and mark all lines in between if the line
> of the closing "]" is marked.
> 
> Apart from that: nice output!

Ok.. I now propagate the marked status to comments.. output is much better
now. Still Arrays/Hashes/=begin=end needs to be fixed.

Try compare the new output agains the old:
http://neoneye.dk/parser.rb.coverage.ver2.html

Suggestions for improvements is welcome.. also patches is welcome.

For the courius; try to execute the attached code by 
requiring it on the commandline.  
ruby -rcoverage helloworld.rb
That should output a 'helloworld.rb.coverage.html' file.

--
Simon Strandgaard

module PrettyCoverage
  class HTML
    def initialize
      @files = {}
    end
    def execute
      puts "execute"
      create_file_index
      @files.each{|file, line_marked|
        create_file(file, line_marked)
      }
    end
    def mk_filename(name)  
      name+".coverage.html" 
    end
    def create_file_index
      output_filename = "index.html"
      rows = []
      @files.each{|file, line_marked|
        filename = mk_filename(file)
        rows << "<tr><td><a href=\"#{filename}\">#{file}</a></td></tr>"
      }
      result = rows.join("\n")
      body = "<table>#{result}</table>"
      title = "coverage"
      css = <<EOCSS
body {
  background-color: rgb(180, 180, 180);
}
div.marked {
  background-color: rgb(185, 200, 200);
}
div.overview {
  border-bottom: 8px solid black;
}
EOCSS
      html = <<EOHTML 
<html><head><title>#{title}</title>
<style type="text/css">#{css}</style></head>
<body>#{body}</body></html> 
EOHTML
      File.open(output_filename, "w+") do |f|
        f.puts html
      end
    end
    def add_file(file, line_marked)
      percent = calc_coverage(line_marked)
      printf("file=#{file} coverage=%02.1f%\n", percent)

      # comments and empty lines.. we must
      # propagate marked-value backwards 
      line_marked << ["", false]
      (line_marked.size).downto(1) do |index|
        line, marked = line_marked[index-1]
        next_line, next_marked = line_marked[index]
        if line =~ /^\s*(#|$)/ and marked == false
          marked = next_marked
          #line = "hest" + line 
          line_marked[index-1] = [line, marked]
        end
      end
      line_marked.pop
      
      @files[file] = line_marked
    end
    def calc_coverage(line_marked)
      marked = line_marked.transpose[1]
      n = marked.inject(0) {|r, i| (i) ? (r+1) : r } 
      percent = n.to_f * 100 / marked.size
    end
    def format_overview(file, line_marked)
      percent = "%02.1f" % calc_coverage(line_marked)
      html = <<EOHTML
<div class="overview">
<table>
<tr><td>filename</td><td><tt>#{file}</tt></td></tr>
<tr><td>coverage</td><td>#{percent}</td></tr>
</table>
</div>
EOHTML
      html
    end
    def format_lines(line_marked)
      result = ""
      last = nil
      end_of_div = ""
      format_line = "%#{line_marked.size.to_s.size}d"
      line_no = 1
      line_marked.each {|(line, marked)|
        if marked != last
          result += end_of_div
          case marked
          when true
            result += "<div class=\"marked\">"
            end_of_div = "</div>"
          when false
            end_of_div = ""
          end
        end
        result += (format_line % line_no) + " " + line + "\n"
        last = marked
        line_no += 1
      }
      result += end_of_div
      "<pre>#{result}</pre>"
    end
    def create_file(file, line_marked)
      output_filename = mk_filename(file)
      puts "outputting #{output_filename.inspect}"
      body = 
        format_overview(file, line_marked) + 
        format_lines(line_marked)
      title = file + " - coverage"
      css = <<EOCSS
body {
  background-color: rgb(180, 180, 180);
}
div.marked {
  background-color: rgb(185, 200, 200);
}
div.overview {
  border-bottom: 8px solid black;
}
EOCSS
      html = <<EOHTML 
<html><head><title>#{title}</title>
<style type="text/css">#{css}</style></head>
<body>#{body}</body></html> 
EOHTML
      File.open(output_filename, "w+") do |f|
        f.puts html
      end
    end
  end
end

SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__

module COVERAGE__
  COVER = {}
  def self.trace_func(event, file, line, id, binding, klass)
    case event
    when 'c-call', 'c-return', 'class'
      return
    end
    COVER[file] ||= []
    COVER[file][line] ||= 0
    COVER[file][line] += 1
  end

  END {
    set_trace_func(nil)
  printer = PrettyCoverage::HTML.new
    COVER.each do |file, lines|
    next if SCRIPT_LINES__.has_key?(file) == false
    lines = SCRIPT_LINES__[file]
    covers = COVER[file]
    line_status = []
    0.upto(lines.size - 1) do |c|
      line = lines[c].chomp
      marked = false
      if covers[c + 1]
        marked = true
      elsif /^\s*(?:begin\s*(?:#.*)?|ensure\s*(?:#.*)?|else\s*(?:#.*)?)$/ =~ line and covers[c + 1 + 1]
        covers[c + 1] = covers[c + 1 + 1]
        marked = true
      elsif /^\s*(?:end|})\s*$/ =~ line && covers[c + 1 - 1]
        covers[c + 1] = covers[c + 1 - 1]
        marked = true
      end
      line_status << [line, marked]
    end
    printer.add_file(file, line_status)
    end
  printer.execute
  }

  set_trace_func(COVERAGE__.method(:trace_func).to_proc)
end