Skip to content

Commit

Permalink
add interface-string
Browse files Browse the repository at this point in the history
  • Loading branch information
smoench committed Sep 18, 2020
1 parent b6a886b commit 9ca72bf
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 1 deletion.
37 changes: 37 additions & 0 deletions src/TypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\Types\Expression;
use phpDocumentor\Reflection\Types\Integer;
use phpDocumentor\Reflection\Types\InterfaceString;
use phpDocumentor\Reflection\Types\Intersection;
use phpDocumentor\Reflection\Types\Iterable_;
use phpDocumentor\Reflection\Types\Nullable;
Expand Down Expand Up @@ -71,6 +72,7 @@ final class TypeResolver
private $keywords = [
'string' => Types\String_::class,
'class-string' => Types\ClassString::class,
'interface-string' => Types\InterfaceString::class,
'html-escaped-string' => PseudoTypes\HtmlEscapedString::class,
'lowercase-string' => PseudoTypes\LowercaseString::class,
'non-empty-lowercase-string' => PseudoTypes\NonEmptyLowercaseString::class,
Expand Down Expand Up @@ -246,6 +248,8 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
if ($classType !== null) {
if ((string) $classType === 'class-string') {
$types[] = $this->resolveClassString($tokens, $context);
} elseif ((string) $classType === 'interface-string') {
$types[] = $this->resolveInterfaceString($tokens, $context);
} else {
$types[] = $this->resolveCollection($tokens, $classType, $context);
}
Expand Down Expand Up @@ -455,6 +459,39 @@ private function resolveClassString(ArrayIterator $tokens, Context $context) : T
return new ClassString($classType->getFqsen());
}

/**
* Resolves class string
*
* @param ArrayIterator<int, (string|null)> $tokens
*/
private function resolveInterfaceString(ArrayIterator $tokens, Context $context) : Type
{
$tokens->next();

$classType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION);

if (!$classType instanceof Object_ || $classType->getFqsen() === null) {
throw new RuntimeException(
$classType . ' is not a interface string'
);
}

$token = $tokens->current();
if ($token !== '>') {
if (empty($token)) {
throw new RuntimeException(
'interface-string: ">" is missing'
);
}

throw new RuntimeException(
'Unexpected character "' . $token . '", ">" is missing'
);
}

return new InterfaceString($classType->getFqsen());
}

/**
* Resolves the collection values and keys
*
Expand Down
56 changes: 56 additions & 0 deletions src/Types/InterfaceString.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

/**
* 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.
*
* @link http://phpdoc.org
*/

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\Type;

/**
* Value Object representing the type 'string'.
*
* @psalm-immutable
*/
final class InterfaceString implements Type
{
/** @var Fqsen|null */
private $fqsen;

/**
* Initializes this representation of a class string with the given Fqsen.
*/
public function __construct(?Fqsen $fqsen = null)
{
$this->fqsen = $fqsen;
}

/**
* Returns the FQSEN associated with this object.
*/
public function getFqsen() : ?Fqsen
{
return $this->fqsen;
}

/**
* Returns a rendered output of the Type as it would be used in a DocBlock.
*/
public function __toString() : string
{
if ($this->fqsen === null) {
return 'interface-string';
}

return 'interface-string<' . (string) $this->fqsen . '>';
}
}
39 changes: 39 additions & 0 deletions tests/unit/TypeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\Types\Expression;
use phpDocumentor\Reflection\Types\Integer;
use phpDocumentor\Reflection\Types\InterfaceString;
use phpDocumentor\Reflection\Types\Intersection;
use phpDocumentor\Reflection\Types\Iterable_;
use phpDocumentor\Reflection\Types\Null_;
Expand Down Expand Up @@ -79,6 +80,30 @@ public function testResolvingClassStrings(string $classString, bool $throwsExcep
$this->assertInstanceOf(ClassString::class, $resolvedType);
}

/**
* @uses \phpDocumentor\Reflection\Types\Context
* @uses \phpDocumentor\Reflection\Types\Object_
* @uses \phpDocumentor\Reflection\Types\String_
*
* @covers ::__construct
* @covers ::resolve
* @covers ::<private>
*
* @dataProvider provideInterfaceStrings
*/
public function testResolvingInterfaceStrings(string $interfaceString, bool $throwsException) : void
{
$fixture = new TypeResolver();

if ($throwsException) {
$this->expectException('RuntimeException');
}

$resolvedType = $fixture->resolve($interfaceString, new Context(''));

$this->assertInstanceOf(InterfaceString::class, $resolvedType);
}

/**
* @uses \phpDocumentor\Reflection\Types\Context
* @uses \phpDocumentor\Reflection\Types\Object_
Expand Down Expand Up @@ -748,6 +773,20 @@ public function provideClassStrings() : array
];
}

/**
* Returns a list of interface string types and whether they throw an exception.
*
* @return (string|bool)[][]
*/
public function provideInterfaceStrings() : array
{
return [
['interface-string<\phpDocumentor\Reflection>', false],
['interface-string<\phpDocumentor\Reflection\DocBlock>', false],
['interface-string<string>', true],
];
}

/**
* Provides a list of FQSENs to test the resolution patterns with.
*
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/Types/ClassStringTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function testClassStringStringifyCorrectly(ClassString $array, string $ex
public function provideClassStrings() : array
{
return [
'generic clss string' => [new ClassString(), 'class-string'],
'generic class string' => [new ClassString(), 'class-string'],
'typed class string' => [new ClassString(new Fqsen('\Foo\Bar')), 'class-string<\Foo\Bar>'],
];
}
Expand Down
43 changes: 43 additions & 0 deletions tests/unit/Types/InterfaceStringTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

/**
* 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.
*
* @link http://phpdoc.org
*/

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Fqsen;
use PHPUnit\Framework\TestCase;

/**
* @coversDefaultClass \phpDocumentor\Reflection\Types\ClassString
*/
class InterfaceStringTest extends TestCase
{
/**
* @dataProvider provideInterfaceStrings
* @covers ::__toString
*/
public function testInterfaceStringStringifyCorrectly(ClassString $array, string $expectedString) : void
{
$this->assertSame($expectedString, (string) $array);
}

/**
* @return mixed[]
*/
public function provideInterfaceStrings() : array
{
return [
'generic interface string' => [new InterfaceString(), 'interface-string'],
'typed interface string' => [new InterfaceString(new Fqsen('\Foo\Bar')), 'interface-string<\Foo\Bar>'],
];
}
}

0 comments on commit 9ca72bf

Please sign in to comment.