didou Sat Mar 3 03:05:34 2007 UTC
Added files:
/phpdoc/scripts/check_phpdoc build.php view_check_phpdoc.php
Log:
Add a new tool that checks the documentation on various issues
Example output on http://didou.php.free.fr/view_check_phpdoc.php5
http://cvs.php.net/viewvc.cgi/phpdoc/scripts/check_phpdoc/build.php?view=markup&rev=1.1
Index: phpdoc/scripts/check_phpdoc/build.php
+++ phpdoc/scripts/check_phpdoc/build.php
<?php
/*
+----------------------------------------------------------------------+
| PHP Version 4 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| [EMAIL PROTECTED] so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Mehdi Achour <[EMAIL PROTECTED]> |
+----------------------------------------------------------------------+
$Id: build.php,v 1.1 2007/03/03 03:05:33 didou Exp $
*/
/**
* @todo
* Improve support for deprecated functions (introduce a new entity in phpdoc?)
* Check for role="reference" on parameters
* Check against php-src for parameters/return values (parse the C code, not
protos)
* Add various tests for parameters
*/
error_reporting(E_ALL);
$status = array();
foreach (glob('../en/reference/*/*/*.xml') as $function) {
$path = explode('/', $function);
$extension = $path[count($path) - 3];
$funcname = basename($function);
// Skip main
if ($funcname == 'main.xml') {
continue;
}
$xmlstr = str_replace('&', '&', file_get_contents($function));
$xml = new DOMDocument();
$xml->preserveWhiteSpace = false;
if ([EMAIL PROTECTED]>loadXml($xmlstr)) {
echo "XML Parse Error: $function\n";
continue;
}
// Variables initialisation
$noparameters = false;
$returnvoid = false;
$refsect1s = $xml->getElementsByTagName('refsect1');
foreach ($refsect1s as $refsect1) {
$role = $refsect1->getAttribute('role');
switch ($role) {
case 'description':
// Get text buffer for various checks
$whole_description = $refsect1->nodeValue;
// If not documented, mark it and skip to next function
if (strpos($whole_description, '&warn.undocumented.func;') !==
false) {
$status[$extension][$funcname]['undoc'] = 1;
continue 3;
}
// If deprecated, skip to next function
// @todo: add a better way of handling this (new entity in
phpdoc?)
if (strpos($whole_description, 'This function is deprecated')
!== false) {
continue 3;
}
// If an alias, skip to next function
if (strpos($whole_description, '&info.function.alias;') !==
false) {
continue 3;
} else {
$refnamedivs = $xml->getElementsByTagName('refnamediv');
foreach ($refnamedivs as $refnamediv) {
if (stripos($refnamediv->nodeValue, 'alias') !== false)
{
continue 4;
}
}
}
// Look into the methodsynopsys tag(s)
$methodsynopsiss =
$xml->getElementsByTagName('methodsynopsis');
foreach ($methodsynopsiss as $methodsynopsis) {
foreach ($methodsynopsis->childNodes as $child) {
switch ($child->nodeName) {
case '#comment':
// Skip comments
continue;
case 'type':
// This is the return type
break;
case 'void':
// This either the return type or 0 parameters
if (!isset($methodname)) {
$returnvoid = true;
} else { // no parameters
$noparameters = true;
}
break;
case 'methodname':
$methodname = $child->nodeValue;
break;
case 'methodparam':
break;
default:
echo 'Unknown child for methodsynopsis: ' .
$child->nodeName . "\n";
}
}
}
break;
case 'returnvalues':
case 'parameters':
case 'seealso':
case 'examples':
case 'notes':
case 'changelog':
case 'errors':
// test order
switch ($role) {
case 'parameters':
if (isset($notes) && isset($changelog) &&
isset($returnvalues) && isset($examples) && isset($seealso)) {
$status[$extension][$funcname]['badorder'] = 1;
}
break;
case 'returnvalues':
if (isset($notes) && isset($changelog) &&
isset($examples) && isset($seealso)) {
$status[$extension][$funcname]['badorder'] = 1;
}
break;
case 'changelog':
if (isset($notes) && isset($examples) &&
isset($seealso)) {
$status[$extension][$funcname]['badorder'] = 1;
}
break;
case 'examples':
if (isset($notes) && isset($seealso)) {
$status[$extension][$funcname]['badorder'] = 1;
}
break;
case 'notes':
if (isset($seealso)) {
$status[$extension][$funcname]['badorder'] = 1;
}
break;
}
$$role = 1;
$whole_content = $refsect1->nodeValue;
// Check for default stub generated by xml_proto
if ($role == 'returnvalues' && strpos($whole_content, 'What the
function returns, first on success, then on failure.') !== false) {
unset($returnvalues);
}
break;
default:
if ($role != '') {
$status[$extension][$funcname]['roleerror'] = 1;
} else {
$status[$extension][$funcname]['oldstyle'] = 1;
// Skip the remaining refsect1
continue 3;
}
}
}
// See also checks
if (!isset($seealso)) {
$status[$extension][$funcname]['noseealso'] = 1;
}
unset($seealso);
// Return Values
if (!isset($returnvalues)) {
$status[$extension][$funcname]['noreturnvalues'] = 1;
}
unset($returnvalues);
// Parameters
if (!isset($parameters) && !$noparameters) {
$status[$extension][$funcname]['noparameters'] = 1;
}
unset($parameters);
// Examples checks
if (!isset($examples)) {
$status[$extension][$funcname]['noexamples'] = 1;
}
unset($examples);
// Errors checks
if (!isset($errors)) {
$status[$extension][$funcname]['noerrors'] = 1;
}
unset($errors);
}
$idx = sqlite_open("check_phpdoc.sqlite");
$qry_str = '
DROP TABLE IF EXISTS reference;
CREATE TABLE reference (
extension char(40),
funcname char(200),
oldstyle integer,
undoc integer,
roleerror integer,
badorder integer,
noseealso integer,
noreturnvalues integer,
noparameters integer,
noexamples integer,
noerrors integer
);';
foreach ($status as $extension => $functions) {
foreach ($functions as $function => $attrs) {
$qry_str .= 'INSERT INTO reference (extension, funcname, ' . implode(',
', array_keys($attrs)) . ') VALUES ("' . $extension . '", "' . $function . '",
' . implode(', ', $attrs) . ');';
}
}
echo $qry_str;
sqlite_exec($idx, 'BEGIN TRANSACTION; '.$qry_str.' COMMIT');
unset($qry_str);
sqlite_close($idx);
http://cvs.php.net/viewvc.cgi/phpdoc/scripts/check_phpdoc/view_check_phpdoc.php?view=markup&rev=1.1
Index: phpdoc/scripts/check_phpdoc/view_check_phpdoc.php
+++ phpdoc/scripts/check_phpdoc/view_check_phpdoc.php
<?php
/*
+----------------------------------------------------------------------+
| PHP Version 4 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| [EMAIL PROTECTED] so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Mehdi Achour <[EMAIL PROTECTED]> |
+----------------------------------------------------------------------+
$Id: view_check_phpdoc.php,v 1.1 2007/03/03 03:05:33 didou Exp $
*/
/**
* @todo
* Add support for online doc editing
* Add count of "perfect" functions
* Get this on http://doc.php.net/
*/
$errors = array(
'undoc' => array(
'label' => 'Not documented',
'description' => 'These are the undocumented functions: The function which XML
skeleton is in CVS, and contain &warn.undocumented.func;'
),
'oldstyle' => array(
'label' => 'Old style',
'description' => 'These functions are not converted to the new doc style yet,
and thus, are not checked',
),
'badorder' => array(
'label' => 'Bad refsect1 order',
'description' => 'These functions are converted to the new doc style, but the
refsect1 are not well ordered',
),
'noparameters' => array(
'label' => 'No parameters',
'description' => 'These functions lacks parameters description.',
),
'noreturnvalues' => array(
'label' => 'No return values',
'description' => 'These functions lacks return values information',
),
'noexamples' => array(
'label' => 'No examples',
'description' => 'These functions lacks examples.',
),
'noerrors' => array(
'label' => 'No errors section',
'description' => 'These functions lacks errors information.',
),
'noseealso' => array(
'label' => 'No see also',
'description' => 'These functions lacks link to other functions/sections. You
may consider adding some cross links to point readers to valuable resources.',
),
'roleerror' => array(
'label' => 'Refsect1 role error',
'description' => 'One or more <refsect1> tags use an unknown role
attribute value',
),
);
$restrict = (isset($_GET['restrict']) && isset($errors[$_GET['restrict']])) ?
$_GET['restrict'] : false;
echo '<?xml version="1.0"?>' . "\n";
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>PHPDOC Check<?php
if ($restrict && isset($errors[$restrict])) {
echo ' > ' . $errors[$restrict]['label'];
}
?></title>
<style>
* { font-family:verdana,arial,helvetica,sans-serif; font-size:98%;}
h1, h2 { font-size:130%; color:#000066; font-weight:bold;}
tr.h:hover { background-color: #FAEBD7;}
dt {color: #000066;font-weight: bold;}
dd {font-style: italic;}
tr.header {background-color:#000066;color:#fff;}
tr.subheader {background-color:#E0E0E0;color:#000066;font-size: 95%;}
td.err {background-color: #f00;}
h2 { margin: 0; margin-top: 10px;}
</style>
</head>
<body>
<?php
$dbhandle = sqlite_open('check_phpdoc.sqlite');
$where = '';
if ($restrict) {
$where = ' WHERE ' . $restrict . ' = 1';
}
$query = sqlite_query($dbhandle, 'SELECT * FROM reference' . $where);
$status = array();
$result = sqlite_fetch_all($query, SQLITE_ASSOC);
foreach ($result as $res) {
$status[$res['extension']][$res['funcname']] = $res;
}
echo '<h1>PHPDOC Check</h1>';
if (!$restrict) {
echo '<p>
This script parses the <i>reference/</i> directory of the PHPDOC module and
checks for common problems in the documentation. For now, supported tests are:
<ul>';
foreach ($errors as $type => $info) {
echo "<li>{$errors[$type]['label']} (<a
href=\"{$_SERVER['PHP_SELF']}?restrict=$type\">Restrict</a>)</li>";
}
echo ' </ul>
</p>';
$exts = '';
$funcn = 0;
foreach ($status as $extension => $functions) {
$nb = count($functions);
if ($nb != 0) {
$funcn += $nb;
$exts .= '<a href="#' . $extension . '">' . $extension . '</a> ';
}
}
echo "The following $funcn functions from " . count($status) . " extensions
lacks some information: $exts";
echo '</p>';
echo '<table width="100%">';
$cols = count($errors) + 1;
foreach ($status as $extension => $functions) {
// Skip if no functions
if (count($functions) == 0) {
continue;
}
echo '<tr class="header" id="' . $extension . '"><td colspan="' . $cols
. '" align="center">' . $extension . ' (' . count($functions) . ')</td></tr>';
echo '<tr class="subheader">
<td></td>
<td>Not documented</td>
<td>Old Style</td>
<td>Bad refsect1 order</td>
<td>No parameters</td>
<td>No return values</td>
<td>No examples</td>
<td>No errors</td>
<td>No see also</td>
<td>Role error</td>
</tr>';
foreach ($functions as $function => $problems) {
echo "<tr class=\"h\">
<td><a href=\"http://php.net/" . substr($function, 0, -4) .
"\">$function</a></td>";
echo "<td" . (isset($problems['undoc']) ? ' class="err">' : '>') .
"</td>";
echo "<td" . (isset($problems['oldstyle']) ? ' class="err">' : '>')
. "</td>";
echo "<td" . (isset($problems['badorder']) ? ' class="err">' : '>')
. "</td>";
echo "<td" . (isset($problems['noparameters']) ? ' class="err">' :
'>') . "</td>";
echo "<td" . (isset($problems['noreturnvalues']) ? ' class="err">'
: '>') . "</td>";
echo "<td" . (isset($problems['noexamples']) ? ' class="err">' :
'>') . "</td>";
echo "<td" . (isset($problems['noerrors']) ? ' class="err">' : '>')
. "</td>";
echo "<td" . (isset($problems['noseealso']) ? ' class="err">' :
'>') . "</td>";
echo "<td" . (isset($problems['roleerror']) ? ' class="err">' :
'>') . "</td>";
echo "</tr>";
}
}
echo '</table>';
} else {
$type = $restrict;
echo '<p>
<dl>';
echo "<dt>{$errors[$type]['label']} (<a
href=\"{$_SERVER['PHP_SELF']}\">All</a>)</dt><dd>{$errors[$type]['description']}</dd>";
echo ' </dl>
</p>';
echo '<p>';
foreach ($status as $extension => $functions) {
$nb = count($functions);
if ($nb != 0) {
$funcn += $nb;
$exts .= '<a href="#' . $extension . '">' . $extension . '</a> ';
}
}
echo "$funcn functions from " . count($status) . " extensions: $exts";
echo '
</p>';
echo '<table width="100%">';
foreach ($status as $extension => $functions) {
echo '<tr class="header" id="' . $extension . '"><td align="center">' .
$extension . ' (' . count($functions) . ')</td></tr>';
foreach ($functions as $function => $problems) {
if (!isset($problems[$type])) {
continue;
}
echo "<tr>
<td><a href=\"http://php.net/" . substr($function, 0, -4) .
"\">$function</a></td>";
echo "</tr>";
}
}
echo '</table>';
}
?></body>
</html>