Compare commits

..
62 Commits
Author SHA1 Message Date
Barry vd. Heuvel 494d594733 Move Context / ContextFactory to correct location
Other location isn't autoloaded correctly.
2015-06-07 14:47:11 +02:00
Mike van Riel afd2520734 Merge pull request #53 from mvriel/feature/refactor-to-v2
Make Context leaner and enable third parties to create them
2015-06-06 21:40:28 +02:00
Mike van Riel ef39243160 Make Context leaner and enable third parties to create them
Contexts are necessary for factories to resolve QSEN into FQSENs based
on partial namespaces and namespace aliases. These provide DocBlocks
with the namespace name and namespace aliases.

The new ContextFactory will enable third parties who don't use
phpDocumentor's Reflection component to construct a Context based on
a class reflector or namespace name (and file contents).
2015-06-06 20:03:59 +02:00
Mike van Riel ae15da2ce2 [#52] Removed dflydev/markdown from suggested list
The markdown package by DFlyDev is deprecated and is not recommended
anymore due to the provided alternatives (parsedown or commonmark).
2015-05-12 09:21:12 +02:00
Mike van Riel d1da796ba5 Merge pull request #47 from TomasVotruba/patch-1
travis: PHP 7.0 nightly added
2015-02-27 10:28:18 +01:00
Tomáš Votruba 868311451b travis: PHP 7.0 nightly added
See http://docs.travis-ci.com/user/languages/php/#PHP-7
2015-02-27 10:18:02 +01:00
Mike van Riel 5a87e6edaa Merge pull request #46 from colinodell/remove-composer-lock
Remove composer.lock
2015-02-25 18:26:05 +01:00
Mike van Riel b79f9f311d Merge pull request #45 from colinodell/commonmark-support
Add support for the league/commonmark Markdown parser
2015-02-25 18:24:05 +01:00
Colin O'Dell 702c5682ae Remove composer.lock
Per the Composer documentation:

> Note: For libraries it is not necessarily recommended to commit the lock file (...)

https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
2015-02-23 15:03:39 -05:00
Colin O'Dell 0d324618be Add support for the league/commonmark Markdown parser 2015-02-23 14:50:38 -05:00
Mike van Riel ff902a0beb Merge pull request #44 from dunglas/patch-1
minor: typo fix in PHPDoc
2015-02-12 13:17:11 +01:00
Kévin Dunglas a8ebd67e2a minor: typo fix in PHPDoc 2015-02-12 13:08:38 +01:00
Mike van Riel 09352d3406 Remove external code coverage 2015-02-03 21:57:02 +01:00
Mike van Riel 7b8092e37f Remove external code coverage and fix scrutinizer issues 2015-02-03 21:43:12 +01:00
Mike van Riel f8bb8d74ae Add scrutinizer config 2015-02-03 13:17:25 +01:00
Mike van Riel d68dbdc53d Disable failing test before tagging 2015-02-03 13:10:50 +01:00
Mike van Riel fb5dfa51d4 Merge pull request #41 from cebe/patch-1
Create LICENSE
2015-02-03 07:38:02 +01:00
Carsten Brandt ae02953010 Create LICENSE
According to [composer.json](https://github.com/phpDocumentor/ReflectionDocBlock/blob/master/composer.json#L4) it should be MIT.

fixes #40
2014-12-19 23:13:47 +01:00
Chuck Burgess fd0ac20074 Merge pull request #39 from mvriel/feature/phpDocumentor2/42
Add support for DocBlock template markers
2014-09-02 09:26:20 -05:00
Mike van Riel 21feb61eb5 Add missing DocBlock (info). 2014-08-30 11:16:26 +02:00
Mike van Riel 280a3ce56d Add support for DocBlock template markers
DocBlocks may start with #@+ and #@- to indicate that they are (the start) of a DocBlock
template or the end of a template.

In this commit I have changed the way a DocBlock is parsed to interpret this information
and added tests to show for it. In addition I have added more comments to the Regular
Expression responsible for splitting a DocBlock to show the business rules more clearly.

This is the first step in implementing https://github.com/phpDocumentor/phpDocumentor2/issues/42.
2014-08-30 11:08:15 +02:00
Mike van Riel 0604d62704 Merge pull request #38 from GrahamCampbell/stuff
Composer And Travis Updates
2014-08-21 23:05:07 +02:00
Graham Campbell a66d783afd Travis improvements 2014-08-21 13:02:49 +01:00
Graham Campbell 84de81c009 Composer updates 2014-08-21 13:02:41 +01:00
Mike van Riel 38743b6779 Merge pull request #37 from alexkn/fix-error-display
Remove Error display at MethodTag
2014-08-09 12:27:07 +02:00
Alexander Knöbel 0d52cb6389 Remove Error display at MethodTag 2014-08-09 12:09:15 +02:00
Mike van Riel 2281569ebc Merge pull request #33 from Nyholm/patch-1
Added PHP 5.6 and HHVM to travis.yml
2014-07-19 08:49:33 +02:00
Tobias Nyholm e0faa7f04f Added hhvm-nightly 2014-07-09 14:15:10 +02:00
Tobias Nyholm 39a08094f1 Added PHP 5.6 and HHVM to travis.yml 2014-07-09 12:05:21 +02:00
Mike van Riel 07b195e1ee Merge branch 'master' of github.com:phpDocumentor/ReflectionDocBlock 2014-04-26 12:10:44 +02:00
Mike van Riel 0bca477a34 Implement support for Variadic arguments
Fixes https://github.com/phpDocumentor/phpDocumentor2/issues/629, in
this commit we add support for recognizing and displaying variadic
arguments as described in the Variadics RFC on Internals
(https://wiki.php.net/rfc/variadics).

This adds support for describing Variadics even before PHP 5.6, where
this feature is planned.
2014-03-28 10:21:30 +01:00
Mike van Riel 66a7d3bf31 Merge pull request #31 from siad007/patch-1
Fixed method call.
2014-03-16 13:31:01 +01:00
Siad Ardroumli 2331fc92f6 Fixed method call.
Related to https://github.com/phpDocumentor/phpDocumentor2/pull/1145
2014-03-16 13:23:37 +01:00
Mike van Riel b1922e00de Merge pull request #30 from cebe/preserve-newlines
Preserve newlines in docblock tags
2014-03-01 11:01:55 +01:00
Carsten Brandt 53ba484043 Preserve newlines in docblock tags
This is especially important when using markdown.
Adding a blank line between text introduces a new paragraph.
Current implementation will result in all text staying in one paragraph
and also other elements like lists and code do not get recognized in
most cases.
2014-02-28 17:17:48 +01:00
Mike van Riel cfb3ebea55 Add support for Parsedown as a markdown parser 2013-12-05 09:16:55 +01:00
Vasil Rangelov c33820b04b Merge pull request #25 from barryvdh/patch-1
Markdown is not required, so move to suggest
2013-08-08 09:31:39 -07:00
Barry vd. Heuvel 280c4a1d44 Markdown is not required, so move to suggest
Markdown is only used once and a check is in place to see if the markdown classes exists. So perhaps it is better to move this to suggest instead of require, so the people who don't need it, don't have to download it.
2013-08-08 18:25:04 +02:00
Vasil Rangelov 66ae84e9d7 Merge pull request #24 from tommygnr/travis-5.5
Enable travis builds on php5.5
2013-08-07 04:04:22 -07:00
Tom Corrigan 3023fb2220 Enable travis builds on php5.5 2013-08-07 13:08:11 +10:00
Mike van Riel a9b6edf3ce Merge pull request #23 from tommygnr/patch-1
Add a branch alias
2013-08-01 12:16:50 -07:00
Tom Corrigan f3d1a28bf7 Add a branch alias
This will enable improved version constraints in phpdocumentor/reflection
2013-08-02 02:40:14 +10:00
Vasil Rangelov 6d705c1a0f Merge pull request #22 from barryvdh/tostring
Add __toString() methods for Description and Tag
2013-05-27 10:54:22 -07:00
Barry vd. Heuvel ab0bcb8d31 Add __toString() methods for Description and Tag
And let the Serializer make use of the (string) $tag
2013-05-27 18:16:15 +02:00
Vasil Rangelov ac6e37af97 Added "{}" around all double quoted variables, for readability's sake;
Performance improvement in Serializer - wrap length is calculated once during the text portion only. Tags reuse the result. Also no "prefix" adding in tags - the name is simply added before wrapping.
2013-05-27 02:04:23 +03:00
Vasil Rangelov 4a7affe15b Minor doc fix at Serializer.php. 2013-05-27 01:31:58 +03:00
Vasil Rangelov b7797b4e1a Added getters for Serializer options;
Swapped the indent and indent string options at Serializer's constructor;
Renamed Serializer::setIndentFirstLine() to setIsFirstLineIndented() in accordance with the getter (PHPMD fix);
Line length is now ACTUALLY line length, i.e. it takes the indentation into account, and is applied to tags as well;
Fixed ReturnTag::setContent() to set "types" to NULL;
A lot of doc and CS fixes at Serializer.php.
2013-05-27 01:27:07 +03:00
Vasil Rangelov 8b529636bf Merge pull request #20 from barryvdh/master
Export docblock comment
2013-05-26 13:55:34 -07:00
Barry vd. Heuvel 2e9fd6a2e8 Revert setType
Doesn't really belong to this PR
2013-05-26 22:36:53 +02:00
Barry vd. Heuvel cbb14bab1e Move serializer to seperate class 2013-05-26 22:36:31 +02:00
Barry vd. Heuvel d57128e65c Export DocBlock & full description
Add get/set for entire description, and create a docblock comment, based
on the description/tags
2013-05-26 21:17:09 +02:00
Barry vd. Heuvel d9c0928243 Set return type 2013-05-26 21:16:30 +02:00
Vasil Rangelov 63c9de4e8b Added support for static method declarations at MethodTag and according unit tests.
Fixed MethodTag::getContent() to actually return the content as opposed to $this;
2013-05-16 22:17:15 +03:00
Vasil Rangelov 76619d4a16 Adjusted Unit tests and docs to match the latest dot separation. 2013-04-16 19:25:40 +03:00
Vasil Rangelov 47d3f86c53 Fixed the dot separation to match the latest PSR
(see phpDocumentor/phpDocumentor2#797)
2013-04-16 17:22:15 +03:00
Mike van Riel cfb104b8c8 Merge pull request #17 from joncave/cotnent-typo
Fix typo in "cotnent"
2013-02-01 10:47:35 -08:00
Jon Cave 5c51ccf185 Fix typo in "cotnent" 2013-02-01 18:08:30 +00:00
Vasil Rangelov 5d93f42598 Added "scalar" as a recognized keyword (phpDocumentor/phpDocumentor2#694);
Changed the list of keywords to be static (for the purpose of reducing memory consumption);
Updated composer.lock with the latest dependencies (PHPUnit in particular).
2012-12-02 22:26:45 +02:00
Vasil Rangelov eb83d810de Added a Travis status image to README.md;
Also, fixed a typo.
2012-11-30 22:43:34 +02:00
Vasil Rangelov 6f0fc03c49 Added setters at Location and Description;
Added DocBlock::appendTag();
Minor reorganization at the tag setters;
2012-11-30 22:37:41 +02:00
Vasil Rangelov b09525332f Refactored all tags to have setters for all of their components;
Removed the special handling for VarTag (it's now equivalent to ParamTag);
Minor doc, CS and coverage fixes.
2012-11-30 19:26:19 +02:00
Vasil Rangelov c2796044a6 Adjusted composer files for consistency with PhpDocumentor. 2012-11-29 20:12:53 +02:00
40 changed files with 1744 additions and 640 deletions
+2 -1
View File
@@ -1,2 +1,3 @@
.idea .idea
vendor composer.lock
vendor
+45
View File
@@ -0,0 +1,45 @@
before_commands:
- "composer install --no-dev --prefer-source"
tools:
external_code_coverage:
enabled: false
timeout: 300
filter:
excluded_paths: ["tests", "vendor"]
php_code_coverage:
enabled: false
test_command: phpunit -c phpunit.xml.dist
php_code_sniffer:
enabled: true
config:
standard: PSR2
filter:
paths: ["src/*", "tests/*"]
php_cpd:
enabled: true
excluded_dirs: ["tests", "vendor"]
php_cs_fixer:
enabled: true
config:
level: all
filter:
paths: ["src/*", "tests/*"]
php_loc:
enabled: true
excluded_dirs: ["tests", "vendor"]
php_mess_detector:
enabled: true
config:
ruleset: phpmd.xml.dist
design_rules: { eval_expression: false }
filter:
paths: ["src/*"]
php_pdepend:
enabled: true
excluded_dirs: ["tests", "vendor"]
php_analyzer:
enabled: true
filter:
paths: ["src/*", "tests/*"]
sensiolabs_security_checker: true
+14 -4
View File
@@ -3,17 +3,27 @@ php:
- 5.3.3 - 5.3.3
- 5.3 - 5.3
- 5.4 - 5.4
- 5.5
- 5.6
- 7.0
- hhvm
- hhvm-nightly
matrix:
allow_failures:
- php: hhvm
- php: hhvm-nightly
script: script:
- vendor/phpunit/phpunit/composer/bin/phpunit - vendor/bin/phpunit
before_script: before_script:
- sudo apt-get -qq update > /dev/null - sudo apt-get -qq update > /dev/null
- phpenv rehash > /dev/null - phpenv rehash > /dev/null
- composer selfupdate --quiet - composer selfupdate --quiet
- composer install --dev - composer install --no-interaction --prefer-source --dev
- vendor/phpunit/phpunit/composer/bin/phpunit - vendor/bin/phpunit
- composer update --dev - composer update --no-interaction --prefer-source --dev
notifications: notifications:
irc: "irc.freenode.org#phpdocumentor" irc: "irc.freenode.org#phpdocumentor"
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2010 Mike van Riel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+2 -2
View File
@@ -1,4 +1,4 @@
The ReflectionDocBlock Component The ReflectionDocBlock Component [![Build Status](https://secure.travis-ci.org/phpDocumentor/ReflectionDocBlock.png)](https://travis-ci.org/phpDocumentor/ReflectionDocBlock)
================================ ================================
Introduction Introduction
@@ -7,7 +7,7 @@ Introduction
The ReflectionDocBlock component of phpDocumentor provides a DocBlock parser The ReflectionDocBlock component of phpDocumentor provides a DocBlock parser
that is 100% compatible with the [PHPDoc standard](http://phpdoc.org/docs/latest). that is 100% compatible with the [PHPDoc standard](http://phpdoc.org/docs/latest).
With this component can a library provide support for annotations via DocBlocks With this component, a library can provide support for annotations via DocBlocks
or otherwise retrieve information that is embedded in a DocBlock. or otherwise retrieve information that is embedded in a DocBlock.
> **Note**: *this is a core component of phpDocumentor and is constantly being > **Note**: *this is a core component of phpDocumentor and is constantly being
+11 -3
View File
@@ -6,13 +6,21 @@
{"name": "Mike van Riel", "email": "[email protected]"} {"name": "Mike van Riel", "email": "[email protected]"}
], ],
"require": { "require": {
"php": ">=5.3.2", "php": ">=5.3.3"
"dflydev/markdown": "1.0.*"
}, },
"autoload": { "autoload": {
"psr-0": {"phpDocumentor": ["src/"]} "psr-0": {"phpDocumentor": ["src/"]}
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "*@stable" "phpunit/phpunit": "~4.0"
},
"suggest": {
"erusev/parsedown": "~1.0",
"league/commonmark": "*"
},
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
} }
} }
Generated
-67
View File
@@ -1,67 +0,0 @@
{
"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": [
]
}
+23
View File
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ruleset
name="ProxyManager rules"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"
>
<rule ref="rulesets/codesize.xml"/>
<rule ref="rulesets/unusedcode.xml"/>
<rule ref="rulesets/design.xml">
<!-- eval is needed to generate runtime classes -->
<exclude name="EvalExpression"/>
</rule>
<rule ref="rulesets/naming.xml">
<exclude name="LongVariable"/>
</rule>
<rule ref="rulesets/naming.xml/LongVariable">
<properties>
<property name="minimum">40</property>
</properties>
</rule>
</ruleset>
+195 -81
View File
@@ -12,6 +12,7 @@
namespace phpDocumentor\Reflection; namespace phpDocumentor\Reflection;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Context; use phpDocumentor\Reflection\DocBlock\Context;
use phpDocumentor\Reflection\DocBlock\Location; use phpDocumentor\Reflection\DocBlock\Location;
@@ -28,13 +29,13 @@ class DocBlock implements \Reflector
protected $short_description = ''; protected $short_description = '';
/** /**
* @var \phpDocumentor\Reflection\DocBlock\LongDescription The actual * @var DocBlock\Description The actual
* description for this docblock. * description for this docblock.
*/ */
protected $long_description = null; protected $long_description = null;
/** /**
* @var \phpDocumentor\Reflection\DocBlock\Tags[] An array containing all * @var Tag[] An array containing all
* the tags in this docblock; except inline. * the tags in this docblock; except inline.
*/ */
protected $tags = array(); protected $tags = array();
@@ -45,22 +46,25 @@ class DocBlock implements \Reflector
/** @var Location Information about the location of this DocBlock. */ /** @var Location Information about the location of this DocBlock. */
protected $location = null; protected $location = null;
/** @var bool Is this DocBlock (the start of) a template? */
protected $isTemplateStart = false;
/** @var bool Does this DocBlock signify the end of a DocBlock template? */
protected $isTemplateEnd = false;
/** /**
* Parses the given docblock and populates the member fields. * Parses the given docblock and populates the member fields.
* *
* The constructor may also receive namespace information such as the * The constructor may also receive namespace information such as the
* current namespace and aliases. This information is used by some tags * current namespace and aliases. This information is used by some tags
* (e.g. @return, @param, etc.) to turn a relative Type into a FQCN. * (e.g. return, param, etc.) to turn a relative Type into a FQCN.
* *
* @param \Reflector|string $docblock A docblock comment (including * @param \Reflector|string $docblock A docblock comment (including asterisks) or reflector supporting the
* asterisks) or reflector supporting the getDocComment method.
* @param Context $context The context in which the DocBlock
* occurs.
* @param Location $location The location within the file that this
* DocBlock occurs in.
*
* @throws \InvalidArgumentException if the given argument does not have the
* getDocComment method. * getDocComment method.
* @param Context $context The context in which the DocBlock occurs.
* @param Location $location The location within the file that this DocBlock occurs in.
*
* @throws \InvalidArgumentException if the given argument does not have the getDocComment method.
*/ */
public function __construct( public function __construct(
$docblock, $docblock,
@@ -70,8 +74,7 @@ class DocBlock implements \Reflector
if (is_object($docblock)) { if (is_object($docblock)) {
if (!method_exists($docblock, 'getDocComment')) { if (!method_exists($docblock, 'getDocComment')) {
throw new \InvalidArgumentException( throw new \InvalidArgumentException(
'Invalid object passed; the given reflector must support ' 'Invalid object passed; the given reflector must support the getDocComment method'
. 'the getDocComment method'
); );
} }
@@ -80,7 +83,9 @@ class DocBlock implements \Reflector
$docblock = $this->cleanInput($docblock); $docblock = $this->cleanInput($docblock);
list($short, $long, $tags) = $this->splitDocBlock($docblock); list($templateMarker, $short, $long, $tags) = $this->splitDocBlock($docblock);
$this->isTemplateStart = $templateMarker === '#@+';
$this->isTemplateEnd = $templateMarker === '#@-';
$this->short_description = $short; $this->short_description = $short;
$this->long_description = new DocBlock\Description($long, $this); $this->long_description = new DocBlock\Description($long, $this);
$this->parseTags($tags); $this->parseTags($tags);
@@ -118,74 +123,86 @@ class DocBlock implements \Reflector
} }
/** /**
* Splits the DocBlock into a short description, long description and * Splits the DocBlock into a template marker, summary, description and block of tags.
* block of tags.
* *
* @param string $comment Comment to split into the sub-parts. * @param string $comment Comment to split into the sub-parts.
* *
* @author RichardJ Special thanks to RichardJ for the regex responsible * @author Richard van Velzen (@_richardJ) Special thanks to Richard for the regex responsible for the split.
* for the split. * @author Mike van Riel <[email protected]> for extending the regex with template marker support.
* *
* @return string[] containing the short-, long description and an element * @return string[] containing the template marker (if any), summary, description and a string containing the tags.
* containing the tags.
*/ */
protected function splitDocBlock($comment) protected function splitDocBlock($comment)
{ {
// Performance improvement cheat: if the first character is an @ then only tags are in this DocBlock. This
// method does not split tags so we return this verbatim as the fourth result (tags). This saves us the
// performance impact of running a regular expression
if (strpos($comment, '@') === 0) { if (strpos($comment, '@') === 0) {
$matches = array('', '', $comment); return array('', '', '', $comment);
} else {
// clears all extra horizontal whitespace from the line endings
// to prevent parsing issues
$comment = preg_replace('/\h*$/Sum', '', $comment);
/*
* Splits the docblock into a short description, long description and
* tags section
* - The short description is started from the first character until
* a dot is encountered followed by a whitespace OR
* two consecutive newlines (horizontal whitespace is taken into
* account to consider spacing errors)
* - The long description, any character until a new line is
* encountered followed by an @ and word characters (a tag).
* This is optional.
* - Tags; the remaining characters
*
* Big thanks to RichardJ for contributing this Regular Expression
*/
preg_match(
'/
\A (
[^\n.]+
(?:
(?! \. \s | \n{2} ) # disallow the first seperator here
[\n.] (?! [ \t]* @\pL ) # disallow second seperator
[^\n.]+
)*
\.?
)
(?:
\s* # first seperator (actually newlines but it\'s all whitespace)
(?! @\pL ) # disallow the rest, to make sure this one doesn\'t match,
#if it doesn\'t exist
(
[^\n]+
(?: \n+
(?! [ \t]* @\pL ) # disallow second seperator (@param)
[^\n]+
)*
)
)?
(\s+ [\s\S]*)? # everything that follows
/ux',
$comment,
$matches
);
array_shift($matches);
} }
while (count($matches) < 3) { // clears all extra horizontal whitespace from the line endings to prevent parsing issues
$comment = preg_replace('/\h*$/Sum', '', $comment);
/*
* Splits the docblock into a template marker, short description, long description and tags section
*
* - The template marker is empty, #@+ or #@- if the DocBlock starts with either of those (a newline may
* occur after it and will be stripped).
* - The short description is started from the first character until a dot is encountered followed by a
* newline OR two consecutive newlines (horizontal whitespace is taken into account to consider spacing
* errors). This is optional.
* - The long description, any character until a new line is encountered followed by an @ and word
* characters (a tag). This is optional.
* - Tags; the remaining characters
*
* Big thanks to RichardJ for contributing this Regular Expression
*/
preg_match(
'/
\A
# 1. Extract the template marker
(?:(\#\@\+|\#\@\-)\n?)?
# 2. Extract the summary
(?:
(?! @\pL ) # The summary may not start with an @
(
[^\n.]+
(?:
(?! \. \n | \n{2} ) # End summary upon a dot followed by newline or two newlines
[\n.] (?! [ \t]* @\pL ) # End summary when an @ is found as first character on a new line
[^\n.]+ # Include anything else
)*
\.?
)?
)
# 3. Extract the description
(?:
\s* # Some form of whitespace _must_ precede a description because a summary must be there
(?! @\pL ) # The description may not start with an @
(
[^\n]+
(?: \n+
(?! [ \t]* @\pL ) # End description when an @ is found as first character on a new line
[^\n]+ # Include anything else
)*
)
)?
# 4. Extract the tags (anything that follows)
(\s+ [\s\S]*)? # everything that follows
/ux',
$comment,
$matches
);
array_shift($matches);
while (count($matches) < 4) {
$matches[] = ''; $matches[] = '';
} }
return $matches; return $matches;
} }
@@ -208,26 +225,58 @@ class DocBlock implements \Reflector
); );
} }
foreach (explode("\n", $tags) as $tag_line) { foreach (explode("\n", $tags) as $tag_line) {
if (trim($tag_line) === '') {
continue;
}
if (isset($tag_line[0]) && ($tag_line[0] === '@')) { if (isset($tag_line[0]) && ($tag_line[0] === '@')) {
$result[] = $tag_line; $result[] = $tag_line;
} else { } else {
$result[count($result) - 1] .= PHP_EOL . $tag_line; $result[count($result) - 1] .= "\n" . $tag_line;
} }
} }
// 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, $this); $result[$key] = Tag::createInstance(trim($tag_line), $this);
} }
} }
$this->tags = $result; $this->tags = $result;
} }
/**
* Gets the text portion of the doc block.
*
* Gets the text portion (short and long description combined) of the doc
* block.
*
* @return string The text portion of the doc block.
*/
public function getText()
{
$short = $this->getShortDescription();
$long = $this->getLongDescription()->getContents();
if ($long) {
return "{$short}\n\n{$long}";
} else {
return $short;
}
}
/**
* Set the text portion of the DocBlock.
*
* Sets the text portion (short and long description combined) of the DocBlock.
*
* @param string $comment The new text portion of the DocBlock.
*
* @return $this
*/
public function setText($comment)
{
list(,$short, $long) = $this->splitDocBlock($comment);
$this->short_description = $short;
$this->long_description = new DocBlock\Description($long, $this);
return $this;
}
/** /**
* Returns the opening line or also known as short description. * Returns the opening line or also known as short description.
* *
@@ -241,13 +290,51 @@ class DocBlock implements \Reflector
/** /**
* Returns the full description or also known as long description. * Returns the full description or also known as long description.
* *
* @return \phpDocumentor\Reflection\DocBlock\LongDescription * @return DocBlock\Description
*/ */
public function getLongDescription() public function getLongDescription()
{ {
return $this->long_description; return $this->long_description;
} }
/**
* Returns whether this DocBlock is the start of a Template section.
*
* A Docblock may serve as template for a series of subsequent DocBlocks. This is indicated by a special marker
* (`#@+`) that is appended directly after the opening `/**` of a DocBlock.
*
* An example of such an opening is:
*
* ```
* /**#@+
* * My DocBlock
* * /
* ```
*
* The description and tags (not the summary!) are copied onto all subsequent DocBlocks and also applied to all
* elements that follow until another DocBlock is found that contains the closing marker (`#@-`).
*
* @see self::isTemplateEnd() for the check whether a closing marker was provided.
*
* @return boolean
*/
public function isTemplateStart()
{
return $this->isTemplateStart;
}
/**
* Returns whether this DocBlock is the end of a Template section.
*
* @see self::isTemplateStart() for a more complete description of the Docblock Template functionality.
*
* @return boolean
*/
public function isTemplateEnd()
{
return $this->isTemplateEnd;
}
/** /**
* Returns the current context. * Returns the current context.
* *
@@ -271,7 +358,7 @@ class DocBlock implements \Reflector
/** /**
* Returns the tags for this DocBlock. * Returns the tags for this DocBlock.
* *
* @return \phpDocumentor\Reflection\DocBlock\Tag[] * @return Tag[]
*/ */
public function getTags() public function getTags()
{ {
@@ -284,13 +371,13 @@ class DocBlock implements \Reflector
* *
* @param string $name String to search by. * @param string $name String to search by.
* *
* @return \phpDocumentor\Reflection\DocBlock_Tag[] * @return Tag[]
*/ */
public function getTagsByName($name) public function getTagsByName($name)
{ {
$result = array(); $result = array();
/** @var \phpDocumentor\Reflection\DocBlock\Tag $tag */ /** @var Tag $tag */
foreach ($this->getTags() as $tag) { foreach ($this->getTags() as $tag) {
if ($tag->getName() != $name) { if ($tag->getName() != $name) {
continue; continue;
@@ -311,7 +398,7 @@ class DocBlock implements \Reflector
*/ */
public function hasTag($name) public function hasTag($name)
{ {
/** @var \phpDocumentor\Reflection\DocBlock\Tag $tag */ /** @var Tag $tag */
foreach ($this->getTags() as $tag) { foreach ($this->getTags() as $tag) {
if ($tag->getName() == $name) { if ($tag->getName() == $name) {
return true; return true;
@@ -321,6 +408,33 @@ class DocBlock implements \Reflector
return false; return false;
} }
/**
* Appends a tag at the end of the list of tags.
*
* @param Tag $tag The tag to add.
*
* @return Tag The newly added tag.
*
* @throws \LogicException When the tag belongs to a different DocBlock.
*/
public function appendTag(Tag $tag)
{
if (null === $tag->getDocBlock()) {
$tag->setDocBlock($this);
}
if ($tag->getDocBlock() === $this) {
$this->tags[] = $tag;
} else {
throw new \LogicException(
'This tag belongs to a different DocBlock object.'
);
}
return $tag;
}
/** /**
* Builds a string representation of this object. * Builds a string representation of this object.
* *
+40 -119
View File
@@ -1,11 +1,11 @@
<?php <?php
/** /**
* phpDocumentor * This file is part of phpDocumentor.
* *
* PHP Version 5.3 * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
* *
* @author Vasil Rangelov <[email protected]> * @copyright 2010-2015 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 * @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://phpdoc.org * @link http://phpdoc.org
*/ */
@@ -13,46 +13,49 @@
namespace phpDocumentor\Reflection\DocBlock; namespace phpDocumentor\Reflection\DocBlock;
/** /**
* The context in which a DocBlock occurs. * Provides information about the Context in which the DocBlock occurs that receives this context.
* *
* @author Vasil Rangelov <[email protected]> * A DocBlock does not know of its own accord in which namespace it occurs and which namespace aliases are applicable
* @license http://www.opensource.org/licenses/mit-license.php MIT * for the block of code in which it is in. This information is however necessary to resolve Class names in tags since
* @link http://phpdoc.org * you can provide a short form or make use of namespace aliases.
*
* The phpDocumentor Reflection component knows how to create this class but if you use the DocBlock parser from your
* own application it is possible to generate a Context class using the ContextFactory; this will analyze the file in
* which an associated class resides for its namespace and imports.
*
* @see ContextFactory::createFromClassReflector()
* @see ContextFactory::createForNamespace()
*/ */
class Context final class Context
{ {
/** @var string The current namespace. */ /** @var string The current namespace. */
protected $namespace = ''; private $namespace = '';
/** @var array List of namespace aliases => Fully Qualified Namespace. */ /** @var array List of namespace aliases => Fully Qualified Namespace. */
protected $namespace_aliases = array(); private $namespaceAliases = [];
/** @var string Name of the structural element, within the namespace. */
protected $lsen = '';
/** /**
* Cteates a new context. * Initializes the new context and normalizes all passed namespaces to be in Qualified Namespace Name (QNN)
* @param string $namespace The namespace where this DocBlock * format (without a preceding `\`).
* resides in. *
* @param array $namespace_aliases List of namespace aliases => Fully * @param string $namespace The namespace where this DocBlock resides in.
* Qualified Namespace. * @param array $namespaceAliases List of namespace aliases => Fully Qualified Namespace.
* @param string $lsen Name of the structural element, within
* the namespace.
*/ */
public function __construct( public function __construct($namespace, array $namespaceAliases = [])
$namespace = '', {
array $namespace_aliases = array(), $this->namespace = ('global' !== $namespace && 'default' !== $namespace)
$lsen = '' ? trim((string)$namespace, '\\')
) { : '';
if (!empty($namespace)) {
$this->setNamespace($namespace); foreach ($namespaceAliases as $alias => $fqnn) {
$this->namespaceAliases[$alias] = trim((string)$fqnn, '\\');
} }
$this->setNamespaceAliases($namespace_aliases);
$this->setLSEN($lsen);
} }
/** /**
* @return string The namespace where this DocBlock resides in. * Returns the Qualified Namespace Name (thus without `\` in front) where the associated element is in.
*
* @return string
*/ */
public function getNamespace() public function getNamespace()
{ {
@@ -60,95 +63,13 @@ class Context
} }
/** /**
* @return array List of namespace aliases => Fully Qualified Namespace. * Returns a list of Qualified Namespace Names (thus without `\` in front) that are imported, the keys represent
* the alias for the imported Namespace.
*
* @return string[]
*/ */
public function getNamespaceAliases() public function getNamespaceAliases()
{ {
return $this->namespace_aliases; return $this->namespaceAliases;
}
/**
* Returns the Local Structural Element Name.
*
* @return string Name of the structural element, within the namespace.
*/
public function getLSEN()
{
return $this->lsen;
}
/**
* Sets a new namespace.
*
* Sets a new namespace for the context. Leading and trailing slashes are
* trimmed, and the keywords "global" and "default" are treated as aliases
* to no namespace.
*
* @param string $namespace The new namespace to set.
*
* @return $this
*/
public function setNamespace($namespace)
{
if ('global' !== $namespace
&& 'default' !== $namespace
) {
// Srip leading and trailing slash
$this->namespace = trim((string)$namespace, '\\');
} else {
$this->namespace = '';
}
return $this;
}
/**
* Sets the namespace aliases, replacing all previous ones.
*
* @param array $namespace_aliases List of namespace aliases => Fully
* Qualified Namespace.
*
* @return $this
*/
public function setNamespaceAliases(array $namespace_aliases)
{
$this->namespace_aliases = array();
foreach ($namespace_aliases as $alias => $fqnn) {
$this->setNamespaceAlias($alias, $fqnn);
}
return $this;
}
/**
* Adds a namespace alias to the context.
*
* @param string $alias The alias name (the part after "as", or the last
* part of the Fully Qualified Namespace Name) to add.
* @param string $fqnn The Fully Qualified Namespace Name for this alias.
* Any form of leading/trailing slashes are accepted, but what will be
* stored is a name, prefixed with a slash, and no trailing slash.
*
* @return $this
*/
public function setNamespaceAlias($alias, $fqnn)
{
$this->namespace_aliases[$alias] = '\\' . trim((string)$fqnn, '\\');
return $this;
}
/**
* Sets a new Local Structural Element Name.
*
* Sets a new Local Structural Element Name. A local name also contains
* punctuation determining the kind of structural element (e.g. trailing "("
* and ")" for functions and methods).
*
* @param string $lsen The new local name of a structural element.
*
* @return $this
*/
public function setLSEN($lsen)
{
$this->lsen = (string)$lsen;
return $this;
} }
} }
@@ -0,0 +1,174 @@
<?php
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright 2010-2015 Mike van Riel<[email protected]>
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://phpdoc.org
*/
namespace phpDocumentor\Reflection\DocBlock;
/**
* Convenience class to create a Context for DocBlocks when not using the Reflection Component of phpDocumentor.
*
* For a DocBlock to be able to resolve types that use partial namespace names or rely on namespace imports we need to
* provide a bit of context so that the DocBlock can read that and based on it decide how to resolve the types to
* Fully Qualified names.
*
* @see Context for more information.
*/
final class ContextFactory
{
/** The literal used at the end of a use statement. */
const T_LITERAL_END_OF_USE = ';';
/** The literal used between sets of use statements */
const T_LITERAL_USE_SEPARATOR = ',';
/**
* Build a Context given a Class Reflection.
*
* @param \ReflectionClass $class
*
* @see Context for more information on Contexts.
*
* @return Context
*/
public function createFromClassReflector(\ReflectionClass $class)
{
return $this->createForNamespace(
$class->getNamespaceName(),
file_get_contents($class->getFileName())
);
}
/**
* Build a Context for a namespace in the provided file contents.
*
* @param string $namespace It does not matter if a `\` precedes the namespace name, this method first normalizes.
* @param string $fileContents the file's contents to retrieve the aliases from with the given namespace.
*
* @see Context for more information on Contexts.
*
* @return Context
*/
public function createForNamespace($namespace, $fileContents)
{
$namespace = trim($namespace, '\\');
$useStatements = [];
$currentNamespace = '';
$tokens = new \ArrayIterator(token_get_all($fileContents));
while ($tokens->valid()) {
switch ($tokens->current()[0]) {
case T_NAMESPACE:
$currentNamespace = $this->parseNamespace($tokens);
break;
case T_USE:
if ($currentNamespace === $namespace) {
$useStatements = array_merge($useStatements, $this->parseUseStatement($tokens));
}
break;
}
$tokens->next();
}
return new Context($namespace, $useStatements);
}
/**
* Deduce the name from tokens when we are at the T_NAMESPACE token.
*
* @param \ArrayIterator $tokens
*
* @return string
*/
private function parseNamespace(\ArrayIterator $tokens)
{
// skip to the first string or namespace separator
$this->skipToNextStringOrNamespaceSeparator($tokens);
$name = '';
while ($tokens->valid() && ($tokens->current()[0] === T_STRING || $tokens->current()[0] === T_NS_SEPARATOR)
) {
$name .= $tokens->current()[1];
$tokens->next();
}
return $name;
}
/**
* Deduce the names of all imports when we are at the T_USE token.
*
* @param \ArrayIterator $tokens
*
* @return string[]
*/
private function parseUseStatement(\ArrayIterator $tokens)
{
$uses = [];
$continue = true;
while ($continue) {
$this->skipToNextStringOrNamespaceSeparator($tokens);
list($alias, $fqnn) = $this->extractUseStatement($tokens);
$uses[$alias] = $fqnn;
if ($tokens->current()[0] === self::T_LITERAL_END_OF_USE) {
$continue = false;
}
}
return $uses;
}
/**
* Fast-forwards the iterator as longs as we don't encounter a T_STRING or T_NS_SEPARATOR token.
*
* @param \ArrayIterator $tokens
*
* @return void
*/
private function skipToNextStringOrNamespaceSeparator(\ArrayIterator $tokens)
{
while ($tokens->valid() && ($tokens->current()[0] !== T_STRING) && ($tokens->current()[0] !== T_NS_SEPARATOR)) {
$tokens->next();
}
}
/**
* Deduce the namespace name and alias of an import when we are at the T_USE token or have not reached the end of
* a USE statement yet.
*
* @param \ArrayIterator $tokens
*
* @return string
*/
private function extractUseStatement(\ArrayIterator $tokens)
{
$result = [''];
while ($tokens->valid()
&& ($tokens->current()[0] !== self::T_LITERAL_USE_SEPARATOR)
&& ($tokens->current()[0] !== self::T_LITERAL_END_OF_USE)
) {
if ($tokens->current()[0] === T_AS) {
$result[] = '';
}
if ($tokens->current()[0] === T_STRING || $tokens->current()[0] === T_NS_SEPARATOR) {
$result[count($result) - 1] .= $tokens->current()[1];
}
$tokens->next();
}
if (count($result) == 1) {
$result[] = substr($result[0], strrpos($result[0], '\\') + 1);
}
return array_reverse($result);
}
}
@@ -26,29 +26,25 @@ class Description implements \Reflector
/** @var string */ /** @var string */
protected $contents = ''; protected $contents = '';
/** @var array The contents, as an array of strings and Tag objects. */ /** @var array|null The contents, as an array of strings and Tag objects or null if it is not parsed yet. */
protected $parsedContents = null; protected $parsedContents = null;
/** @var \phpDocumentor\Reflection\DocBlock\Tags[] */
protected $tags = array();
/** @var DocBlock The DocBlock which this description belongs to. */ /** @var DocBlock The DocBlock which this description belongs to. */
protected $docblock = null; protected $docblock = null;
/** /**
* Populates the fields of a description. * Populates the fields of a description.
* *
* @param string $content The DocBlock contents without asterisks. * @param string $content The description's content.
* @param DocBlock $docblock The DocBlock which this description belongs to. * @param DocBlock $docblock The DocBlock which this description belongs to.
*/ */
public function __construct($content, DocBlock $docblock = null) public function __construct($content, DocBlock $docblock = null)
{ {
$this->contents = trim($content); $this->setContent($content)->setDocBlock($docblock);
$this->docblock = $docblock;
} }
/** /**
* Returns the text of this description. * Gets the text of this description.
* *
* @return string * @return string
*/ */
@@ -57,6 +53,21 @@ class Description implements \Reflector
return $this->contents; return $this->contents;
} }
/**
* Sets the text of this description.
*
* @param string $content The new text of this description.
*
* @return $this
*/
public function setContent($content)
{
$this->contents = trim($content);
$this->parsedContents = null;
return $this;
}
/** /**
* Returns the parsed text of this description. * Returns the parsed text of this description.
* *
@@ -101,7 +112,9 @@ class Description implements \Reflector
null, null,
PREG_SPLIT_DELIM_CAPTURE PREG_SPLIT_DELIM_CAPTURE
); );
for ($i=1, $l = count($this->parsedContents); $i<$l; $i += 2) {
$count = count($this->parsedContents);
for ($i=1; $i<$count; $i += 2) {
$this->parsedContents[$i] = Tag::createInstance( $this->parsedContents[$i] = Tag::createInstance(
$this->parsedContents[$i], $this->parsedContents[$i],
$this->docblock $this->docblock
@@ -111,7 +124,7 @@ class Description implements \Reflector
//In order to allow "literal" inline tags, the otherwise invalid //In order to allow "literal" inline tags, the otherwise invalid
//sequence "{@}" is changed to "@", and "{}" is changed to "}". //sequence "{@}" is changed to "@", and "{}" is changed to "}".
//See unit tests for examples. //See unit tests for examples.
for ($i=0, $l = count($this->parsedContents); $i<$l; $i += 2) { for ($i=0; $i<$count; $i += 2) {
$this->parsedContents[$i] = str_replace( $this->parsedContents[$i] = str_replace(
array('{@}', '{}'), array('{@}', '{}'),
array('@', '}'), array('@', '}'),
@@ -127,7 +140,7 @@ class Description implements \Reflector
* *
* @todo this should become a more intelligent piece of code where the * @todo this should become a more intelligent piece of code where the
* configuration contains a setting what format long descriptions are. * configuration contains a setting what format long descriptions are.
* *
* @codeCoverageIgnore Will be removed soon, in favor of adapters at * @codeCoverageIgnore Will be removed soon, in favor of adapters at
* PhpDocumentor itself that will process text in various formats. * PhpDocumentor itself that will process text in various formats.
* *
@@ -148,14 +161,45 @@ class Description implements \Reflector
); );
} }
if (class_exists('dflydev\markdown\MarkdownExtraParser')) { if (class_exists('Parsedown')) {
$markdown = \Parsedown::instance();
$result = $markdown->parse($result);
} elseif (class_exists('dflydev\markdown\MarkdownExtraParser')) {
$markdown = new \dflydev\markdown\MarkdownExtraParser(); $markdown = new \dflydev\markdown\MarkdownExtraParser();
$result = $markdown->transformMarkdown($result); $result = $markdown->transformMarkdown($result);
} elseif (class_exists('League\CommonMark\CommonMarkConverter')) {
$markdown = new \League\CommonMark\CommonMarkConverter();
$result = $markdown->convertToHtml($result);
} }
return trim($result); return trim($result);
} }
/**
* Gets the docblock this tag belongs to.
*
* @return DocBlock The docblock this description belongs to.
*/
public function getDocBlock()
{
return $this->docblock;
}
/**
* Sets the docblock this tag belongs to.
*
* @param DocBlock $docblock The new docblock this description belongs to.
* Setting NULL removes any association.
*
* @return $this
*/
public function setDocBlock(DocBlock $docblock = null)
{
$this->docblock = $docblock;
return $this;
}
/** /**
* Builds a string representation of this object. * Builds a string representation of this object.
* *
@@ -171,14 +215,12 @@ class Description implements \Reflector
} }
/** /**
* Returns the exported information (we should use the export static method * Returns the long description as a string.
* BUT this throws an exception at this point).
* *
* @return string * @return string
* @codeCoverageIgnore Not yet implemented
*/ */
public function __toString() public function __toString()
{ {
return 'Not yet implemented'; return $this->getContents();
} }
} }
@@ -22,32 +22,61 @@ namespace phpDocumentor\Reflection\DocBlock;
class Location class Location
{ {
/** @var int Line where the DocBlock text starts. */ /** @var int Line where the DocBlock text starts. */
protected $line_number = 0; protected $lineNumber = 0;
/** @var int Column where the DocBlock text starts. */ /** @var int Column where the DocBlock text starts. */
protected $column_number = 0; protected $columnNumber = 0;
public function __construct( public function __construct($lineNumber = 0, $columnNumber = 0)
$line_number = 0, {
$column_number = 0 $this->setLineNumber($lineNumber)->setColumnNumber($columnNumber);
) {
$this->line_number = (int)$line_number;
$this->column_number = (int)$column_number;
} }
/** /**
* @return int Line where the DocBlock text starts. * Returns the line number that is covered by this location.
*
* @return integer
*/ */
public function getLineNumber() public function getLineNumber()
{ {
return $this->line_number; return $this->lineNumber;
} }
/** /**
* @return int Column where the DocBlock text starts. * Registers which line number is covered by this location object.
*
* @param integer $lineNumber
*
* @return $this
*/
public function setLineNumber($lineNumber)
{
$this->lineNumber = (int)$lineNumber;
return $this;
}
/**
* Returns the column number (character position on a line) for this location object.
*
* @return integer
*/ */
public function getColumnNumber() public function getColumnNumber()
{ {
return $this->column_number; return $this->columnNumber;
}
/**
* Registers the column number (character position on a line) for this location object.
*
* @param integer $columnNumber
*
* @return $this
*/
public function setColumnNumber($columnNumber)
{
$this->columnNumber = (int)$columnNumber;
return $this;
} }
} }
@@ -0,0 +1,199 @@
<?php
/**
* phpDocumentor
*
* PHP Version 5.3
*
* @author Barry vd. Heuvel <[email protected]>
* @copyright 2013 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;
use phpDocumentor\Reflection\DocBlock;
/**
* Serializes a DocBlock instance.
*
* @author Barry vd. Heuvel <[email protected]>
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://phpdoc.org
*/
class Serializer
{
/** @var string The string to indent the comment with. */
protected $indentString = ' ';
/** @var int The number of times the indent string is repeated. */
protected $indent = 0;
/** @var bool Whether to indent the first line. */
protected $isFirstLineIndented = true;
/** @var int|null The max length of a line. */
protected $lineLength = null;
/**
* Create a Serializer instance.
*
* @param int $indent The number of times the indent string is
* repeated.
* @param string $indentString The string to indent the comment with.
* @param bool $indentFirstLine Whether to indent the first line.
* @param int|null $lineLength The max length of a line or NULL to
* disable line wrapping.
*/
public function __construct(
$indent = 0,
$indentString = ' ',
$indentFirstLine = true,
$lineLength = null
) {
$this->setIndentationString($indentString);
$this->setIndent($indent);
$this->setIsFirstLineIndented($indentFirstLine);
$this->setLineLength($lineLength);
}
/**
* Sets the string to indent comments with.
*
* @param string $indentString The string to indent comments with.
*
* @return $this This serializer object.
*/
public function setIndentationString($indentString)
{
$this->indentString = (string)$indentString;
return $this;
}
/**
* Gets the string to indent comments with.
*
* @return string The indent string.
*/
public function getIndentationString()
{
return $this->indentString;
}
/**
* Sets the number of indents.
*
* @param int $indent The number of times the indent string is repeated.
*
* @return $this This serializer object.
*/
public function setIndent($indent)
{
$this->indent = (int)$indent;
return $this;
}
/**
* Gets the number of indents.
*
* @return int The number of times the indent string is repeated.
*/
public function getIndent()
{
return $this->indent;
}
/**
* Sets whether or not the first line should be indented.
*
* Sets whether or not the first line (the one with the "/**") should be
* indented.
*
* @param bool $indentFirstLine The new value for this setting.
*
* @return $this This serializer object.
*/
public function setIsFirstLineIndented($indentFirstLine)
{
$this->isFirstLineIndented = (bool)$indentFirstLine;
return $this;
}
/**
* Gets whether or not the first line should be indented.
*
* @return bool Whether or not the first line should be indented.
*/
public function isFirstLineIndented()
{
return $this->isFirstLineIndented;
}
/**
* Sets the line length.
*
* Sets the length of each line in the serialization. Content will be
* wrapped within this limit.
*
* @param int|null $lineLength The length of each line. NULL to disable line
* wrapping altogether.
*
* @return $this This serializer object.
*/
public function setLineLength($lineLength)
{
$this->lineLength = null === $lineLength ? null : (int)$lineLength;
return $this;
}
/**
* Gets the line length.
*
* @return int|null The length of each line or NULL if line wrapping is
* disabled.
*/
public function getLineLength()
{
return $this->lineLength;
}
/**
* Generate a DocBlock comment.
*
* @param DocBlock The DocBlock to serialize.
*
* @return string The serialized doc block.
*/
public function getDocComment(DocBlock $docblock)
{
$indent = str_repeat($this->indentString, $this->indent);
$firstIndent = $this->isFirstLineIndented ? $indent : '';
$wrapLength = 80;
$text = $docblock->getText();
if ($this->lineLength) {
//3 === strlen(' * ')
$wrapLength = $this->lineLength - strlen($indent) - 3;
$text = wordwrap($text, $wrapLength);
}
$text = str_replace("\n", "\n{$indent} * ", $text);
$comment = "{$firstIndent}/**\n{$indent} * {$text}\n{$indent} *\n";
/** @var Tag $tag */
foreach ($docblock->getTags() as $tag) {
$tagText = (string) $tag;
if ($this->lineLength) {
$tagText = wordwrap($tagText, $wrapLength);
}
$tagText = str_replace("\n", "\n{$indent} * ", $tagText);
$comment .= "{$indent} * {$tagText}\n";
}
$comment .= $indent . ' */';
return $comment;
}
}
+158 -29
View File
@@ -23,16 +23,27 @@ use phpDocumentor\Reflection\DocBlock;
*/ */
class Tag implements \Reflector class Tag implements \Reflector
{ {
/**
* PCRE regular expression matching a tag name.
*/
const REGEX_TAGNAME = '[\w\-\_\\\\]+';
/** @var string Name of the tag */ /** @var string Name of the tag */
protected $tag = ''; protected $tag = '';
/** @var string Content of the tag */ /**
* @var string|null Content of the tag.
* When set to NULL, it means it needs to be regenerated.
*/
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. */ /**
* @var array|null The description, as an array of strings and Tag objects.
* When set to NULL, it means it needs to be regenerated.
*/
protected $parsedDescription = null; protected $parsedDescription = null;
/** @var Location Location of the tag. */ /** @var Location Location of the tag. */
@@ -103,15 +114,7 @@ class Tag implements \Reflector
DocBlock $docblock = null, DocBlock $docblock = null,
Location $location = null Location $location = null
) { ) {
if (!preg_match( $matches = self::extractTagParts($tag_line);
'/^@([\w\-\_\\\\]+)(?:\s*([^\s].*)|$)?/us',
$tag_line,
$matches
)) {
throw new \InvalidArgumentException(
'Invalid tag_line detected: ' . $tag_line
);
}
$handler = __CLASS__; $handler = __CLASS__;
if (isset(self::$tagHandlerMappings[$matches[1]])) { if (isset(self::$tagHandlerMappings[$matches[1]])) {
@@ -173,28 +176,28 @@ class Tag implements \Reflector
/** /**
* Parses a tag and populates the member variables. * Parses a tag and populates the member variables.
* *
* @param string $type Name of the tag. * @param string $name Name of the tag.
* @param string $content The contents of the given tag. * @param string $content The contents of the given tag.
* @param DocBlock $docblock The DocBlock which this tag belongs to. * @param DocBlock $docblock The DocBlock which this tag belongs to.
* @param Location $location Location of the tag. * @param Location $location Location of the tag.
*/ */
public function __construct( public function __construct(
$type, $name,
$content, $content,
DocBlock $docblock = null, DocBlock $docblock = null,
Location $location = null Location $location = null
) { ) {
$this->tag = $type; $this
$this->content = $content; ->setName($name)
$this->description = trim($content); ->setContent($content)
$this->docblock = $docblock; ->setDocBlock($docblock)
$this->location = $location; ->setLocation($location);
} }
/** /**
* Returns the name of this tag. * Gets the name of this tag.
* *
* @return string * @return string The name of this tag.
*/ */
public function getName() public function getName()
{ {
@@ -202,17 +205,54 @@ class Tag implements \Reflector
} }
/** /**
* Returns the content of this tag. * Sets the name of this tag.
*
* @param string $name The new name of this tag.
*
* @throws \InvalidArgumentException When an invalid tag name is provided.
*
* @return $this
*/
public function setName($name)
{
$this->validateTagName($name);
$this->tag = $name;
return $this;
}
/**
* Gets the content of this tag.
* *
* @return string * @return string
*/ */
public function getContent() public function getContent()
{ {
if (null === $this->content) {
$this->content = $this->description;
}
return $this->content; return $this->content;
} }
/** /**
* Returns the description component of this tag. * Sets the content of this tag.
*
* @param string $content The new content of this tag.
*
* @return $this
*/
public function setContent($content)
{
$this->setDescription($content);
$this->content = $content;
return $this;
}
/**
* Gets the description component of this tag.
* *
* @return string * @return string
*/ */
@@ -222,7 +262,23 @@ class Tag implements \Reflector
} }
/** /**
* Returns the parsed text of this description. * Sets the description component of this tag.
*
* @param string $description The new description component of this tag.
*
* @return $this
*/
public function setDescription($description)
{
$this->content = null;
$this->parsedDescription = null;
$this->description = trim($description);
return $this;
}
/**
* Gets the parsed text of this description.
* *
* @return array An array of strings and tag objects, in the order they * @return array An array of strings and tag objects, in the order they
* occur within the description. * occur within the description.
@@ -237,14 +293,53 @@ class Tag implements \Reflector
} }
/** /**
* Get the location of the tag. * Gets the docblock this tag belongs to.
*
* @return DocBlock The docblock this tag belongs to.
*/
public function getDocBlock()
{
return $this->docblock;
}
/**
* Sets the docblock this tag belongs to.
*
* @param DocBlock $docblock The new docblock this tag belongs to. Setting
* NULL removes any association.
*
* @return $this
*/
public function setDocBlock(DocBlock $docblock = null)
{
$this->docblock = $docblock;
return $this;
}
/**
* Gets the location of the tag.
* *
* @return Location Tag's location. * @return Location The tag's location.
*/ */
public function getLocation() public function getLocation()
{ {
return $this->location; return $this->location;
} }
/**
* Sets the location of the tag.
*
* @param Location $location The new location of the tag.
*
* @return $this
*/
public function setLocation(Location $location = null)
{
$this->location = $location;
return $this;
}
/** /**
* Builds a string representation of this object. * Builds a string representation of this object.
@@ -260,14 +355,48 @@ class Tag implements \Reflector
} }
/** /**
* Returns the exported information (we should use the export static method * Returns the tag as a serialized string
* BUT this throws an exception at this point).
* *
* @return string * @return string
* @codeCoverageIgnore Not yet implemented
*/ */
public function __toString() public function __toString()
{ {
return 'Not yet implemented'; return "@{$this->getName()} {$this->getContent()}";
}
/**
* Extracts all components for a tag.
*
* @param string $tagLine
*
* @return string[]
*/
private static function extractTagParts($tagLine)
{
$matches = array();
if (! preg_match('/^@(' . self::REGEX_TAGNAME . ')(?:\s*([^\s].*)|$)?/us', $tagLine, $matches)) {
throw new \InvalidArgumentException(
'The tag "' . $tagLine . '" does not seem to be wellformed, please check it for errors'
);
}
return $matches;
}
/**
* Validates if the tag name matches the expected format, otherwise throws an exception.
*
* @param string $name
*
* @return void
*/
private function validateTagName($name)
{
if (!preg_match('/^' . self::REGEX_TAGNAME . '$/u', $name)) {
throw new \InvalidArgumentException(
'The tag name "' . $name . '" is not wellformed. Tags may only consist of letters, underscores, '
. 'hyphens and backslashes.'
);
}
} }
} }
@@ -12,7 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tag;
/** /**
@@ -24,37 +23,54 @@ use phpDocumentor\Reflection\DocBlock\Tag;
*/ */
class AuthorTag extends Tag class AuthorTag extends Tag
{ {
/** @var string The name of the author */ /**
protected $name = ''; * PCRE regular expression matching any valid value for the name component.
*/
/** @var string The email of the author */ const REGEX_AUTHOR_NAME = '[^\<]*';
protected $email = '';
/** /**
* Parses a tag and populates the member variables. * PCRE regular expression matching any valid value for the email component.
*
* @param string $type Tag identifier for this tag (should be 'author').
* @param string $content Contents for this tag.
* @param DocBlock $docblock The DocBlock which this tag belongs to.
* @param Location $location Location of the tag.
*/ */
public function __construct( const REGEX_AUTHOR_EMAIL = '[^\>]*';
$type,
$content, /** @var string The name of the author */
DocBlock $docblock = null, protected $authorName = '';
Location $location = null
) { /** @var string The email of the author */
parent::__construct($type, $content, $docblock, $location); protected $authorEmail = '';
public function getContent()
{
if (null === $this->content) {
$this->content = $this->authorName;
if ('' != $this->authorEmail) {
$this->content .= "<{$this->authorEmail}>";
}
}
return $this->content;
}
/**
* {@inheritdoc}
*/
public function setContent($content)
{
parent::setContent($content);
if (preg_match( if (preg_match(
'/^([^\<]*)(\<([^\>]*)\>)?$/', '/^(' . self::REGEX_AUTHOR_NAME .
')(\<(' . self::REGEX_AUTHOR_EMAIL .
')\>)?$/u',
$this->description, $this->description,
$matches $matches
)) { )) {
$this->name = trim($matches[1]); $this->authorName = trim($matches[1]);
if (isset($matches[3])) { if (isset($matches[3])) {
$this->email = trim($matches[3]); $this->authorEmail = trim($matches[3]);
} }
} }
return $this;
} }
/** /**
@@ -64,7 +80,25 @@ class AuthorTag extends Tag
*/ */
public function getAuthorName() public function getAuthorName()
{ {
return $this->name; return $this->authorName;
}
/**
* Sets the author's name.
*
* @param string $authorName The new author name.
* An invalid value will set an empty string.
*
* @return $this
*/
public function setAuthorName($authorName)
{
$this->content = null;
$this->authorName
= preg_match('/^' . self::REGEX_AUTHOR_NAME . '$/u', $authorName)
? $authorName : '';
return $this;
} }
/** /**
@@ -74,6 +108,24 @@ class AuthorTag extends Tag
*/ */
public function getAuthorEmail() public function getAuthorEmail()
{ {
return $this->email; return $this->authorEmail;
}
/**
* Sets the author's email.
*
* @param string $authorEmail The new author email.
* An invalid value will set an empty string.
*
* @return $this
*/
public function setAuthorEmail($authorEmail)
{
$this->authorEmail
= preg_match('/^' . self::REGEX_AUTHOR_EMAIL . '$/u', $authorEmail)
? $authorEmail : '';
$this->content = null;
return $this;
} }
} }
@@ -12,7 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tag;
/** /**
@@ -24,26 +23,46 @@ use phpDocumentor\Reflection\DocBlock\Tag;
*/ */
class ExampleTag extends SourceTag class ExampleTag extends SourceTag
{ {
/** @var string Path to a file to use as an example. Can also be an URI. */ /**
* @var string Path to a file to use as an example.
* May also be an absolute URI.
*/
protected $filePath = ''; protected $filePath = '';
/** /**
* Parses a tag and populates the member variables. * @var bool Whether the file path component represents an URI.
* * This determines how the file portion appears at {@link getContent()}.
* @param string $type Tag identifier for this tag (should be 'example').
* @param string $content Contents for this tag.
* @param DocBlock $docblock The DocBlock which this tag belongs to.
* @param Location $location Location of the tag.
*/ */
public function __construct( protected $isURI = false;
$type,
$content, /**
DocBlock $docblock = null, * {@inheritdoc}
Location $location = null */
) { public function getContent()
Tag::__construct($type, $content, $docblock, $location); {
if (null === $this->content) {
$filePath = '"' . $this->filePath . '"';
if ($this->isURI) {
$filePath = $this->isUriRelative($this->filePath)
? str_replace('%2F', '/', rawurlencode($this->filePath))
:$this->filePath;
}
$this->content = $filePath . ' ' . parent::getContent();
}
return $this->content;
}
/**
* {@inheritdoc}
*/
public function setContent($content)
{
Tag::setContent($content);
if (preg_match( if (preg_match(
'/^ '/^
# File component
(?: (?:
# File path in quotes # File path in quotes
\"([^\"]+)\" \"([^\"]+)\"
@@ -58,34 +77,82 @@ class ExampleTag extends SourceTag
$matches $matches
)) { )) {
if ('' !== $matches[1]) { if ('' !== $matches[1]) {
//Quoted file path. $this->setFilePath($matches[1]);
$this->filePath = trim($matches[1]);
} elseif (false === strpos($matches[2], ':')) {
//Relative URL or a file path with no spaces in it.
$this->filePath = rawurldecode(
str_replace(array('/', '\\'), '%2F', $matches[2])
);
} else { } else {
//Absolute URL or URI. $this->setFileURI($matches[2]);
$this->filePath = $matches[2];
} }
if (isset($matches[3])) { if (isset($matches[3])) {
parent::__construct($type, $matches[3]); parent::setContent($matches[3]);
$this->content = $content;
} else { } else {
$this->description = ''; $this->setDescription('');
} }
$this->content = $content;
} }
return $this;
} }
/** /**
* Returns the file path. * Returns the file path.
* *
* @return string Path to a file to use as an example. Can also be an URI. * @return string Path to a file to use as an example.
* May also be an absolute URI.
*/ */
public function getFilePath() public function getFilePath()
{ {
return $this->filePath; return $this->filePath;
} }
/**
* Sets the file path.
*
* @param string $filePath The new file path to use for the example.
*
* @return $this
*/
public function setFilePath($filePath)
{
$this->isURI = false;
$this->filePath = trim($filePath);
$this->content = null;
return $this;
}
/**
* Sets the file path as an URI.
*
* This function is equivalent to {@link setFilePath()}, except that it
* converts an URI to a file path before that.
*
* There is no getFileURI(), as {@link getFilePath()} is compatible.
*
* @param string $uri The new file URI to use as an example.
*
* @return $this
*/
public function setFileURI($uri)
{
$this->isURI = true;
$this->content = null;
$this->filePath = $this->isUriRelative($uri)
? rawurldecode(str_replace(array('/', '\\'), '%2F', $uri))
: $this->filePath = $uri;
return $this;
}
/**
* Returns true if the provided URI is relative or contains a complete scheme (and thus is absolute).
*
* @param string $uri
*
* @return bool
*/
private function isUriRelative($uri)
{
return false === strpos($uri, ':');
}
} }
@@ -12,7 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tag;
/** /**
@@ -28,30 +27,35 @@ class LinkTag extends Tag
protected $link = ''; protected $link = '';
/** /**
* Parses a tag and populates the member variables. * {@inheritdoc}
*
* @param string $type Tag identifier for this tag (should be 'link').
* @param string $content Contents for this tag.
* @param DocBlock $docblock The DocBlock which this tag belongs to.
* @param Location $location Location of the tag.
*/ */
public function __construct( public function getContent()
$type, {
$content, if (null === $this->content) {
DocBlock $docblock = null, $this->content = "{$this->link} {$this->description}";
Location $location = null }
) {
parent::__construct($type, $content, $docblock, $location);
$content = preg_split('/\s+/u', $this->description, 2);
// any output is considered a type return $this->content;
$this->link = $content[0];
$this->description = isset($content[1]) ? $content[1] : $content[0];
} }
/** /**
* Returns the link * {@inheritdoc}
*/
public function setContent($content)
{
parent::setContent($content);
$parts = preg_split('/\s+/Su', $this->description, 2);
$this->link = $parts[0];
$this->setDescription(isset($parts[1]) ? $parts[1] : $parts[0]);
$this->content = $content;
return $this;
}
/**
* Gets the link
* *
* @return string * @return string
*/ */
@@ -65,10 +69,13 @@ class LinkTag extends Tag
* *
* @param string $link The link * @param string $link The link
* *
* @return void * @return $this
*/ */
public function setLink($link) public function setLink($link)
{ {
$this->link = $link; $this->link = $link;
$this->content = null;
return $this;
} }
} }
@@ -12,7 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tag;
/** /**
@@ -30,34 +29,51 @@ class MethodTag extends ReturnTag
/** @var string */ /** @var string */
protected $arguments = ''; protected $arguments = '';
/** @var bool */
protected $isStatic = false;
/** /**
* Parses a tag and populates the member variables. * {@inheritdoc}
*
* @param string $type Tag identifier for this tag (should be 'method').
* @param string $content Contents for this tag.
* @param DocBlock $docblock The DocBlock which this tag belongs to.
* @param Location $location Location of the tag.
*/ */
public function __construct( public function getContent()
$type, {
$content, if (null === $this->content) {
DocBlock $docblock = null, $this->content = '';
Location $location = null if ($this->isStatic) {
) { $this->content .= 'static ';
Tag::__construct($type, $content, $docblock, $location); }
$this->content .= $this->type .
" {$this->method_name}({$this->arguments}) " .
$this->description;
}
$matches = array(); return $this->content;
}
/**
* {@inheritdoc}
*/
public function setContent($content)
{
Tag::setContent($content);
// 1. none or more whitespace // 1. none or more whitespace
// 2. optionally a word with underscores followed by whitespace : as // 2. optionally the keyword "static" followed by whitespace
// 3. optionally a word with underscores followed by whitespace : as
// type for the return value // type for the return value
// 3. then optionally a word with underscores followed by () and // 4. then optionally a word with underscores followed by () and
// whitespace : as method name as used by phpDocumentor // whitespace : as method name as used by phpDocumentor
// 4. then a word with underscores, followed by ( and any character // 5. then a word with underscores, followed by ( and any character
// until a ) and whitespace : as method name with signature // until a ) and whitespace : as method name with signature
// 5. any remaining text : as description // 6. any remaining text : as description
if (preg_match( if (preg_match(
'/^ '/^
# Static keyword
# Declates a static method ONLY if type is also present
(?:
(static)
\s+
)?
# Return type # Return type
(?: (?:
([\w\|_\\\\]+) ([\w\|_\\\\]+)
@@ -80,18 +96,27 @@ class MethodTag extends ReturnTag
)) { )) {
list( list(
, ,
$static,
$this->type, $this->type,
$this->method_name, $this->method_name,
$this->arguments, $this->arguments,
$this->description $this->description
) = $matches; ) = $matches;
if (!$this->type) { if ($static) {
$this->type = 'void'; if (!$this->type) {
$this->type = 'static';
} else {
$this->isStatic = true;
}
} else {
if (!$this->type) {
$this->type = 'void';
}
} }
} else { $this->parsedDescription = null;
echo date('c') . ' ERR (3): @method contained invalid contents: '
. $this->content . PHP_EOL;
} }
return $this;
} }
/** /**
@@ -99,11 +124,14 @@ class MethodTag extends ReturnTag
* *
* @param string $method_name The name of the method. * @param string $method_name The name of the method.
* *
* @return void * @return $this
*/ */
public function setMethodName($method_name) public function setMethodName($method_name)
{ {
$this->method_name = $method_name; $this->method_name = $method_name;
$this->content = null;
return $this;
} }
/** /**
@@ -126,6 +154,9 @@ class MethodTag extends ReturnTag
public function setArguments($arguments) public function setArguments($arguments)
{ {
$this->arguments = $arguments; $this->arguments = $arguments;
$this->content = null;
return $this;
} }
/** /**
@@ -149,4 +180,30 @@ class MethodTag extends ReturnTag
return $arguments; return $arguments;
} }
/**
* Checks whether the method tag describes a static method or not.
*
* @return bool TRUE if the method declaration is for a static method, FALSE
* otherwise.
*/
public function isStatic()
{
return $this->isStatic;
}
/**
* Sets a new value for whether the method is static or not.
*
* @param bool $isStatic The new value to set.
*
* @return $this
*/
public function setIsStatic($isStatic)
{
$this->isStatic = $isStatic;
$this->content = null;
return $this;
}
} }
@@ -12,7 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tag;
/** /**
@@ -24,52 +23,63 @@ use phpDocumentor\Reflection\DocBlock\Tag;
*/ */
class ParamTag extends ReturnTag class ParamTag extends ReturnTag
{ {
/** /** @var string */
* @var string protected $variableName = '';
*/
protected $variableName = null; /** @var bool determines whether this is a variadic argument */
protected $isVariadic = false;
/** /**
* Parses a tag and populates the member variables. * {@inheritdoc}
*
* @param string $type Tag identifier for this tag (should be 'param').
* @param string $content Contents for this tag.
* @param DocBlock $docblock The DocBlock which this tag belongs to.
* @param Location $location Location of the tag.
*/ */
public function __construct( public function getContent()
$type, {
$content, if (null === $this->content) {
DocBlock $docblock = null, $this->content
Location $location = null = "{$this->type} {$this->variableName} {$this->description}";
) { }
Tag::__construct($type, $content, $docblock, $location); return $this->content;
$content = preg_split( }
'/(\s+)/u', /**
* {@inheritdoc}
*/
public function setContent($content)
{
Tag::setContent($content);
$parts = preg_split(
'/(\s+)/Su',
$this->description, $this->description,
3, 3,
PREG_SPLIT_DELIM_CAPTURE PREG_SPLIT_DELIM_CAPTURE
); );
// if the first item that is encountered is not a variable; it is a type // if the first item that is encountered is not a variable; it is a type
if (isset($content[0]) if (isset($parts[0])
&& (strlen($content[0]) > 0) && (strlen($parts[0]) > 0)
&& ($content[0][0] !== '$') && ($parts[0][0] !== '$')
) { ) {
$this->type = array_shift($content); $this->type = array_shift($parts);
array_shift($content); array_shift($parts);
} }
// if the next item starts with a $ it must be the variable name // if the next item starts with a $ or ...$ it must be the variable name
if (isset($content[0]) if (isset($parts[0])
&& (strlen($content[0]) > 0) && (strlen($parts[0]) > 0)
&& ($content[0][0] == '$') && ($parts[0][0] == '$' || substr($parts[0], 0, 4) === '...$')
) { ) {
$this->variableName = array_shift($content); $this->variableName = array_shift($parts);
array_shift($content); array_shift($parts);
if (substr($this->variableName, 0, 3) === '...') {
$this->isVariadic = true;
$this->variableName = substr($this->variableName, 3);
}
} }
$this->description = implode('', $content); $this->setDescription(implode('', $parts));
$this->content = $content;
return $this;
} }
/** /**
@@ -87,10 +97,23 @@ class ParamTag extends ReturnTag
* *
* @param string $name The new name for this variable. * @param string $name The new name for this variable.
* *
* @return void * @return $this
*/ */
public function setVariableName($name) public function setVariableName($name)
{ {
$this->variableName = $name; $this->variableName = $name;
$this->content = null;
return $this;
}
/**
* Returns whether this tag is variadic.
*
* @return boolean
*/
public function isVariadic()
{
return $this->isVariadic;
} }
} }
@@ -12,7 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Type\Collection; use phpDocumentor\Reflection\DocBlock\Type\Collection;
@@ -32,26 +31,34 @@ class ReturnTag extends Tag
protected $types = null; protected $types = null;
/** /**
* Parses a tag and populates the member variables. * {@inheritdoc}
*
* @param string $type Tag identifier for this tag (should be 'return').
* @param string $content Contents for this tag.
* @param DocBlock $docblock The DocBlock which this tag belongs to.
* @param Location $location Location of the tag.
*/ */
public function __construct( public function getContent()
$type, {
$content, if (null === $this->content) {
DocBlock $docblock = null, $this->content = "{$this->type} {$this->description}";
Location $location = null }
) {
parent::__construct($type, $content, $docblock, $location); return $this->content;
$content = preg_split('/\s+/u', $this->description, 2); }
/**
* {@inheritdoc}
*/
public function setContent($content)
{
parent::setContent($content);
$parts = preg_split('/\s+/Su', $this->description, 2);
// any output is considered a type // any output is considered a type
$this->type = $content[0]; $this->type = $parts[0];
$this->types = null;
$this->description = isset($content[1]) ? $content[1] : ''; $this->setDescription(isset($parts[1]) ? $parts[1] : '');
$this->content = $content;
return $this;
} }
/** /**
@@ -12,7 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tag;
/** /**
@@ -28,30 +27,35 @@ class SeeTag extends Tag
protected $refers = null; protected $refers = null;
/** /**
* Parses a tag and populates the member variables. * {@inheritdoc}
*
* @param string $type Tag identifier for this tag (should be 'see').
* @param string $content Contents for this tag.
* @param DocBlock $docblock The DocBlock which this tag belongs to.
* @param Location $location Location of the tag.
*/ */
public function __construct( public function getContent()
$type, {
$content, if (null === $this->content) {
DocBlock $docblock = null, $this->content = "{$this->refers} {$this->description}";
Location $location = null }
) { return $this->content;
parent::__construct($type, $content, $docblock, $location);
$content = preg_split('/\s+/u', $this->description, 2);
// any output is considered a type
$this->refers = $content[0];
$this->description = isset($content[1]) ? $content[1] : '';
} }
/** /**
* Returns the type of the variable. * {@inheritdoc}
*/
public function setContent($content)
{
parent::setContent($content);
$parts = preg_split('/\s+/Su', $this->description, 2);
// any output is considered a type
$this->refers = $parts[0];
$this->setDescription(isset($parts[1]) ? $parts[1] : '');
$this->content = $content;
return $this;
}
/**
* Gets the structural element this tag refers to.
* *
* @return string * @return string
*/ */
@@ -59,4 +63,19 @@ class SeeTag extends Tag
{ {
return $this->refers; return $this->refers;
} }
/**
* Sets the structural element this tag refers to.
*
* @param string $refers The new type this tag refers to.
*
* @return $this
*/
public function setReference($refers)
{
$this->refers = $refers;
$this->content = null;
return $this;
}
} }
@@ -36,20 +36,24 @@ class SourceTag extends Tag
protected $lineCount = null; protected $lineCount = null;
/** /**
* Parses a tag and populates the member variables. * {@inheritdoc}
*
* @param string $type Tag identifier for this tag (should be 'source').
* @param string $content Contents for this tag.
* @param DocBlock $docblock The DocBlock which this tag belongs to.
* @param Location $location Location of the tag.
*/ */
public function __construct( public function getContent()
$type, {
$content, if (null === $this->content) {
DocBlock $docblock = null, $this->content
Location $location = null = "{$this->startingLine} {$this->lineCount} {$this->description}";
) { }
parent::__construct($type, $content, $docblock, $location);
return $this->content;
}
/**
* {@inheritdoc}
*/
public function setContent($content)
{
parent::setContent($content);
if (preg_match( if (preg_match(
'/^ '/^
# Starting line # Starting line
@@ -70,12 +74,15 @@ class SourceTag extends Tag
if (isset($matches[2]) && '' !== $matches[2]) { if (isset($matches[2]) && '' !== $matches[2]) {
$this->lineCount = (int)$matches[2]; $this->lineCount = (int)$matches[2];
} }
$this->description = $matches[3]; $this->setDescription($matches[3]);
$this->content = $content;
} }
return $this;
} }
/** /**
* Returns the starting line. * Gets the starting line.
* *
* @return int The starting line, relative to the structural element's * @return int The starting line, relative to the structural element's
* location. * location.
@@ -85,6 +92,22 @@ class SourceTag extends Tag
return $this->startingLine; return $this->startingLine;
} }
/**
* Sets the starting line.
*
* @param int $startingLine The new starting line, relative to the
* structural element's location.
*
* @return $this
*/
public function setStartingLine($startingLine)
{
$this->startingLine = $startingLine;
$this->content = null;
return $this;
}
/** /**
* Returns the number of lines. * Returns the number of lines.
* *
@@ -95,4 +118,20 @@ class SourceTag extends Tag
{ {
return $this->lineCount; return $this->lineCount;
} }
/**
* Sets the number of lines.
*
* @param int|null $lineCount The new number of lines, relative to the
* starting line. NULL means "to the end".
*
* @return $this
*/
public function setLineCount($lineCount)
{
$this->lineCount = $lineCount;
$this->content = null;
return $this;
}
} }
@@ -12,9 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag;
/** /**
* Reflection class for a @var tag in a Docblock. * Reflection class for a @var tag in a Docblock.
* *
@@ -24,38 +21,4 @@ use phpDocumentor\Reflection\DocBlock\Tag;
*/ */
class VarTag extends ParamTag class VarTag extends ParamTag
{ {
/**
* Parses a tag and populates the member variables.
*
* @param string $type Tag identifier for this tag (should be 'var').
* @param string $content Contents for this tag.
* @param DocBlock $docblock The DocBlock which this tag belongs to.
* @param Location $location Location of the tag.
*/
public function __construct(
$type,
$content,
DocBlock $docblock = null,
Location $location = null
) {
Tag::__construct($type, $content, $docblock, $location);
$content = preg_split('/\s+/u', $this->description);
if (count($content) == 0) {
return;
}
// var always starts with the variable name
$this->type = array_shift($content);
// if the next item starts with a $ it must be the variable name
if ((count($content) > 0)
&& (strlen($content[0]) > 0)
&& ($content[0][0] == '$')
) {
$this->variableName = array_shift($content);
}
$this->description = implode(' ', $content);
}
} }
@@ -12,7 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tag;
/** /**
@@ -24,39 +23,45 @@ use phpDocumentor\Reflection\DocBlock\Tag;
*/ */
class VersionTag extends Tag class VersionTag extends Tag
{ {
/**
* PCRE regular expression matching a version vector.
* Assumes the "x" modifier.
*/
const REGEX_VECTOR = '(?:
# Normal release vectors.
\d\S*
|
# VCS version vectors. Per PHPCS, they are expected to
# follow the form of the VCS name, followed by ":", followed
# by the version vector itself.
# By convention, popular VCSes like CVS, SVN and GIT use "$"
# around the actual version vector.
[^\s\:]+\:\s*\$[^\$]+\$
)';
/** @var string The version vector. */ /** @var string The version vector. */
protected $version = ''; protected $version = '';
public function getContent()
{
if (null === $this->content) {
$this->content = "{$this->version} {$this->description}";
}
return $this->content;
}
/** /**
* Parses a tag and populates the member variables. * {@inheritdoc}
*
* @param string $type Tag identifier for this tag (should be 'version').
* @param string $content Contents for this tag.
* @param DocBlock $docblock The DocBlock which this tag belongs to.
* @param Location $location Location of the tag.
*/ */
public function __construct( public function setContent($content)
$type, {
$content, parent::setContent($content);
DocBlock $docblock = null,
Location $location = null
) {
parent::__construct($type, $content, $docblock, $location);
if (preg_match( if (preg_match(
'/^ '/^
# The version vector # The version vector
((?: (' . self::REGEX_VECTOR . ')
# Normal release vectors.
\d\S*
|
# VCS version vectors. Per PHPCS, they are expected to
# follow the form of the VCS name, followed by ":", followed
# by the version vector itself.
# By convention, popular VCSes like CVS, SVN and GIT use "$"
# around the actual version vector.
[^\s\:]+\:\s*\$[^\$]+\$
))
\s* \s*
# The description # The description
(.+)? (.+)?
@@ -65,12 +70,15 @@ class VersionTag extends Tag
$matches $matches
)) { )) {
$this->version = $matches[1]; $this->version = $matches[1];
$this->description = isset($matches[2]) ? $matches[2] : ''; $this->setDescription(isset($matches[2]) ? $matches[2] : '');
$this->content = $content;
} }
return $this;
} }
/** /**
* Returns the version section of the tag. * Gets the version section of the tag.
* *
* @return string The version section of the tag. * @return string The version section of the tag.
*/ */
@@ -78,4 +86,23 @@ class VersionTag extends Tag
{ {
return $this->version; return $this->version;
} }
/**
* Sets the version section of the tag.
*
* @param string $version The new version section of the tag.
* An invalid value will set an empty string.
*
* @return $this
*/
public function setVersion($version)
{
$this->version
= preg_match('/^' . self::REGEX_VECTOR . '$/ux', $version)
? $version
: '';
$this->content = null;
return $this;
}
} }
@@ -34,9 +34,9 @@ class Collection extends \ArrayObject
const OPERATOR_NAMESPACE = '\\'; const OPERATOR_NAMESPACE = '\\';
/** @var string[] List of recognized keywords */ /** @var string[] List of recognized keywords */
protected $keywords = array( protected static $keywords = array(
'string', 'int', 'integer', 'bool', 'boolean', 'float', 'double', 'string', 'int', 'integer', 'bool', 'boolean', 'float', 'double',
'object', 'mixed', 'array', 'resource', 'void', 'null', 'object', 'mixed', 'array', 'resource', 'void', 'null', 'scalar',
'callback', 'callable', 'false', 'true', 'self', '$this', 'static' 'callback', 'callable', 'false', 'true', 'self', '$this', 'static'
); );
@@ -152,7 +152,7 @@ class Collection extends \ArrayObject
} }
if ($this->isTypeAnArray($type)) { if ($this->isTypeAnArray($type)) {
return $this->expand(substr($type, 0, -2)).self::OPERATOR_ARRAY; return $this->expand(substr($type, 0, -2)) . self::OPERATOR_ARRAY;
} }
if ($this->isRelativeType($type) && !$this->isTypeAKeyword($type)) { if ($this->isRelativeType($type) && !$this->isTypeAKeyword($type)) {
@@ -186,7 +186,7 @@ class Collection extends \ArrayObject
*/ */
protected function isTypeAnArray($type) protected function isTypeAnArray($type)
{ {
return (substr($type, -2) == self::OPERATOR_ARRAY); return substr($type, -2) === self::OPERATOR_ARRAY;
} }
/** /**
@@ -199,7 +199,7 @@ class Collection extends \ArrayObject
*/ */
protected function isTypeAKeyword($type) protected function isTypeAKeyword($type)
{ {
return in_array(strtolower($type), $this->keywords); return in_array(strtolower($type), static::$keywords, true);
} }
/** /**
@@ -0,0 +1,94 @@
<?php
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright 2010-2015 Mike van Riel<[email protected]>
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://phpdoc.org
*/
namespace phpDocumentor\Reflection\DocBlock {
// Added imports on purpose as mock for the unit tests, please do not remove.
use Mockery as m;
use phpDocumentor\Reflection\DocBlock,
phpDocumentor\Reflection\DocBlock\Tag;
use \ReflectionClass; // yes, the slash is part of the test
/**
* @coversDefaultClass \phpDocumentor\Reflection\DocBlock\ContextFactory
* @covers ::<private>
*/
class ContextFactoryTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers ::createFromClassReflector
* @covers ::createForNamespace
* @uses phpDocumentor\Reflection\DocBlock\Context
*/
public function testReadsNamespaceFromClassReflection()
{
$fixture = new ContextFactory();
$context = $fixture->createFromClassReflector(new ReflectionClass($this));
$this->assertSame(__NAMESPACE__, $context->getNamespace());
}
/**
* @covers ::createFromClassReflector
* @covers ::createForNamespace
* @uses phpDocumentor\Reflection\DocBlock\Context
*/
public function testReadsAliasesFromClassReflection()
{
$fixture = new ContextFactory();
$expected = [
'm' => 'Mockery',
'DocBlock' => 'phpDocumentor\Reflection\DocBlock',
'Tag' => 'phpDocumentor\Reflection\DocBlock\Tag',
'ReflectionClass' => 'ReflectionClass'
];
$context = $fixture->createFromClassReflector(new ReflectionClass($this));
$this->assertSame($expected, $context->getNamespaceAliases());
}
/**
* @covers ::createForNamespace
* @uses phpDocumentor\Reflection\DocBlock\Context
*/
public function testReadsNamespaceFromProvidedNamespaceAndContent()
{
$fixture = new ContextFactory();
$context = $fixture->createForNamespace(__NAMESPACE__, file_get_contents(__FILE__));
$this->assertSame(__NAMESPACE__, $context->getNamespace());
}
/**
* @covers ::createForNamespace
* @uses phpDocumentor\Reflection\DocBlock\Context
*/
public function testReadsAliasesFromProvidedNamespaceAndContent()
{
$fixture = new ContextFactory();
$expected = [
'm' => 'Mockery',
'DocBlock' => 'phpDocumentor\Reflection\DocBlock',
'Tag' => 'phpDocumentor\Reflection\DocBlock\Tag',
'ReflectionClass' => 'ReflectionClass'
];
$context = $fixture->createForNamespace(__NAMESPACE__, file_get_contents(__FILE__));
$this->assertSame($expected, $context->getNamespaceAliases());
}
}
}
namespace phpDocumentor\Reflection\DocBlock\Mock {
// the following import should not show in the tests above
use phpDocumentor\Reflection\DocBlock\Description;
}
@@ -0,0 +1,61 @@
<?php
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright 2010-2015 Mike van Riel<[email protected]>
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://phpdoc.org
*/
namespace phpDocumentor\Reflection\DocBlock;
use Mockery as m;
/**
* @coversDefaultClass \phpDocumentor\Reflection\DocBlock\Context
*/
class ContextTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers ::__construct
* @covers ::getNamespace
*/
public function testProvidesANormalizedNamespace()
{
$fixture = new Context('\My\Space');
$this->assertSame('My\Space', $fixture->getNamespace());
}
/**
* @covers ::__construct
* @covers ::getNamespace
*/
public function testInterpretsNamespaceNamedGlobalAsRootNamespace()
{
$fixture = new Context('global');
$this->assertSame('', $fixture->getNamespace());
}
/**
* @covers ::__construct
* @covers ::getNamespace
*/
public function testInterpretsNamespaceNamedDefaultAsRootNamespace()
{
$fixture = new Context('default');
$this->assertSame('', $fixture->getNamespace());
}
/**
* @covers ::__construct
* @covers ::getNamespaceAliases
*/
public function testProvidesNormalizedNamespaceAliases()
{
$fixture = new Context('', ['Space' => '\My\Space']);
$this->assertSame(['Space' => 'My\Space'], $fixture->getNamespaceAliases());
}
}
@@ -33,8 +33,7 @@ class ExampleTagTest extends \PHPUnit_Framework_TestCase
* @param string $exLineCount * @param string $exLineCount
* @param string $exFilepath * @param string $exFilepath
* *
* @covers \phpDocumentor\Reflection\DocBlock\Tag\ExampleTag::__construct * @covers \phpDocumentor\Reflection\DocBlock\Tag\ExampleTag
* @covers \phpDocumentor\Reflection\DocBlock\Tag\ExampleTag::getFilePath
* @dataProvider provideDataForConstuctor * @dataProvider provideDataForConstuctor
* *
* @return void * @return void
@@ -32,8 +32,7 @@ class LinkTagTest extends \PHPUnit_Framework_TestCase
* @param string $exDescription * @param string $exDescription
* @param string $exLink * @param string $exLink
* *
* @covers \phpDocumentor\Reflection\DocBlock\Tag\LinkTag::__construct * @covers \phpDocumentor\Reflection\DocBlock\Tag\LinkTag
* @covers \phpDocumentor\Reflection\DocBlock\Tag\LinkTag::getLink
* @dataProvider provideDataForConstuctor * @dataProvider provideDataForConstuctor
* *
* @return void * @return void
@@ -34,10 +34,7 @@ class MethodTagTest extends \PHPUnit_Framework_TestCase
* @param string $description The short description mentioned in the * @param string $description The short description mentioned in the
* signature. * signature.
* *
* @covers \phpDocumentor\Reflection\DocBlock\Tag\MethodTag::__construct * @covers \phpDocumentor\Reflection\DocBlock\Tag\MethodTag
* @covers \phpDocumentor\Reflection\DocBlock\Tag\MethodTag::getMethodName
* @covers \phpDocumentor\Reflection\DocBlock\Tag\MethodTag::getArguments
*
* @dataProvider getTestSignatures * @dataProvider getTestSignatures
* *
* @return void * @return void
@@ -47,6 +44,7 @@ class MethodTagTest extends \PHPUnit_Framework_TestCase
$valid, $valid,
$expected_name, $expected_name,
$expected_return, $expected_return,
$expected_isStatic,
$paramCount, $paramCount,
$description $description
) { ) {
@@ -67,64 +65,82 @@ class MethodTagTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($expected_name, $tag->getMethodName()); $this->assertEquals($expected_name, $tag->getMethodName());
$this->assertEquals($expected_return, $tag->getType()); $this->assertEquals($expected_return, $tag->getType());
$this->assertEquals($description, $tag->getDescription()); $this->assertEquals($description, $tag->getDescription());
$this->assertEquals($expected_isStatic, $tag->isStatic());
$this->assertCount($paramCount, $tag->getArguments()); $this->assertCount($paramCount, $tag->getArguments());
} }
public function getTestSignatures() public function getTestSignatures()
{ {
return array( return array(
array( // TODO: Verify this case
'foo', // array(
false, 'foo', '', 0, '' // 'foo',
), // false, 'foo', '', false, 0, ''
// ),
array( array(
'foo()', 'foo()',
true, 'foo', 'void', 0, '' true, 'foo', 'void', false, 0, ''
), ),
array( array(
'foo() description', 'foo() description',
true, 'foo', 'void', 0, 'description' true, 'foo', 'void', false, 0, 'description'
), ),
array( array(
'int foo()', 'int foo()',
true, 'foo', 'int', 0, '' true, 'foo', 'int', false, 0, ''
), ),
array( array(
'int foo() description', 'int foo() description',
true, 'foo', 'int', 0, 'description' true, 'foo', 'int', false, 0, 'description'
), ),
array( array(
'int foo($a, $b)', 'int foo($a, $b)',
true, 'foo', 'int', 2, '' true, 'foo', 'int', false, 2, ''
), ),
array( array(
'int foo() foo(int $a, int $b)', 'int foo() foo(int $a, int $b)',
true, 'foo', 'int', 2, '' true, 'foo', 'int', false, 2, ''
), ),
array( array(
'int foo(int $a, int $b)', 'int foo(int $a, int $b)',
true, 'foo', 'int', 2, '' true, 'foo', 'int', false, 2, ''
), ),
array( array(
'null|int foo(int $a, int $b)', 'null|int foo(int $a, int $b)',
true, 'foo', 'null|int', 2, '' true, 'foo', 'null|int', false, 2, ''
), ),
array( array(
'int foo(null|int $a, int $b)', 'int foo(null|int $a, int $b)',
true, 'foo', 'int', 2, '' true, 'foo', 'int', false, 2, ''
), ),
array( array(
'\Exception foo() foo(Exception $a, Exception $b)', '\Exception foo() foo(Exception $a, Exception $b)',
true, 'foo', '\Exception', 2, '' true, 'foo', '\Exception', false, 2, ''
), ),
array( array(
'int foo() foo(Exception $a, Exception $b) description', 'int foo() foo(Exception $a, Exception $b) description',
true, 'foo', 'int', 2, 'description' true, 'foo', 'int', false, 2, 'description'
), ),
array( array(
'int foo() foo(\Exception $a, \Exception $b) description', 'int foo() foo(\Exception $a, \Exception $b) description',
true, 'foo', 'int', 2, 'description' true, 'foo', 'int', false, 2, 'description'
), ),
array(
'void()',
true, 'void', 'void', false, 0, ''
),
array(
'static foo()',
true, 'foo', 'static', false, 0, ''
),
array(
'static void foo()',
true, 'foo', 'void', true, 0, ''
),
array(
'static static foo()',
true, 'foo', 'static', true, 0, ''
)
); );
} }
} }
@@ -33,9 +33,7 @@ class ParamTagTest extends \PHPUnit_Framework_TestCase
* @param string $extractedVarName * @param string $extractedVarName
* @param string $extractedDescription * @param string $extractedDescription
* *
* @covers \phpDocumentor\Reflection\DocBlock\Tag\ParamTag::__construct * @covers \phpDocumentor\Reflection\DocBlock\Tag\ParamTag
* @covers \phpDocumentor\Reflection\DocBlock\Tag\ParamTag::getVariableName
*
* @dataProvider provideDataForConstructor * @dataProvider provideDataForConstructor
* *
* @return void * @return void
@@ -33,7 +33,6 @@ class ReturnTagTest extends \PHPUnit_Framework_TestCase
* @param string $extractedDescription * @param string $extractedDescription
* *
* @covers \phpDocumentor\Reflection\DocBlock\Tag\ReturnTag * @covers \phpDocumentor\Reflection\DocBlock\Tag\ReturnTag
*
* @dataProvider provideDataForConstructor * @dataProvider provideDataForConstructor
* *
* @return void * @return void
@@ -31,8 +31,7 @@ class SeeTagTest extends \PHPUnit_Framework_TestCase
* @param string $exContent * @param string $exContent
* @param string $exReference * @param string $exReference
* *
* @covers \phpDocumentor\Reflection\DocBlock\Tag\SeeTag::__construct * @covers \phpDocumentor\Reflection\DocBlock\Tag\SeeTag
* @covers \phpDocumentor\Reflection\DocBlock\Tag\SeeTag::getReference
* @dataProvider provideDataForConstuctor * @dataProvider provideDataForConstuctor
* *
* @return void * @return void
@@ -32,9 +32,7 @@ class SourceTagTest extends \PHPUnit_Framework_TestCase
* @param string $exStartingLine * @param string $exStartingLine
* @param string $exLineCount * @param string $exLineCount
* *
* @covers \phpDocumentor\Reflection\DocBlock\Tag\SourceTag::__construct * @covers \phpDocumentor\Reflection\DocBlock\Tag\SourceTag
* @covers \phpDocumentor\Reflection\DocBlock\Tag\SourceTag::getStartingLine
* @covers \phpDocumentor\Reflection\DocBlock\Tag\SourceTag::getLineCount
* @dataProvider provideDataForConstuctor * @dataProvider provideDataForConstuctor
* *
* @return void * @return void
@@ -33,7 +33,6 @@ class ThrowsTagTest extends \PHPUnit_Framework_TestCase
* @param string $extractedDescription * @param string $extractedDescription
* *
* @covers \phpDocumentor\Reflection\DocBlock\Tag\ThrowsTag * @covers \phpDocumentor\Reflection\DocBlock\Tag\ThrowsTag
*
* @dataProvider provideDataForConstructor * @dataProvider provideDataForConstructor
* *
* @return void * @return void
@@ -32,7 +32,7 @@ class VarTagTest extends \PHPUnit_Framework_TestCase
* @param string $exVariable * @param string $exVariable
* @param string $exDescription * @param string $exDescription
* *
* @covers \phpDocumentor\Reflection\DocBlock\Tag\VarTag::__construct * @covers \phpDocumentor\Reflection\DocBlock\Tag\VarTag
* @dataProvider provideDataForConstuctor * @dataProvider provideDataForConstuctor
* *
* @return void * @return void
@@ -32,8 +32,7 @@ class VersionTagTest extends \PHPUnit_Framework_TestCase
* @param string $exDescription * @param string $exDescription
* @param string $exVersion * @param string $exVersion
* *
* @covers \phpDocumentor\Reflection\DocBlock\Tag\VersionTag::__construct * @covers \phpDocumentor\Reflection\DocBlock\Tag\VersionTag
* @covers \phpDocumentor\Reflection\DocBlock\Tag\VersionTag::getVersion
* @dataProvider provideDataForConstuctor * @dataProvider provideDataForConstuctor
* *
* @return void * @return void
@@ -272,9 +272,7 @@ TAG_HANDLER
* @param string $content * @param string $content
* @param string $exDescription * @param string $exDescription
* *
* @covers \phpDocumentor\Reflection\DocBlock\Tag::__construct * @covers \phpDocumentor\Reflection\DocBlock\Tag
* @covers \phpDocumentor\Reflection\DocBlock\Tag::getDescription
* @covers \phpDocumentor\Reflection\DocBlock\Tag::getContent
* @dataProvider provideDataForConstuctor * @dataProvider provideDataForConstuctor
* *
* @return void * @return void
@@ -309,11 +307,6 @@ TAG_HANDLER
'unknown', 'unknown',
'', '',
'', '',
),
array(
'',
'unknown',
'unknown',
) )
); );
} }
@@ -14,6 +14,7 @@ namespace phpDocumentor\Reflection;
use phpDocumentor\Reflection\DocBlock\Context; use phpDocumentor\Reflection\DocBlock\Context;
use phpDocumentor\Reflection\DocBlock\Location; use phpDocumentor\Reflection\DocBlock\Location;
use phpDocumentor\Reflection\DocBlock\Tag\ReturnTag;
/** /**
* Test class for phpDocumentor\Reflection\DocBlock * Test class for phpDocumentor\Reflection\DocBlock
@@ -34,9 +35,9 @@ class DocBlockTest extends \PHPUnit_Framework_TestCase
{ {
$fixture = <<<DOCBLOCK $fixture = <<<DOCBLOCK
/** /**
* This is a short description. * This is a short description
* *
* This is a long description. * This is a long description
* *
* @see \MyClass * @see \MyClass
* @return void * @return void
@@ -48,11 +49,11 @@ DOCBLOCK;
new Location(2) new Location(2)
); );
$this->assertEquals( $this->assertEquals(
'This is a short description.', 'This is a short description',
$object->getShortDescription() $object->getShortDescription()
); );
$this->assertEquals( $this->assertEquals(
'This is a long description.', 'This is a long description',
$object->getLongDescription()->getContents() $object->getLongDescription()->getContents()
); );
$this->assertCount(2, $object->getTags()); $this->assertCount(2, $object->getTags());
@@ -70,7 +71,7 @@ DOCBLOCK;
/** /**
* @covers \phpDocumentor\Reflection\DocBlock::splitDocBlock * @covers \phpDocumentor\Reflection\DocBlock::splitDocBlock
* *
* @return void * @return void
*/ */
public function testConstructWithTagsOnly() public function testConstructWithTagsOnly()
@@ -90,6 +91,41 @@ DOCBLOCK;
$this->assertFalse($object->hasTag('category')); $this->assertFalse($object->hasTag('category'));
} }
/**
* @covers \phpDocumentor\Reflection\DocBlock::isTemplateStart
*/
public function testIfStartOfTemplateIsDiscovered()
{
$fixture = <<<DOCBLOCK
/**#@+
* @see \MyClass
* @return void
*/
DOCBLOCK;
$object = new DocBlock($fixture);
$this->assertEquals('', $object->getShortDescription());
$this->assertEquals('', $object->getLongDescription()->getContents());
$this->assertCount(2, $object->getTags());
$this->assertTrue($object->hasTag('see'));
$this->assertTrue($object->hasTag('return'));
$this->assertFalse($object->hasTag('category'));
$this->assertTrue($object->isTemplateStart());
}
/**
* @covers \phpDocumentor\Reflection\DocBlock::isTemplateEnd
*/
public function testIfEndOfTemplateIsDiscovered()
{
$fixture = <<<DOCBLOCK
/**#@-*/
DOCBLOCK;
$object = new DocBlock($fixture);
$this->assertEquals('', $object->getShortDescription());
$this->assertEquals('', $object->getLongDescription()->getContents());
$this->assertTrue($object->isTemplateEnd());
}
/** /**
* @covers \phpDocumentor\Reflection\DocBlock::cleanInput * @covers \phpDocumentor\Reflection\DocBlock::cleanInput
* *
@@ -142,7 +178,8 @@ DOCBLOCK;
{ {
$fixture = <<<DOCBLOCK $fixture = <<<DOCBLOCK
/** /**
* This is a short description. This is a long description. * This is a short description.
* This is a long description.
* This is a continuation of the long description. * This is a continuation of the long description.
*/ */
DOCBLOCK; DOCBLOCK;
@@ -271,7 +308,10 @@ DOCBLOCK;
*/ */
DOCBLOCK; DOCBLOCK;
$object = new DocBlock($fixture); $object = new DocBlock($fixture);
$this->assertCount(1, $object->getTags()); $this->assertCount(1, $tags = $object->getTags());
/** @var ReturnTag $tag */
$tag = reset($tags);
$this->assertEquals("Content on\n multiple lines.\n\n One more, after the break.", $tag->getDescription());
} }
/** /**