Compare commits

...
30 Commits
Author SHA1 Message Date
Mike van Riel 6b707f7166 Change behaviour of @param parsing
In issue report phpDocumentor/phpDocumentor2#620 @bobef reported that when he
used just a Type as content of the @param that it would be recognized as
description instead of the Type.

According to the unit tests this is correct behaviour but after reviewing the
pattern of the output his version is more consistent. As such I have altered
the behaviour to act as following:

If only one word is found after an @param (word means white-space bounded
series of characters) then interpret that as the type and not description.

During this item several issues in unit tests were fixed and a new 'Type'
Collection was introduced that is capable of expanding types based on a given
namespace and series of aliases.
This should be re-used in phpDocumentor's Transformer as a duplication exists
there with the expanding of the Types.

Please note: the suggested format by @bobef is not valid according to the
PHPDoc Standard but is provided for convenience.
2012-11-03 22:14:43 +01:00
Mike van Riel 5236694595 Merge branch 'patch-2' of https://github.com/boenrobot/ReflectionDocBlock into boenrobot-patch-2
Conflicts:
	src/phpDocumentor/Reflection/DocBlock/LongDescription.php
2012-11-01 18:56:36 +01:00
Vasil Rangelov ce57e5445f Restored the greedy-ness inversion. 2012-10-31 11:28:53 +02:00
Vasil Rangelov 37f5090d90 Removed LongDescription::getTags() and made parsing to occur only the first time it's requested. 2012-10-17 17:33:52 +03:00
Mike van Riel 5941846e99 Merge pull request #7 from boenrobot/patch-3
Reflection for the author tag.
2012-10-15 13:01:19 -07:00
Vasil Rangelov 95ad95d3be Added doc blocks to the new methods. 2012-10-15 13:17:51 +03:00
Mike van Riel aa61de9761 Merge branch 'master' of github.com:phpDocumentor/ReflectionDocBlock 2012-09-30 14:29:16 +02:00
Mike van Riel a935cbfff9 Fix @return type/description seperation
Per issue phpDocumentor/phpDocumentor2#623 should a newline directly behind the type
of a multiline @return tag be interpreted correctly. Currently seperation occurs
on the first space or tab but this is not sufficient.
2012-09-30 14:26:28 +02:00
Vasil Rangelov ee412932f1 Added Tag/AuthorTag.php. 2012-09-30 01:47:50 +03:00
Vasil Rangelov c8fe0e4e40 Added Tag::getParsedDescription();
Minor performance tweak at LongDescription.
2012-09-26 16:27:32 +03:00
Vasil Rangelov ad4e358fb0 Added doc block to getParsedContents(). 2012-09-22 05:56:37 +03:00
Vasil Rangelov 1b3acdce18 Added parsed inline tags. 2012-09-22 05:41:10 +03:00
Mike van Riel 4235beebfa Merge pull request #5 from boenrobot/patch-1
Fix for phpDocumentor2#562
2012-09-16 08:15:18 -07:00
Mike van Riel 60ba10fad1 Multiline @return statements were stripped from their newlines and indent
@return statements (and effectively others) were stripped from their newlines
and indentation. By tweaking the reflection a bit was this effect countered.
2012-09-10 16:50:44 +02:00
Vasil Rangelov f3cca4b7c7 Ensured key consistency. 2012-08-12 23:53:31 +03:00
Vasil Rangelov e0d8988490 Fix for phpDocumentor2#562
Possible fix for phpDocumentor/phpDocumentor2#562.
2012-08-12 20:21:19 +03:00
Mike van Riel 91ef535ae3 #544: Added self and $this to the exceptions where type expansion is not required 2012-07-27 06:56:37 +02:00
Mike van Riel c999e7d32a Removed the prefixing slash in a class_exists call because the autoloader of Composer
dies on that occasionally.
2012-07-26 17:09:50 +02:00
Mike van Riel 2b05ea3221 Fixing the other RegExes as well since they were also not using the u modifier 2012-07-13 20:07:51 +02:00
Mike van Riel 33a2e55cbc Merge pull request #4 from rvanvelzen/master
Add the u modifier to the regexes used.
2012-07-13 10:28:21 -07:00
Richard van Velzen 3d97a72bac Merge branch 'master' of git://github.com/phpDocumentor/ReflectionDocBlock 2012-07-13 13:43:29 +02:00
Richard van Velzen 51210b581e Add the u modifier to the regexes used.
Without the u modifier, PCRE does not recognize Unicode sequences, which breaks certain cases.
2012-07-13 13:42:49 +02:00
Mike van Riel cee3c0bc21 Namespace resolution did not work as intended
The algorithm to expand a class name into a FCQN contained seevral errors.
These are now gone and expansion should work as expected
2012-06-30 13:38:18 +02:00
Mike van Riel 731e797dd8 Added 'global' to the list of special namespace names indicating global space and adding namespace resolution to the param tags 'getType()' method 2012-06-29 23:04:12 +02:00
Mike van Riel 838fbfa43f Added command to set the DocBlock onto the tags so that type expansion may happen 2012-06-21 23:03:48 +02:00
Mike van Riel 4d262053fc Changed return tag to properly support expanding types 2012-06-21 23:00:13 +02:00
Mike van Riel bbac3fa418 Added type expansion for the @param tag 2012-06-21 22:51:29 +02:00
Mike van Riel cd252c1f09 Added support for namespace expansion of a DocBlock and via the DocBlock to its tags 2012-06-21 22:17:30 +02:00
Mike van Riel 8f8cbd9ab6 Merge pull request #3 from rvanvelzen/master
Fix phpDocumentor/phpDocumentor2#467
2012-06-04 13:34:54 -07:00
Richard van Velzen a5b50ba482 Fixed the case where the dot does not properly terminate the short description.
The regular expression only took into account newlines, not general whitespace after the dot. Added a test case as well.
2012-06-04 09:27:56 +02:00
21 changed files with 996 additions and 89 deletions
+2 -1
View File
@@ -1 +1,2 @@
.idea .idea
vendor
+1 -1
View File
@@ -10,6 +10,6 @@
"dflydev/markdown": "1.0.*" "dflydev/markdown": "1.0.*"
}, },
"autoload": { "autoload": {
"psr-0": {"phpDocumentor\\Reflection": "src/"} "psr-0": {"phpDocumentor": ["src/"]}
} }
} }
Generated
+67
View File
@@ -0,0 +1,67 @@
{
"hash": "89c7387ec02d39de3c07849e525f95e4",
"packages": [
{
"name": "dflydev/markdown",
"version": "v1.0.2",
"source": {
"type": "git",
"url": "https://github.com/dflydev/dflydev-markdown.git",
"reference": "v1.0.2"
},
"dist": {
"type": "zip",
"url": "https://github.com/dflydev/dflydev-markdown/zipball/v1.0.2",
"reference": "v1.0.2",
"shasum": ""
},
"require": {
"php": ">=5.3"
},
"time": "2012-01-15 19:36:37",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"dflydev\\markdown": "src"
}
},
"license": [
"New BSD License"
],
"authors": [
{
"name": "Dragonfly Development Inc.",
"email": "[email protected]",
"homepage": "http://dflydev.com"
},
{
"name": "Beau Simensen",
"email": "[email protected]",
"homepage": "http://beausimensen.com"
},
{
"name": "Michel Fortin",
"homepage": "http://michelf.com"
},
{
"name": "John Gruber",
"homepage": "http://daringfireball.net"
}
],
"description": "PHP Markdown & Extra",
"homepage": "http://github.com/dflydev/dflydev-markdown",
"keywords": [
"markdown"
]
}
],
"packages-dev": null,
"aliases": [
],
"minimum-stability": "stable",
"stability-flags": [
]
}
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<phpunit colors="true" strict="true"> <phpunit colors="true" strict="true" bootstrap="vendor/autoload.php">
<testsuites> <testsuites>
<testsuite name="phpDocumentor\Reflection\DocBlock"> <testsuite name="phpDocumentor\Reflection\DocBlock">
<directory>./tests/</directory> <directory>./tests/</directory>
+128 -13
View File
@@ -36,14 +36,36 @@ class DocBlock implements \Reflector
*/ */
protected $tags = array(); protected $tags = array();
/** @var string the current namespace */
protected $namespace = '\\';
/** @var string[] List of namespace aliases => Fully Qualified Namespace */
protected $namespace_aliases = array();
/** /**
* Parses the given docblock and populates the member fields. * Parses the given docblock and populates the member fields.
* *
* @param string|\Reflector $docblock A docblock comment (including asterisks) * The constructor may also receive namespace information such as the
* current namespace and aliases. This information is used in the
* {@link expandType()} method to transform a relative Type into a FQCN.
*
* For example the param and return tags use this to expand their type
* information.
*
* @param \Reflector|string $docblock A docblock comment (including asterisks)
* or reflector supporting the getDocComment method. * or reflector supporting the getDocComment method.
* @param string $namespace The namespace where this DocBlock resides in;
* defaults to `\`.
* @param string[] $namespace_aliases a list of namespace aliases as
* provided by the `use` keyword; the key of the array is the alias name
* or last part of the alias array if no alias name is provided.
*
* @throws \InvalidArgumentException if the given argument does not have the
* getDocComment method.
*/ */
public function __construct($docblock) public function __construct(
{ $docblock, $namespace = '\\', $namespace_aliases = array()
) {
if (is_object($docblock)) { if (is_object($docblock)) {
if (!method_exists($docblock, 'getDocComment')) { if (!method_exists($docblock, 'getDocComment')) {
throw new \InvalidArgumentException( throw new \InvalidArgumentException(
@@ -61,6 +83,9 @@ class DocBlock implements \Reflector
$this->short_description = $short; $this->short_description = $short;
$this->long_description = new DocBlock\LongDescription($long); $this->long_description = new DocBlock\LongDescription($long);
$this->parseTags($tags); $this->parseTags($tags);
$this->namespace = $namespace;
$this->namespace_aliases = $namespace_aliases;
} }
/** /**
@@ -74,7 +99,7 @@ class DocBlock implements \Reflector
{ {
$comment = trim( $comment = trim(
preg_replace( preg_replace(
'#[ \t]*(?:\/\*\*|\*\/|\*)?[ \t]{0,1}(.*)?#', '$1', $comment '#[ \t]*(?:\/\*\*|\*\/|\*)?[ \t]{0,1}(.*)?#u', '$1', $comment
) )
); );
@@ -108,7 +133,7 @@ class DocBlock implements \Reflector
} else { } else {
// clears all extra horizontal whitespace from the line endings // clears all extra horizontal whitespace from the line endings
// to prevent parsing issues // to prevent parsing issues
$comment = preg_replace('~(?m)\h*$~', '', $comment); $comment = preg_replace('~(?m)\h*$~u', '', $comment);
/* /*
* Splits the docblock into a short description, long description and * Splits the docblock into a short description, long description and
@@ -127,11 +152,11 @@ class DocBlock implements \Reflector
preg_match( preg_match(
'/(?x) '/(?x)
\A ( \A (
[^\n]+ [^\n.]+
(?: (?:
(?! (?<=\.) \n | \n{2} ) # disallow the first seperator here (?! \. \s | \n{2} ) # disallow the first seperator here
\n (?! [ \t]* @\pL ) # disallow second seperator [\n.] (?! [ \t]* @\pL ) # disallow second seperator
[^\n]+ [^\n.]+
)* )*
\.? \.?
) )
@@ -148,7 +173,7 @@ class DocBlock implements \Reflector
) )
)? )?
(\s+ [\s\S]*)? # everything that follows (\s+ [\s\S]*)? # everything that follows
/', $comment, $matches /u', $comment, $matches
); );
array_shift($matches); array_shift($matches);
} }
@@ -174,8 +199,6 @@ class DocBlock implements \Reflector
continue; continue;
} }
$tag_line = ltrim($tag_line);
if (isset($tag_line[0]) && ($tag_line[0] === '@')) { if (isset($tag_line[0]) && ($tag_line[0] === '@')) {
$result[] = $tag_line; $result[] = $tag_line;
} else { } else {
@@ -192,7 +215,9 @@ class DocBlock implements \Reflector
// create proper Tag objects // create proper Tag objects
foreach ($result as $key => $tag_line) { foreach ($result as $key => $tag_line) {
$result[$key] = DocBlock\Tag::createInstance($tag_line); $tag = DocBlock\Tag::createInstance($tag_line);
$tag->setDocBlock($this);
$result[$key] = $tag;
} }
$this->tags = $result; $this->tags = $result;
@@ -271,6 +296,84 @@ class DocBlock implements \Reflector
return false; return false;
} }
/**
* Tries to expand a type to it's full namespaced equivalent (FQCN).
*
* This method will take the given type and examine the current namespace
* and namespace aliases to see whether it should expand it into a FQCN
* as defined by the rules in PHP.
*
* @param string $type Type to expand into full namespaced
* equivalent.
* @param string[] $ignore_keywords Whether to ignore given keywords, when
* null it will use the default keywords: 'string', 'int', 'integer',
* 'bool', 'boolean', 'float', 'double', 'object', 'mixed', 'array',
* 'resource', 'void', 'null', 'callback', 'false', 'true'.
* Default value for this parameter is null.
*
* @return string
*/
public function expandType($type, $ignore_keywords = null)
{
if ($type === null) {
return null;
}
if ($ignore_keywords === null) {
$ignore_keywords = array(
'string', 'int', 'integer', 'bool', 'boolean', 'float', 'double',
'object', 'mixed', 'array', 'resource', 'void', 'null',
'callback', 'false', 'true', 'self', '$this', 'callable'
);
}
$namespace = '\\';
if ($this->namespace != 'default' && $this->namespace != 'global') {
$namespace = rtrim($this->namespace, '\\') . '\\';
}
$type = explode('|', $type);
foreach ($type as &$item) {
$item = trim($item);
// add support for array notation
$is_array = false;
if (substr($item, -2) == '[]') {
$item = substr($item, 0, -2);
$is_array = true;
}
if ((substr($item, 0, 1) != '\\')
&& (!in_array(strtolower($item), $ignore_keywords))
) {
$type_parts = explode('\\', $item);
// if the first segment is an alias; replace with full name
if (isset($this->namespace_aliases[$type_parts[0]])) {
$type_parts[0] = $this->namespace_aliases[$type_parts[0]];
$item = implode('\\', $type_parts);
} else {
// otherwise prepend the current namespace
$item = $namespace . $item;
}
}
// full paths always start with a slash
if (isset($item[0]) && ($item[0] !== '\\')
&& (!in_array(strtolower($item), $ignore_keywords))
) {
$item = '\\' . $item;
}
// re-add the array notation markers
if ($is_array) {
$item .= '[]';
}
}
return implode('|', $type);
}
/** /**
* Builds a string representation of this object. * Builds a string representation of this object.
* *
@@ -295,4 +398,16 @@ class DocBlock implements \Reflector
return 'Not yet implemented'; return 'Not yet implemented';
} }
/**
* @return string
*/
public function getNamespace()
{
return $this->namespace;
}
public function getNamespaceAliases()
{
return $this->namespace_aliases;
}
} }
@@ -2,7 +2,7 @@
/** /**
* phpDocumentor * phpDocumentor
* *
* PHP Version 5 * PHP Version 5.3
* *
* @author Mike van Riel <[email protected]> * @author Mike van Riel <[email protected]>
* @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com)
@@ -24,6 +24,9 @@ class LongDescription implements \Reflector
/** @var string */ /** @var string */
protected $contents = ''; protected $contents = '';
/** @var array The contents, as an array of strings and Tag objects. */
protected $parsedContents = null;
/** @var \phpDocumentor\Reflection\DocBlock\Tags[] */ /** @var \phpDocumentor\Reflection\DocBlock\Tags[] */
protected $tags = array(); protected $tags = array();
@@ -35,13 +38,6 @@ class LongDescription implements \Reflector
*/ */
public function __construct($content) public function __construct($content)
{ {
if (preg_match('/\{\@(.+?)\}/', $content, $matches)) {
array_shift($matches);
foreach ($matches as $tag) {
$this->tags[] = Tag::createInstance('@' . $tag);
}
}
$this->contents = trim($content); $this->contents = trim($content);
} }
@@ -55,6 +51,28 @@ class LongDescription implements \Reflector
return $this->contents; return $this->contents;
} }
/*
* Returns the parsed text of this description.
*
* @return array An array of strings and tag objects, in the order they
* occur within the description.
*/
public function getParsedContents()
{
if (null === $this->parsedContents) {
$this->parsedContents = preg_split(
'/\{(\@.*?)\}/uS', $this->contents,
null, PREG_SPLIT_DELIM_CAPTURE
);
for ($i=1, $l = count($this->parsedContents); $i<$l; $i += 2) {
$this->parsedContents[$i] = Tag::createInstance(
$this->parsedContents[$i]
);
}
}
return $this->parsedContents;
}
/** /**
* Return a formatted variant of the Long Description using MarkDown. * Return a formatted variant of the Long Description using MarkDown.
* *
@@ -78,7 +96,7 @@ class LongDescription implements \Reflector
); );
} }
if (class_exists('\dflydev\markdown\MarkdownExtraParser')) { if (class_exists('dflydev\markdown\MarkdownExtraParser')) {
$md = new \dflydev\markdown\MarkdownExtraParser(); $md = new \dflydev\markdown\MarkdownExtraParser();
$result = $md->transformMarkdown($result); $result = $md->transformMarkdown($result);
} }
@@ -86,16 +104,6 @@ class LongDescription implements \Reflector
return trim($result); return trim($result);
} }
/**
* Returns a list of tags mentioned in the text.
*
* @return \phpDocumentor\Reflection\DocBlock\Tags[]
*/
public function getTags()
{
return $this->tags;
}
/** /**
* Builds a string representation of this object. * Builds a string representation of this object.
* *
+22 -4
View File
@@ -24,16 +24,19 @@ class Tag implements \Reflector
/** @var string Name of the tag */ /** @var string Name of the tag */
protected $tag = ''; protected $tag = '';
/** @var string content of the tag */ /** @var string Content of the tag */
protected $content = ''; protected $content = '';
/** @var string description of the content of this tag */ /** @var string Description of the content of this tag */
protected $description = ''; protected $description = '';
/** @var array The description, as an array of strings and Tag objects. */
protected $parsedDescription = null;
/** @var int line number of the tag */ /** @var int Line number of the tag */
protected $line_number = 0; protected $line_number = 0;
/** @var object docblock class */ /** @var \phpDocumentor\Reflection\DocBlock docblock class */
protected $docblock; protected $docblock;
/** /**
@@ -108,6 +111,21 @@ class Tag implements \Reflector
{ {
return $this->description; return $this->description;
} }
/*
* Returns the parsed text of this description.
*
* @return array An array of strings and tag objects, in the order they
* occur within the description.
*/
public function getParsedDescription()
{
if (null === $this->parsedDescription) {
$description = new LongDescription($this->description);
$this->parsedDescription = $description->getParsedContents();
}
return $this->parsedDescription;
}
/** /**
* Set the tag line number * Set the tag line number
@@ -0,0 +1,68 @@
<?php
/**
* phpDocumentor
*
* PHP Version 5
*
* @author Mike van Riel <[email protected]>
* @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
*/
namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tag;
/**
* Reflection class for an @author tag in a Docblock.
*
* @author Mike van Riel <[email protected]>
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://phpdoc.org
*/
class AuthorTag extends Tag
{
/** @var string The name of the author */
protected $name = '';
/** @var string The email of the author */
protected $email = '';
/**
* Parses a tag and populates the member variables.
*
* @param string $type Name of the tag.
* @param string $content The contents of the given tag.
*/
public function __construct($type, $content)
{
parent::__construct($type, $content);
if (preg_match('/^([^\<]*)(\<([^\>]*)\>)?$/', $content, $matches)) {
$this->name = trim($matches[1]);
if (isset($matches[3])) {
$this->email = trim($matches[3]);
}
}
}
/**
* Gets the author's name.
*
* @return string The author's name.
*/
public function getAuthorName()
{
return $this->name;
}
/**
* Gets the author's email.
*
* @return string The author's email.
*/
public function getAuthorEmail()
{
return $this->email;
}
}
@@ -23,7 +23,7 @@ use phpDocumentor\Reflection\DocBlock\Tag;
class ParamTag extends Tag class ParamTag extends Tag
{ {
/** @var string */ /** @var string */
protected $type = null; protected $type = '';
/** /**
* @var string * @var string
@@ -33,7 +33,7 @@ class ParamTag extends Tag
/** /**
* Parses a tag and populates the member variables. * Parses a tag and populates the member variables.
* *
* @param string $type Tag identifier for this tag (should be 'return') * @param string $type Tag identifier for this tag (should be 'param')
* @param string $content Contents for this tag. * @param string $content Contents for this tag.
*/ */
public function __construct($type, $content) public function __construct($type, $content)
@@ -42,13 +42,13 @@ class ParamTag extends Tag
$this->content = $content; $this->content = $content;
$content = preg_split('/\s+/u', $content); $content = preg_split('/\s+/u', $content);
// if there is only 1, it is either a piece of content or a variable name // if the first item that is encountered is not a variable; it is a type
if (count($content) > 1) { if (isset($content[0]) && (strlen($content[0]) > 0) && ($content[0][0] !== '$')) {
$this->type = array_shift($content); $this->type = array_shift($content);
} }
// if the next item starts with a $ it must be the variable name // if the next item starts with a $ it must be the variable name
if ((strlen($content[0]) > 0) && ($content[0][0] == '$')) { if (isset($content[0]) && (strlen($content[0]) > 0) && ($content[0][0] == '$')) {
$this->variableName = array_shift($content); $this->variableName = array_shift($content);
} }
@@ -62,9 +62,13 @@ class ParamTag extends Tag
*/ */
public function getTypes() public function getTypes()
{ {
$types = explode('|', $this->type); $types = new \phpDocumentor\Reflection\DocBlock\Type\Collection(
array_walk($types, 'trim'); array($this->type),
return $types; $this->docblock ? $this->docblock->getNamespace() : null,
$this->docblock ? $this->docblock->getNamespaceAliases() : array()
);
return $types->getArrayCopy();
} }
/** /**
@@ -74,7 +78,7 @@ class ParamTag extends Tag
*/ */
public function getType() public function getType()
{ {
return $this->type; return implode('|', $this->getTypes());
} }
/** /**
@@ -34,7 +34,8 @@ class ReturnTag extends ParamTag
{ {
$this->tag = $type; $this->tag = $type;
$this->content = $content; $this->content = $content;
$content = preg_split('/\s+/u', $content);
$content = preg_split('/[\ \t]+/u', $content, 2);
// any output is considered a type // any output is considered a type
$this->type = array_shift($content); $this->type = array_shift($content);
@@ -42,25 +43,4 @@ class ReturnTag extends ParamTag
$this->description = implode(' ', $content); $this->description = implode(' ', $content);
} }
/**
* Returns the type of the variable.
*
* @return string
*/
public function getTypes()
{
$types = explode('|', $this->type);
array_walk($types, 'trim');
return $types;
}
/**
* Returns the type of the variable.
*
* @return string
*/
public function getType()
{
return $this->type;
}
} }
@@ -0,0 +1,248 @@
<?php
namespace phpDocumentor\Reflection\DocBlock\Type;
class Collection extends \ArrayObject
{
/** @var string Definition of the OR operator for types */
const OPERATOR_OR = '|';
/** @var string Definition of the ARRAY operator for types */
const OPERATOR_ARRAY = '[]';
/** @var string Definition of the NAMESPACE operator in PHP */
const OPERATOR_NAMESPACE = '\\';
/** @var string[] List of recognized keywords */
protected $keywords = array(
'string', 'int', 'integer', 'bool', 'boolean', 'float', 'double',
'object', 'mixed', 'array', 'resource', 'void', 'null',
'callback', 'callable', 'false', 'true', 'self', '$this', 'static'
);
/**
* Current namespace of the invoking location.
*
* This string is used to prepend to type with a relative location.
* May also be 'default' or 'global', in which case they are ignored.
*
* @var string
*/
protected $namespace = '\\';
/**
* Associative array of alias => namespace pairs.
*
* @var string[]
*/
protected $namespace_aliases = array();
/**
* Registers the namespace and aliases; uses that to add and expand the
* given types.
*
* @param string[] $types Array containing a list of types
* to add to this container.
* @param string|null $namespace The namespace where the types in
* this container are relative to; used to expand any relative
* namespaces.
* @param string[] $namespace_aliases An array containing alias => FQNN
* pairs that are used in the resolving process.
*/
public function __construct(
array $types = array(), $namespace = null,
array $namespace_aliases = array()
) {
// only set the namespace if overridden
if (is_string($namespace)) {
$this->setNamespace($namespace);
}
$this->namespace_aliases = $namespace_aliases;
foreach($types as $type) {
$this->add($type);
}
}
/**
* Returns the namespace name used to expand relative namespaces with.
*
* @return string
*/
public function getNamespace()
{
return $this->namespace;
}
/**
* Sets the namespace which is used to resolve types with relative
* namespaces.
*
* Unless the name of the current namespace if default or global we make
* sure the namespace is succeeded with a '\'. This makes it clear for
* the processing functions that a leading slash is present.
*
* @param string $namespace
*
* @return void
*/
public function setNamespace($namespace)
{
if ($namespace != 'default' && $namespace != 'global') {
$namespace = self::OPERATOR_NAMESPACE
. trim($namespace, self::OPERATOR_NAMESPACE)
. self::OPERATOR_NAMESPACE;
} else {
$namespace = '\\';
}
$this->namespace = $namespace;
}
/**
* Returns the list of namespace aliases used to expand the typed with.
*
* @return string[] An associative array of Alias => Fully Qualified
* Namespace Names.
*/
public function getNamespaceAliases()
{
return $this->namespace_aliases;
}
/**
* Sets the namespace aliases to expand the added types.
*
* @param string[] $namespace_aliases An associative array of Alias => Fully
* Qualified Namespace Names.
*
* @return void
*/
public function setNamespaceAliases($namespace_aliases)
{
$this->namespace_aliases = $namespace_aliases;
}
/**
* Adds a new type to the collection and expands it if it contains a
* relative namespace.
*
* If a class in the type contains a relative namespace than this collection
* will try to expand that into a FQCN.
*
* @param string $type A 'Type' as defined in the phpDocumentor
* documentation.
*
* @throws \InvalidArgumentException if a non-string argument is passed.
*
* @see http://phpdoc.org/docs/latest/for-users/types.html for the
* definition of a type.
*
* @return void
*/
public function add($type)
{
if (!is_string($type)) {
throw new \InvalidArgumentException(
'A type should be represented by a string, received: '
.var_export($type, true)
);
}
// separate the type by the OR operator
$type_parts = explode(self::OPERATOR_OR, $type);
foreach($type_parts as $part) {
$expanded_type = $this->expand($part);
if ($expanded_type) {
$this[] = $expanded_type;
}
}
}
/**
* Analyzes the given type and returns the FQCN variant.
*
* When a type is provided this method checks whether it is not a keyword or
* Fully Qualified Class Name. If so it will use the given namespace and
* aliases to expand the type to a FQCN representation.
*
* This method only works as expected if the namespace and aliases are set;
* no dynamic reflection is being performed here.
*
* @uses getNamespace to determine with what to prefix the type name.
* @uses getNamespaceAliases to check whether the first part of the relative
* type name should not be replaced with another namespace.
*
* @param string $type The relative or absolute type.
*
* @return string
*/
protected function expand($type)
{
$type = trim($type);
if (!$type) {
return '';
}
if ($this->isTypeAnArray($type)) {
return $this->expand(substr($type, 0, -2)).self::OPERATOR_ARRAY;
}
if ($this->isRelativeType($type) && !$this->isTypeAKeyword($type)) {
$type_parts = explode(self::OPERATOR_NAMESPACE, $type);
// if the first segment is not an alias; prepend namespace name and
// return
if (!isset($this->namespace_aliases[$type_parts[0]])) {
return $this->getNamespace() . $type;
}
$type_parts[0] = $this->namespace_aliases[$type_parts[0]];
$type = implode(self::OPERATOR_NAMESPACE, $type_parts);
}
return $type;
}
/**
* Detects whether the given type represents an array.
*
* @param string $type A relative or absolute type as defined in the
* phpDocumentor documentation.
*
* @return bool
*/
protected function isTypeAnArray($type)
{
return (substr($type, -2) == self::OPERATOR_ARRAY);
}
/**
* Detects whether the given type represents a PHPDoc keyword.
*
* @param string $type A relative or absolute type as defined in the
* phpDocumentor documentation.
*
* @return bool
*/
protected function isTypeAKeyword($type)
{
return in_array(strtolower($type), $this->keywords);
}
/**
* Detects whether the given type represents a relative or absolute path.
*
* This method will detect keywords as being absolute; even though they are
* not preceeded by a namespace separator.
*
* @param string $type A relative or absolute type as defined in the
* phpDocumentor documentation.
*
* @return bool
*/
protected function isRelativeType($type)
{
return ($type[0] !== self::OPERATOR_NAMESPACE)
|| $this->isTypeAKeyword($type);
}
}
@@ -8,10 +8,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
require_once __DIR__.'/../../../../../src/phpDocumentor/Reflection/DocBlock/Tag.php';
require_once __DIR__.'/../../../../../src/phpDocumentor/Reflection/DocBlock/Tag/SeeTag.php';
require_once __DIR__.'/../../../../../src/phpDocumentor/Reflection/DocBlock/Tag/CoversTag.php';
/** /**
* Test class for phpDocumentor_Reflection_DocBlock_Tag_Covers * Test class for phpDocumentor_Reflection_DocBlock_Tag_Covers
* *
@@ -8,8 +8,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
require_once __DIR__ . '/../../../../../src/phpDocumentor/Reflection/DocBlock/Tag/LinkTag.php';
/** /**
* Test class for \phpDocumentor\Reflection\DocBlock\Tag\LinkTag * Test class for \phpDocumentor\Reflection\DocBlock\Tag\LinkTag
* *
@@ -8,9 +8,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
require_once __DIR__ . '/../../../../../src/phpDocumentor/Reflection/DocBlock/Tag/ParamTag.php';
require_once __DIR__ . '/../../../../../src/phpDocumentor/Reflection/DocBlock/Tag/MethodTag.php';
/** /**
* Test class for \phpDocumentor\Reflection\DocBlock\Tag\MethodTag * Test class for \phpDocumentor\Reflection\DocBlock\Tag\MethodTag
* *
@@ -0,0 +1,67 @@
<?php
/**
* phpDocumentor Param tag test.
*
* @author Mike van Riel <[email protected]>
* @copyright Copyright (c) 2010-2011 Mike van Riel / Naenius. (http://www.naenius.com)
*/
namespace phpDocumentor\Reflection\DocBlock\Tag;
/**
* Test class for phpDocumentor_Reflection_DocBlock_Param.
*
* @author Mike van Riel <[email protected]>
* @copyright Copyright (c) 2010-2011 Mike van Riel / Naenius. (http://www.naenius.com)
*/
class ParamTagTest extends \PHPUnit_Framework_TestCase
{
/**
* Test that the \phpDocumentor\Reflection\DocBlock\Tag\ParamTag can
* understand the param DocBlock.
*
* @param string $type
* @param string $content
* @param string $extracted_type
* @param string $extracted_variable_name
* @param string $extracted_description
*
* @covers \phpDocumentor\Reflection\DocBlock\Tag\ParamTag::__construct
*
* @dataProvider provideDataForConstructor
*
* @return void
*/
public function testConstructorParsesInputsIntoCorrectFields(
$type, $content, $extracted_type, $extracted_variable_name,
$extracted_description
) {
$tag = new ParamTag($type, $content);
$this->assertEquals($extracted_type, $tag->getTypes());
$this->assertEquals($extracted_variable_name, $tag->getVariableName());
$this->assertEquals($extracted_description, $tag->getDescription());
}
/**
* Data provider for testConstructorParsesInputsIntoCorrectFields()
*
* @return array
*/
public function provideDataForConstructor()
{
return array(
array('param', 'int', array('int'), '', ''),
array('param', '$bob', array(), '$bob', ''),
array(
'param', 'int Number of bobs', array('int'), '',
'Number of bobs'
),
array('param', 'int $bob', array('int'), '$bob', ''),
array(
'param', 'int $bob Number of bobs', array('int'), '$bob',
'Number of bobs'
),
);
}
}
@@ -0,0 +1,55 @@
<?php
/**
* phpDocumentor Return tag test.
*
* @author Mike van Riel <[email protected]>
* @copyright Copyright (c) 2010-2011 Mike van Riel / Naenius. (http://www.naenius.com)
*/
namespace phpDocumentor\Reflection\DocBlock\Tag;
/**
* Test class for phpDocumentor_Reflection_DocBlock_ReturnTag.
*
* @author Mike van Riel <[email protected]>
* @copyright Copyright (c) 2010-2011 Mike van Riel / Naenius. (http://www.naenius.com)
*/
class ReturnTagTest extends ParamTagTest
{
/**
* Test that the \phpDocumentor\Reflection\DocBlock\Tag\ReturnTag can
* understand the Return DocBlock.
*
* @param string $content
* @param string $extracted_type
* @param string $extracted_description
*
* @covers \phpDocumentor\Reflection\DocBlock\Tag\ReturnTag::__construct
*
* @dataProvider provideDataForConstructor
*
* @return void
*/
public function testConstructorParsesInputsIntoCorrectFields(
$content, $extracted_type, $extracted_description
) {
$tag = new ReturnTag('return', $content);
$this->assertEquals($extracted_type, $tag->getTypes());
$this->assertEquals($extracted_description, $tag->getDescription());
}
/**
* Data provider for testConstructorParsesInputsIntoCorrectFields()
*
* @return array
*/
public function provideDataForConstructor()
{
return array(
array('', array(), ''),
array('int', array('int'), ''),
array('int Number of Bobs', array('int'), 'Number of Bobs'),
);
}
}
@@ -8,8 +8,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
require_once __DIR__ . '/../../../../../src/phpDocumentor/Reflection/DocBlock/Tag/SeeTag.php';
/** /**
* Test class for phpDocumentor_Reflection_DocBlock_Tag_See * Test class for phpDocumentor_Reflection_DocBlock_Tag_See
* *
@@ -8,8 +8,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
require_once __DIR__ . '/../../../../../src/phpDocumentor/Reflection/DocBlock/Tag/UsesTag.php';
/** /**
* Test class for phpDocumentor_Reflection_DocBlock_Tag_Uses * Test class for phpDocumentor_Reflection_DocBlock_Tag_Uses
* *
@@ -8,8 +8,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
require_once __DIR__ . '/../../../../../src/phpDocumentor/Reflection/DocBlock/Tag/VarTag.php';
/** /**
* Test class for phpDocumentor_Reflection_DocBlock_Tag_Link * Test class for phpDocumentor_Reflection_DocBlock_Tag_Link
* *
@@ -0,0 +1,194 @@
<?php
namespace phpDocumentor\Reflection\DocBlock\Type;
/**
* Test class for phpDocumentor_Reflection_DocBlock
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection
*/
class CollectionTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::__construct
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::getNamespace
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::getNamespaceAliases
*/
public function testConstruct()
{
$collection = new Collection();
$this->assertCount(0, $collection);
$this->assertEquals('\\', $collection->getNamespace());
$this->assertCount(0, $collection->getNamespaceAliases());
}
/**
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::__construct
*/
public function testConstructWithTypes()
{
$collection = new Collection(array('integer', 'string'));
$this->assertCount(2, $collection);
}
/**
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::__construct
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::getNamespace
*/
public function testConstructWithNamespace()
{
$collection = new Collection(array(), '\My\Space');
$this->assertEquals('\My\Space\\', $collection->getNamespace());
$collection = new Collection(array(), 'My\Space');
$this->assertEquals('\My\Space\\', $collection->getNamespace());
$collection = new Collection(array(), null);
$this->assertEquals('\\', $collection->getNamespace());
}
/**
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::__construct
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::getNamespaceAliases
*/
public function testConstructWithNamespaceAliases()
{
$fixture = array('a' => 'b');
$collection = new Collection(array(), null, $fixture);
$this->assertEquals($fixture, $collection->getNamespaceAliases());
}
/**
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::setNamespace
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::getNamespace
*/
public function testSetAndGetNamespace()
{
$collection = new Collection();
$this->assertEquals('\\', $collection->getNamespace());
$collection->setNamespace('My');
$this->assertEquals('\My\\', $collection->getNamespace());
$collection->setNamespace('\My');
$this->assertEquals('\My\\', $collection->getNamespace());
$collection->setNamespace('\My\\');
$this->assertEquals('\My\\', $collection->getNamespace());
}
/**
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::setNamespaceAliases
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::getNamespaceAliases
*/
public function testSetAndGetNamespaceAliases()
{
$collection = new Collection();
$this->assertEmpty($collection->getNamespaceAliases());
$collection->setNamespaceAliases(array('My'));
$this->assertEquals(array('My'), $collection->getNamespaceAliases());
}
/**
* @param $fixture
* @param $expected
*
* @dataProvider provideTypesToExpand
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::add
*/
public function testAdd($fixture, $expected)
{
$collection = new Collection();
$collection->setNamespace('\My\Space');
$collection->setNamespaceAliases(array('Alias' => '\My\Space\Aliasing'));
$collection->add($fixture);
$this->assertSame($expected, $collection->getArrayCopy());
}
/**
* @param $fixture
* @param $expected
*
* @dataProvider provideTypesToExpandWithoutNamespace
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::add
*/
public function testAddWithoutNamespace($fixture, $expected)
{
$collection = new Collection();
$collection->setNamespaceAliases(array('Alias' => '\My\Space\Aliasing'));
$collection->add($fixture);
$this->assertSame($expected, $collection->getArrayCopy());
}
/**
* @covers phpDocumentor\Reflection\DocBlock\Type\Collection::add
* @expectedException InvalidArgumentException
*/
public function testAddWithInvalidArgument()
{
$collection = new Collection();
$collection->add(array());
}
/**
* Returns the types and their expected values to test the retrieval of
* types.
*
* @param string $method Name of the method consuming this data provider.
* @param string $namespace Name of the namespace to user as basis.
*
* @return string[]
*/
public function provideTypesToExpand($method, $namespace = '\My\Space\\')
{
return array(
array('', array()),
array(' ', array()),
array('int', array('int')),
array('int ', array('int')),
array('string', array('string')),
array('DocBlock', array($namespace.'DocBlock')),
array('DocBlock[]', array($namespace.'DocBlock[]')),
array(' DocBlock ', array($namespace.'DocBlock')),
array('\My\Space\DocBlock', array('\My\Space\DocBlock')),
array('Alias\DocBlock', array('\My\Space\Aliasing\DocBlock')),
array(
'DocBlock|Tag',
array($namespace .'DocBlock', $namespace .'Tag')
),
array(
'DocBlock|null',
array($namespace.'DocBlock', 'null')
),
array(
'\My\Space\DocBlock|Tag',
array('\My\Space\DocBlock', $namespace.'Tag')
),
array(
'DocBlock[]|null',
array($namespace.'DocBlock[]', 'null')
),
array(
'DocBlock[]|int[]',
array($namespace.'DocBlock[]', 'int[]')
),
);
}
/**
* Returns the types and their expected values to test the retrieval of
* types when no namespace is available.
*
* @param string $method Name of the method consuming this data provider.
* @param string $namespace Name of the namespace to user as basis.
*
* @return string[]
*/
public function provideTypesToExpandWithoutNamespace($method)
{
return $this->provideTypesToExpand($method, '\\');
}
}
+101 -4
View File
@@ -10,9 +10,6 @@
namespace phpDocumentor\Reflection; namespace phpDocumentor\Reflection;
require_once __DIR__.'/../../../src/phpDocumentor/Reflection/DocBlock.php';
require_once __DIR__.'/../../../src/phpDocumentor/Reflection/DocBlock/LongDescription.php';
/** /**
* Test class for phpDocumentor_Reflection_DocBlock * Test class for phpDocumentor_Reflection_DocBlock
* *
@@ -38,10 +35,110 @@ DOCBLOCK;
'This is a short description.', $object->getShortDescription() 'This is a short description.', $object->getShortDescription()
); );
$this->assertEquals( $this->assertEquals(
'This is a long description.', $object->getLongDescription()->getContents() 'This is a long description.',
$object->getLongDescription()->getContents()
); );
$this->assertEquals(2, count($object->getTags())); $this->assertEquals(2, count($object->getTags()));
$this->assertTrue($object->hasTag('see')); $this->assertTrue($object->hasTag('see'));
$this->assertTrue($object->hasTag('return')); $this->assertTrue($object->hasTag('return'));
} }
public function testDotSeperation()
{
$fixture = <<<DOCBLOCK
/**
* This is a short description. This is a long description.
* This is a continuation of the long description.
*/
DOCBLOCK;
$object = new DocBlock($fixture);
$this->assertEquals(
'This is a short description.', $object->getShortDescription()
);
$this->assertEquals(
"This is a long description.\nThis is a continuation of the long "
."description.", $object->getLongDescription()->getContents()
);
}
/**
* Tests whether a type is expanded with the given namespace and that a
* keyword is not expanded.
*
* @covers \phpDocumentor\Reflection\DocBlock::expandType()
*
* @return void
*/
public function testExpandTypeUsingNamespace()
{
$docblock = new DocBlock('', '\My\Namespace');
$this->assertEquals('\My\Namespace\Mine', $docblock->expandType('Mine'));
}
/**
* Tests whether a type is expanded when no namespace is given.
*
* @covers \phpDocumentor\Reflection\DocBlock::expandType()
*
* @return void
*/
public function testExpandTypeWithoutNamespace()
{
$docblock = new DocBlock('');
$this->assertEquals('\Mine', $docblock->expandType('Mine'));
}
/**
* Tests whether a type is expanded with the given namespace when an alias
* is provided.
*
* @covers \phpDocumentor\Reflection\DocBlock::expandType()
*
* @return void
*/
public function testExpandTypeUsingNamespaceAlias()
{
$docblock = new DocBlock(
'', '\My\Namespace', array('Alias' => '\My\Namespace\Alias')
);
// first try a normal resolution without alias
$this->assertEquals(
'\My\Namespace\Al', $docblock->expandType('Al')
);
// try to use the alias
$this->assertEquals(
'\My\Namespace\Alias\Al', $docblock->expandType('Alias\Al')
);
}
/**
* Tests whether the keywords that should not be converted are not converted.
*
* @param string $keyword The keyword that is to be tested; this is provided
* by the dataprovider.
*
* @covers \phpDocumentor\Reflection\DocBlock::expandType()
*
* @dataProvider getNonExpandableKeywordsForExpandType
*
* @return void
*/
public function testThatExpandTypeDoesNotExpandAllKeywords($keyword)
{
$docblock = new DocBlock('', '\My\Namespace');
$this->assertEquals($keyword, $docblock->expandType($keyword));
}
public function getNonExpandableKeywordsForExpandType()
{
return array(
array('string'), array('int'), array('integer'), array('bool'),
array('boolean'), array('float'), array('double'), array('object'),
array('mixed'), array('array'), array('resource'), array('void'),
array('null'), array('callback'), array('false'), array('true')
);
}
} }