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('&', '&amp;', 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 &lt;refsect1&gt; 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>

Reply via email to