Skip to content

Commit

Permalink
Issue phpDocumentor#335 - Add support for @Covers
Browse files Browse the repository at this point in the history
  • Loading branch information
CloCkWeRX committed Mar 31, 2012
1 parent 18524ec commit 698d000
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/phpDocumentor/Plugin/Core/Listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public function applyBehaviours(sfEvent $data)
new phpDocumentor_Plugin_Core_Transformer_Behaviour_Tag_Property(),
new phpDocumentor_Plugin_Core_Transformer_Behaviour_Tag_Method(),
new phpDocumentor_Plugin_Core_Transformer_Behaviour_Tag_Uses(),
new phpDocumentor_Plugin_Core_Transformer_Behaviour_Tag_Covers(),
new phpDocumentor_Plugin_Core_Transformer_Behaviour_Tag_Author(),
new phpDocumentor_Plugin_Core_Transformer_Behaviour_Tag_License(),
new phpDocumentor_Plugin_Core_Transformer_Behaviour_Tag_Internal(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ public static function create(
$namespace, $namespace_aliases, $xml, $tag
);
break;
case 'covers':
$def = new phpDocumentor_Plugin_Core_Parser_DocBlock_Tag_Definition_Covers(
$namespace, $namespace_aliases, $xml, $tag
);
break;
case 'link':
$def = new phpDocumentor_Plugin_Core_Parser_DocBlock_Tag_Definition_Link(
$namespace, $namespace_aliases, $xml, $tag
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
/**
* phpDocumentor
*
* PHP Version 5
*
* @category phpDocumentor
* @package Parser
* @subpackage Tag_Definitions
* @author Mike van Riel <mike.vanriel@naenius.com>
* @copyright 2010-2011 Mike van Riel / Naenius. (http://www.naenius.com)
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://phpdoc.org
*/

/**
* Definition for the @covers tag; expands the class mentioned in the refers
* attribute.
*
* @category phpDocumentor
* @package Parser
* @subpackage Tag_Definitions
* @author Mike van Riel <mike.vanriel@naenius.com>
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://phpdoc.org
*/
class phpDocumentor_Plugin_Core_Parser_DocBlock_Tag_Definition_Covers
extends phpDocumentor_Plugin_Core_Parser_DocBlock_Tag_Definition_See
{

}
176 changes: 176 additions & 0 deletions src/phpDocumentor/Plugin/Core/Transformer/Behaviour/Tag/Covers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
<?php
/**
* phpDocumentor
*
* PHP Version 5
*
* @category phpDocumentor
* @package Transformer
* @subpackage Behaviours
* @author Mike van Riel <mike.vanriel@naenius.com>
* @copyright 2010-2011 Mike van Riel / Naenius. (http://www.naenius.com)
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://phpdoc.org
*/

/**
* Behaviour that adds support for the @covers tag
*
* @category phpDocumentor
* @package Transformer
* @subpackage Behaviour
* @author Mike van Riel <mike.vanriel@naenius.com>
* @copyright 2010-2011 Mike van Riel / Naenius. (http://www.naenius.com)
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://phpdoc.org
*/
class phpDocumentor_Plugin_Core_Transformer_Behaviour_Tag_Covers extends
phpDocumentor_Transformer_Behaviour_Abstract
{
/**
* Find all return tags that contain 'self' or '$this' and replace those
* terms for the name of the current class' type.
*
* @param DOMDocument $xml Structure source to apply behaviour onto.
*
* @todo split method into submethods
*
* @return DOMDocument
*/
public function process(DOMDocument $xml)
{
$xpath = new DOMXPath($xml);
$nodes = $xpath->query('//tag[@name=\'covers\']');
/** @var DOMElement $node */
foreach ($nodes as $node) {
$refers = $node->getAttribute('refers');
$refers_array = explode('::', $refers);

// determine the type so we know where to put the @coveredby tag on
$type = 'class';
if (isset($refers_array[1])) {
// starts with $ = property, ends with () = method,
// otherwise constant
$type = $refers_array[1][0] == '$' ? 'property' : 'constant';
$type = substr($refers_array[1], -2) == '()' ? 'method' : $type;
}

switch($type) {
case 'class':
// escape single quotes in the class name
$xpath_refers = 'concat(\''.str_replace(
array("'", '"'),
array('\', "\'", \'', '\', \'"\' , \''),
$refers
) . "', '')";

$qry = '/project/file/class[full_name=' . $xpath_refers . ']';
break;
default:
$class_name = $refers_array[0];

// escape single quotes in the class name
$xpath_class_name = 'concat(\''.str_replace(
array("'", '"'),
array('\', "\'", \'', '\', \'"\' , \''),
$class_name
) . "', '')";

// escape single quotes in the method name
$xpath_method_name = 'concat(\''.str_replace(
array("'", '"'),
array('\', "\'", \'', '\', \'"\' , \''),
rtrim($refers_array[1], '()')
) . "', '')";

$qry = '/project/file/class[full_name=' . $xpath_class_name
. ']/'.$type.'[name=' . $xpath_method_name .']';
break;
}

// get the nodes; we are unable to work around the
// shut up operator as there is no pre-validation possible.
$referral_nodes = @$xpath->query($qry);

// if the query is wrong; output a Critical error and continue to
// the next @covers
if ($referral_nodes === false) {
$this->log(
'An XPath error occurs while processing @covers, '
. 'the query used was: ' . $qry, phpDocumentor_Core_Log::CRIT
);
continue;
}

// check if the result is unique; if not we error and continue
// to the next @covers
if ($referral_nodes->length > 1) {
$this->log(
'@covers "'.$refers.'" refers to more than 1 element',
phpDocumentor_Core_Log::ERR
);
continue;
}

// if there is one matching element; link them together
if ($referral_nodes->length > 0) {
$referral = $referral_nodes->item(0);
$docblock = $referral->getElementsByTagName('docblock');
if ($docblock->length < 1) {
$docblock = new DOMElement('docblock');
$referral->appendChild($docblock);
} else {
$docblock = $docblock->item(0);
}

$used_by = new DOMElement('tag');
$docblock->appendChild($used_by);
$used_by->setAttribute('name', 'used_by');
$used_by->setAttribute('line', '');

// gather the name of the referring element and set that as refers
// attribute
if ($node->parentNode->parentNode->nodeName == 'class') {
// if the element where the @covers is in is a class; nothing
// more than the class name need to returned
$referral_name = $node->parentNode->parentNode
->getElementsByTagName('full_name')->item(0)->nodeValue;
} else {

$referral_class_name = null;
if ($node->parentNode->parentNode->nodeName == 'method') {
// gather the name of the class where the @covers is in
$referral_class_name = $node->parentNode->parentNode
->parentNode->getElementsByTagName('full_name')->item(0)
->nodeValue;
}

// gather the name of the subelement of the class where
// the @covers is in
$referral_name = $node->parentNode->parentNode
->getElementsByTagName('name')->item(0)->nodeValue;

// if it is a method; suffix with ()
if ($node->parentNode->parentNode->nodeName == 'method'
|| $node->parentNode->parentNode->nodeName == 'function'
) {
$referral_name .= '()';
}

// only prefix class name if this is a class member
if ($referral_class_name) {
$referral_name = $referral_class_name . '::'
. $referral_name;
}
}

$used_by->setAttribute('description', $referral_name);
$used_by->setAttribute('refers', $referral_name);
}
}

return $xml;
}

}

0 comments on commit 698d000

Please sign in to comment.