Skip to content

Commit 233e4b3

Browse files
committed
Merge pull request #9 from boenrobot/LongDescription
Nested inline tag parsing
2 parents 607aa79 + d788b51 commit 233e4b3

File tree

4 files changed

+293
-3
lines changed

4 files changed

+293
-3
lines changed

phpunit.xml.dist

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,9 @@
66
<directory>./tests/</directory>
77
</testsuite>
88
</testsuites>
9+
<filter>
10+
<whitelist>
11+
<directory suffix=".php">./src/</directory>
12+
</whitelist>
13+
</filter>
914
</phpunit>

src/phpDocumentor/Reflection/DocBlock/LongDescription.php

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,36 @@ public function getParsedContents()
6161
{
6262
if (null === $this->parsedContents) {
6363
$this->parsedContents = preg_split(
64-
'/\{(\@.*?)\}/uS',
64+
'/\{
65+
# "{@}" is not a valid inline tag. This ensures that
66+
# we do not treat it as one, but treat it literally.
67+
(?!@\})
68+
# We want to capture the whole tag line, but without the
69+
# inline tag delimiters.
70+
(\@
71+
# Match everything up to the next delimiter.
72+
[^{}]*
73+
# Nested inline tag content should not be captured, or
74+
# it will appear in the result separately.
75+
(?:
76+
# Match nested inline tags.
77+
(?:
78+
# Because we did not catch the tag delimiters
79+
# earlier, we must be explicit with them here.
80+
# Notice that this also matches "{}", as a way
81+
# to later introduce it as an escape sequence.
82+
\{(?1)?\}
83+
|
84+
# Make sure we match hanging "{".
85+
\{
86+
)
87+
# Match content after the nested inline tag.
88+
[^{}]*
89+
)* # If there are more inline tags, match them as well.
90+
# We use "*" since there may not be any nested inline
91+
# tags.
92+
)
93+
\}/Sux',
6594
$this->contents,
6695
null,
6796
PREG_SPLIT_DELIM_CAPTURE
@@ -71,6 +100,17 @@ public function getParsedContents()
71100
$this->parsedContents[$i]
72101
);
73102
}
103+
104+
//In order to allow "literal" inline tags, the otherwise invalid
105+
//sequence "{@}" is changed to "@", and "{}" is changed to "}".
106+
//See unit tests for examples.
107+
for ($i=0, $l = count($this->parsedContents); $i<$l; $i += 2) {
108+
$this->parsedContents[$i] = str_replace(
109+
array('{@}', '{}'),
110+
array('@', '}'),
111+
$this->parsedContents[$i]
112+
);
113+
}
74114
}
75115
return $this->parsedContents;
76116
}
@@ -129,4 +169,4 @@ public function __toString()
129169
{
130170
return 'Not yet implemented';
131171
}
132-
}
172+
}
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
<?php
2+
/**
3+
* phpDocumentor Long Description Test
4+
*
5+
* PHP Version 5.3
6+
*
7+
* @author Vasil Rangelov <[email protected]>
8+
* @copyright 2010-2011 Mike van Riel / Naenius. (http://www.naenius.com)
9+
* @license http://www.opensource.org/licenses/mit-license.php MIT
10+
* @link http://phpdoc.org
11+
*/
12+
13+
namespace phpDocumentor\Reflection\DocBlock;
14+
15+
/**
16+
* Test class for phpDocumentor\Reflection\DocBlock\LongDescription
17+
*
18+
* @author Vasil Rangelov <[email protected]>
19+
* @copyright 2010-2011 Mike van Riel / Naenius. (http://www.naenius.com)
20+
* @license http://www.opensource.org/licenses/mit-license.php MIT
21+
* @link http://phpdoc.org
22+
*/
23+
class LongDescriptionTest extends \PHPUnit_Framework_TestCase
24+
{
25+
public function testConstruct()
26+
{
27+
$fixture = <<<LONGDESC
28+
This is text for a description.
29+
LONGDESC;
30+
$object = new LongDescription($fixture);
31+
$this->assertSame($fixture, $object->getContents());
32+
33+
$parsedContents = $object->getParsedContents();
34+
$this->assertCount(1, $parsedContents);
35+
$this->assertSame($fixture, $parsedContents[0]);
36+
}
37+
38+
public function testInlineTagParsing()
39+
{
40+
$fixture = <<<LONGDESC
41+
This is text for a {@link http://phpdoc.org/ description} that uses inline
42+
tags.
43+
LONGDESC;
44+
$object = new LongDescription($fixture);
45+
$this->assertSame($fixture, $object->getContents());
46+
47+
$parsedContents = $object->getParsedContents();
48+
$this->assertCount(3, $parsedContents);
49+
$this->assertSame('This is text for a ', $parsedContents[0]);
50+
$this->assertInstanceOf(
51+
__NAMESPACE__ . '\Tag\LinkTag',
52+
$parsedContents[1]
53+
);
54+
$this->assertSame(
55+
' that uses inline
56+
tags.',
57+
$parsedContents[2]
58+
);
59+
}
60+
61+
public function testInlineTagAtStartParsing()
62+
{
63+
$fixture = <<<LONGDESC
64+
{@link http://phpdoc.org/ This} is text for a description that uses inline
65+
tags.
66+
LONGDESC;
67+
$object = new LongDescription($fixture);
68+
$this->assertSame($fixture, $object->getContents());
69+
70+
$parsedContents = $object->getParsedContents();
71+
$this->assertCount(3, $parsedContents);
72+
73+
$this->assertSame('', $parsedContents[0]);
74+
$this->assertInstanceOf(
75+
__NAMESPACE__ . '\Tag\LinkTag',
76+
$parsedContents[1]
77+
);
78+
$this->assertSame(
79+
' is text for a description that uses inline
80+
tags.',
81+
$parsedContents[2]
82+
);
83+
}
84+
85+
public function testNestedInlineTagParsing()
86+
{
87+
$fixture = <<<LONGDESC
88+
This is text for a description with {@internal inline tag with
89+
{@link http://phpdoc.org another inline tag} in it}.
90+
LONGDESC;
91+
$object = new LongDescription($fixture);
92+
$this->assertSame($fixture, $object->getContents());
93+
94+
$parsedContents = $object->getParsedContents();
95+
$this->assertCount(3, $parsedContents);
96+
97+
$this->assertSame(
98+
'This is text for a description with ',
99+
$parsedContents[0]
100+
);
101+
$this->assertInstanceOf(
102+
__NAMESPACE__ . '\Tag',
103+
$parsedContents[1]
104+
);
105+
$this->assertSame('.', $parsedContents[2]);
106+
107+
$parsedDescription = $parsedContents[1]->getParsedDescription();
108+
$this->assertCount(3, $parsedDescription);
109+
$this->assertSame("inline tag with\n", $parsedDescription[0]);
110+
$this->assertInstanceOf(
111+
__NAMESPACE__ . '\Tag\LinkTag',
112+
$parsedDescription[1]
113+
);
114+
$this->assertSame(' in it', $parsedDescription[2]);
115+
}
116+
117+
public function testLiteralOpeningDelimiter()
118+
{
119+
$fixture = <<<LONGDESC
120+
This is text for a description containing { that is literal.
121+
LONGDESC;
122+
$object = new LongDescription($fixture);
123+
$this->assertSame($fixture, $object->getContents());
124+
125+
$parsedContents = $object->getParsedContents();
126+
$this->assertCount(1, $parsedContents);
127+
$this->assertSame($fixture, $parsedContents[0]);
128+
}
129+
130+
public function testNestedLiteralOpeningDelimiter()
131+
{
132+
$fixture = <<<LONGDESC
133+
This is text for a description containing {@internal inline tag that has { that
134+
is literal}.
135+
LONGDESC;
136+
$object = new LongDescription($fixture);
137+
$this->assertSame($fixture, $object->getContents());
138+
139+
$parsedContents = $object->getParsedContents();
140+
$this->assertCount(3, $parsedContents);
141+
$this->assertSame(
142+
'This is text for a description containing ',
143+
$parsedContents[0]
144+
);
145+
$this->assertInstanceOf(
146+
__NAMESPACE__ . '\Tag',
147+
$parsedContents[1]
148+
);
149+
$this->assertSame('.', $parsedContents[2]);
150+
151+
$this->assertSame(
152+
array('inline tag that has { that
153+
is literal'),
154+
$parsedContents[1]->getParsedDescription()
155+
);
156+
}
157+
158+
public function testLiteralClosingDelimiter()
159+
{
160+
$fixture = <<<LONGDESC
161+
This is text for a description with {} that is not a tag.
162+
LONGDESC;
163+
$object = new LongDescription($fixture);
164+
$this->assertSame($fixture, $object->getContents());
165+
166+
$parsedContents = $object->getParsedContents();
167+
$this->assertCount(1, $parsedContents);
168+
$this->assertSame(
169+
'This is text for a description with } that is not a tag.',
170+
$parsedContents[0]
171+
);
172+
}
173+
174+
public function testNestedLiteralClosingDelimiter()
175+
{
176+
$fixture = <<<LONGDESC
177+
This is text for a description with {@internal inline tag with {} that is not an
178+
inline tag}.
179+
LONGDESC;
180+
$object = new LongDescription($fixture);
181+
$this->assertSame($fixture, $object->getContents());
182+
183+
$parsedContents = $object->getParsedContents();
184+
$this->assertCount(3, $parsedContents);
185+
$this->assertSame(
186+
'This is text for a description with ',
187+
$parsedContents[0]
188+
);
189+
$this->assertInstanceOf(
190+
__NAMESPACE__ . '\Tag',
191+
$parsedContents[1]
192+
);
193+
$this->assertSame('.', $parsedContents[2]);
194+
195+
$this->assertSame(
196+
array('inline tag with } that is not an
197+
inline tag'),
198+
$parsedContents[1]->getParsedDescription()
199+
);
200+
}
201+
202+
public function testInlineTagEscapingSequence()
203+
{
204+
$fixture = <<<LONGDESC
205+
This is text for a description with literal {{@}link}.
206+
LONGDESC;
207+
$object = new LongDescription($fixture);
208+
$this->assertSame($fixture, $object->getContents());
209+
210+
$parsedContents = $object->getParsedContents();
211+
$this->assertCount(1, $parsedContents);
212+
$this->assertSame(
213+
'This is text for a description with literal {@link}.',
214+
$parsedContents[0]
215+
);
216+
}
217+
218+
public function testNestedInlineTagEscapingSequence()
219+
{
220+
$fixture = <<<LONGDESC
221+
This is text for a description with an {@internal inline tag with literal
222+
{{@}link{} in it}.
223+
LONGDESC;
224+
$object = new LongDescription($fixture);
225+
$this->assertSame($fixture, $object->getContents());
226+
227+
$parsedContents = $object->getParsedContents();
228+
$this->assertCount(3, $parsedContents);
229+
$this->assertSame(
230+
'This is text for a description with an ',
231+
$parsedContents[0]
232+
);
233+
$this->assertInstanceOf(
234+
__NAMESPACE__ . '\Tag',
235+
$parsedContents[1]
236+
);
237+
$this->assertSame('.', $parsedContents[2]);
238+
239+
$this->assertSame(
240+
array('inline tag with literal
241+
{@link} in it'),
242+
$parsedContents[1]->getParsedDescription()
243+
);
244+
}
245+
}

tests/phpDocumentor/Reflection/DocBlock/Tag/CoversTagTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class CoversTagTest extends \PHPUnit_Framework_TestCase
3232
* @param string $exContent
3333
* @param string $exReference
3434
*
35-
* @covers \phpDocumentor\Reflection\DocBlock\Tag\Covers::__construct
35+
* @covers \phpDocumentor\Reflection\DocBlock\Tag\CoversTag::__construct
3636
* @dataProvider provideDataForConstuctor
3737
*
3838
* @return void

0 commit comments

Comments
 (0)