cvs: php-gtk-doc /scripts classcoverage.php
[email protected] ("Christian Weiske") Wed, 22 Nov 2006 17:27:57 -0000
| Newsgroups | php.gtk.doc |
|---|---|
| Message-ID | <cvscweiske1164216477@cvsserver> |
cweiske Wed Nov 22 17:27:57 2006 UTC
Added files:
/php-gtk-doc/scripts classcoverage.php
Log:
Add classcoverage script to CVS after it was lost on my disk
and I luckily found it on an old backup
cweiske-20061122172757.txt
(text/plain, 13.9 KB)
http://cvs.php.net/viewvc.cgi/php-gtk-doc/scripts/classcoverage.php?view=markup&rev=1.1 Index: php-gtk-doc/scripts/classcoverage.php +++ php-gtk-doc/scripts/classcoverage.php <?php /** * PHP-Gtk coverage analysis generator. * * The script is based on the php-gtk-doc coverage * analysis script with a slightly modified output. * * The main work is done in the Log2Coverage class * that takes some gen_*.log files and transforms them * into an xml file similar to the one generated by * the coverage.xsl script for the documentation. * * Usage: * Pass the paths of the gen_*.log files to the script, e.g. * php coverage.php ext/* /gen_*.log > classcoverage.htm * ^ remove this space * * @author Christian Weiske <[email protected]> */ /** * Converts a gen_* logfile (e.g. ext/gtk+/gen_gtk.log) to * a coverage xml file as generated by the * php-gtk-doc coverage.xsl script. */ class Log2Coverage { protected static $classpattern = "/([A-Za-z0-9]+)\n~+\n((?: .*\n)+)/"; protected static $funcpattern = "/ ([a-z ]+?)\s+ \\(([0-9]+) written, ([0-9]+) skipped\\)\n/"; protected static $notgenpattern = "/Not Generated Items\\s*\n=+\n((?: .+\n)*)\n/"; protected static $notgenline = "/ ([a-z ]+)\s+(([a-zA-Z0-9]+)(?:::|->)([a-zA-Z0-9_]+):.+)/"; /** * I know that hardcoded titles are bad, but if * the file isn't in here the gen_*.log filename * is shown as fallback. */ protected static $filetitles = array( 'gen_gtk.log' => 'Gtk', 'gen_gdk.log' => 'Gdk', 'gen_atk.log' => 'Atk', 'gen_pango.log' => 'Pango', 'gen_libglade.log' => 'Glade', 'gen_sourceview.log' => 'GtkSourceview', ); public static function generateFromArgs() { $files = $GLOBALS['argv']; array_shift($files); return self::generate($files); }//public static function generateFromArgs() public static function generate($files) { if (count($files) == 0) { echo "I guess you forgot to specify the gen_*.log files to parse.\n"; } $content = '<' . '?xml version="1.0" encoding="utf-8"?' . ">\n"; $content .= '<classcoverage>'; foreach ($files as $file) { $content .= self::splitFile($file); } $content .= '</classcoverage>'; return $content; }//public static function generate($files) protected static function splitFile($filename) { //match not generated items $matches = array(); preg_match_all(self::$notgenpattern, file_get_contents($filename), $matches); $notgen = $matches[1][0]; $arNotGen = self::splitNotGenerated($notgen); //match statistics $matches = array(); preg_match_all(self::$classpattern, file_get_contents($filename), $matches); $bn = basename($filename); $title = isset(self::$filetitles[$bn]) ? self::$filetitles[$bn] : $bn; $content = '<classset title="' . $title . '">'; $contents = array(); foreach ($matches[1] as $id => $class) { $notgen = isset($arNotGen[$class]) ? $arNotGen[$class] : array(); $contents[$class] = self::splitClass($class, $matches[2][$id], $notgen); } ksort($contents); $content .= implode('', $contents); $content .= '</classset>'; return $content; }//protected static function splitFile($filename) protected static function splitClass($class, $data, $notgen) { $matches = array(); preg_match_all(self::$funcpattern, $data, $matches); $content = '<class title="' . $class . '">'; foreach ($matches[1] as $id => $name) { $written = $matches[2][$id]; $skipped = $matches[3][$id]; if ($name[0] == 'p') { $name = 'properties'; } else if ($name[0] == 'f') { $name = 'methods'; } $content .= '<type title="' . $name . '"' . ' existing="' . ($written + $skipped) . '"' . ' missing="' . ($skipped) . '"'; if (!isset($notgen[$name])) { $content .= '/>'; } else { $content .= '>'; foreach ($notgen[$name] as $name => $message) { $content .= '<missing' . ' name="' . htmlspecialchars($name) . '"' . ' message="' . htmlspecialchars($message) . '"' . '/>'; } $content .= '</type>'; } } $content .= '</class>'; return $content; }//protected static function splitClass($class, $data) protected static function splitNotGenerated($notgen) { $ar = explode("\n", $notgen); $arNotGen = array(); foreach ($ar as $line) { $matches = array(); preg_match_all(self::$notgenline, $line, $matches); if (!isset($matches[0][0])) { //strange... continue; } $type = trim($matches[1][0]) . 's'; $message = $matches[2][0]; $class = $matches[3][0]; $name = $matches[4][0]; if ($type[0] == 'r') {//reader for $type = 'properties'; } else if ($type[0] == 'f') {//function $type = 'methods'; } $arNotGen[$class][$type][$name] = $message; } return $arNotGen; }//protected static function splitNotGenerated($notgen) }//class Log2Coverage /** * PHP-Gtk generator coverage analysis generator * * Based on the php-gtk-doc coverage generator. * * @author Christian Weiske <[email protected]> */ class ClassCoverageAnalysis { protected $typestemplate = array( 'constructors' => array( 'missing' => 0, 'existing' => 0 ), 'methods' => array( 'missing' => 0, 'existing' => 0 ), 'properties' => array( 'missing' => 0, 'existing' => 0 ), ); protected $missingThings = ''; public function run() { $doc = simplexml_load_string(Log2Coverage::generateFromArgs()); $output = <<<EOD <html> <head> <title>PHP-Gtk2 generator coverage analysis</title> <style type="text/css"> table { border: 1px solid black; border-collapse: collapse; } td, th { border: 1px solid grey; } table tr.classset td, table tr.documentation td { font-weight:bold; border-bottom: 2px solid black; } th.allpercent { font-size: 200%; } </style> </head> <body> <table> <caption> EOD; $output .= 'PHP-Gtk2 generator coverage analysis of ' . date('Y-m-d H:i:s'); $output .= <<<EOD </caption> EOD; $output .= $this->calcCoverage($doc); $output .= <<<EOD </table> EOD; $output .= $this->missingThings; $output .= <<<EOD </body> </html> EOD; return $output; }//public function run() protected function calcCoverage($doc) { $output = '<thead>' . "\r\n" . '<tr>' . '<th rowspan="2">Name</th>' . '<th colspan="2">Constructors</th>' . '<th colspan="2">Methods</th>' . '<th colspan="2">Properties</th>' . '</tr>' . "\r\n" . '<tr>' . '<th>Done</th><th>All</th>' . '<th>Done</th><th>All</th>' . '<th>Done</th><th>All</th>' . '</tr>' . "\r\n" . '</thead>' . "\r\n" . '<tbody>' . "\r\n"; $allMissing = 0; $allExisting = 0; $types = $this->typestemplate; foreach ($doc->classset as $classset) { list($classoutput, $existing, $missing, $settypes) = $this->calcClassset($classset); $types = $this->addTypes($types, $settypes); $allMissing += $missing; $allExisting += $existing; $output .= $classoutput; } $output .= '<tr class="documentation">' . '<th rowspan="2">Coverage</th>' . $this->getTypesDisplay($types, null) . '</tr>' . '<tr class="documentation">' . $this->getTypesPercentageDisplay($types) . '</tr>' . "\r\n"; $percent = 100 / $allExisting * ($allExisting - $allMissing); $output .= '<tr><th>All in all</th>' . '<th>' . ($allExisting - $allMissing) . '</th>' . '<th>' . $allExisting . '</th>' . '<th class="allpercent" colspan="4" style="background-color:' . $this->getColor($percent) . '">' . number_format($percent, 2) . '%</th>' . '</tr>' . "\r\n" . '<tbody>' . "\r\n"; return $output; }//protected function calcCoverage($doc) public function calcClassset($classset) { $output = ''; $allMissing = 0; $allExisting = 0; $types = $this->typestemplate; foreach ($classset->{'class'} as $class) { list($classoutput, $existing, $missing, $classtypes) = $this->calcClass($class); $types = $this->addTypes($types, $classtypes); $allMissing += $missing; $allExisting += $existing; $output .= $classoutput; } $output .= '<tr class="classset">' . '<th rowspan="2">' . htmlspecialchars((string)$classset['title']) . '</th>' . $this->getTypesDisplay($types, null) . '</tr>' . '<tr class="classset">' . $this->getTypesPercentageDisplay($types) . '</tr>' . "\r\n"; return array($output, $allExisting, $allMissing, $types); } public function calcClass($class) { $classname = htmlspecialchars((string)$class['title']); $types = $this->typestemplate; $allMissing = 0; $allExisting = 0; if (isset($class->type)) { foreach ($class->type as $type) { $title = (string)$type['title']; $types[$title]['missing'] = (string)$type['missing']; $types[$title]['existing'] = (string)$type['existing']; $allMissing += $types[$title]['missing']; $allExisting += $types[$title]['existing']; if (isset($type->missing)) { $this->missingThings .= '<a' . ' name="' . $classname . '-' . $title . '">' . '<h3>' . $classname . ' ' . $title . '</h3>' . '</a>'; foreach ($type->missing as $missing) { $name = (string)$missing['name']; $message = (string)$missing['message']; $this->missingThings .= htmlspecialchars($message) . '<br/>'; } } } } $output = '<tr><td>' . $classname . '</td>' . $this->getTypesDisplay($types, $classname) . '</tr>' . "\r\n"; return array($output, $allExisting, $allMissing, $types); }//public function calcClass($class) function getTypesDisplay($types, $class) { return $this->getTypeDisplay($types['constructors'], $class, 'constructors') . $this->getTypeDisplay($types['methods'] , $class, 'methods') . $this->getTypeDisplay($types['properties'] , $class, 'properties'); }//function getTypesDisplay($types, $class) function getTypesPercentageDisplay($types) { return $this->getTypePercentageDisplay($types['constructors']) . $this->getTypePercentageDisplay($types['methods']) . $this->getTypePercentageDisplay($types['properties']); }//function getTypesPercentageDisplay($types) function getTypeDisplay($type, $class, $typename) { $existing = $type['existing']; $missing = $type['missing']; $done = $existing - $missing; if ($existing != 0) { $percent = intval(100 / $existing * $done); } else { $percent = -100; } $color = $this->getColor($percent); if ($missing > 0 && $class !== null) { $done = '<a href="#' . $class . '-' . $typename . '">' . $done . '</a>'; } $output = '<td style="background-color:' . $color . '">' . $done . '</td>'; $output .= '<td>' . $existing . '</td>'; return $output; }//function getTypeDisplay($type) function getTypePercentageDisplay($type) { $existing = $type['existing']; $missing = $type['missing']; $done = $existing - $missing; if ($existing != 0) { $percent = number_format(100 / $existing * $done, 2); } else { $percent = -100; } $color = $this->getColor($percent); if ($percent == -100) { $percent = ''; } else { $percent .= '%'; } $output = '<td colspan="2" style="background-color:' . $color . '">' . $percent . '</td>'; return $output; }//function getTypePercentageDisplay($type) function getColor($percent) { $percent = intval($percent); if ($percent == -100) { $color = 'white'; } else if ($percent == 100) { $color = 'green'; } else if ($percent >= 85) { $color = 'yellow'; } else if ($percent >= 50) { $color = 'orange'; } else { $color = 'red'; } return $color; }//function getColor($percent) protected function addTypes($types, $newTypes) { foreach ($newTypes as $name => $numbers) { foreach ($numbers as $numtitle => $number) { $types[$name][$numtitle] += $number; } } return $types; }//protected function addTypes($types, $newTypes) }//class ClassCoverageAnalysis $da = new ClassCoverageAnalysis(); echo $da->run(); ?>