Skip to content

Commit

Permalink
Add InflectorSingularResolverTest (#1107)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Oct 29, 2021
1 parent 3bec30a commit c6d2339
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Rector\Tests\Naming\Rector\Foreach_\RenameForeachValueVariableToMatchExprVariableRector\Fixture;

final class SkipWithNumber
{
public function run(array $psr4NamespacesToPaths)
{
foreach ($psr4NamespacesToPaths as $psr4NamespaceToPath) {
continue;
}
}
}
28 changes: 22 additions & 6 deletions rules/CodingStyle/Rector/ClassMethod/UnSpreadOperatorRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use Rector\CodingStyle\NodeAnalyzer\SpreadVariablesCollector;
use Rector\CodingStyle\Reflection\VendorLocationDetector;
Expand Down Expand Up @@ -89,12 +90,8 @@ public function refactor(Node $node): ?Node

private function refactorClassMethod(ClassMethod $classMethod): ?ClassMethod
{
$scope = $classMethod->getAttribute(AttributeKey::SCOPE);
if ($scope instanceof Scope && $classMethod->isPublic()) {
$classReflection = $scope->getClassReflection();
if ($classReflection->isSubclassOf('PHPUnit\Framework\TestCase')) {
return null;
}
if ($this->isInPHPUnitTestCase($classMethod)) {
return null;
}

$spreadParams = $this->spreadVariablesCollector->resolveFromClassMethod($classMethod);
Expand Down Expand Up @@ -218,4 +215,23 @@ private function hasUnpackedArgs(array $args): bool

return false;
}

private function isInPHPUnitTestCase(ClassMethod $classMethod): bool
{
$scope = $classMethod->getAttribute(AttributeKey::SCOPE);
if (! $scope instanceof Scope) {
return false;
}

if (! $classMethod->isPublic()) {
return false;
}

$classReflection = $scope->getClassReflection();
if (! $classReflection instanceof ClassReflection) {
return false;
}

return $classReflection->isSubclassOf('PHPUnit\Framework\TestCase');
}
}
37 changes: 28 additions & 9 deletions rules/Naming/ExpectedNameResolver/InflectorSingularResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,23 @@
use Doctrine\Inflector\Inflector;
use Nette\Utils\Strings;

/**
* @see \Rector\Core\Tests\Naming\ExpectedNameResolver\InflectorSingularResolverTest
*/
final class InflectorSingularResolver
{
/**
* @var array<string, string>
*/
private const SINGULAR_VERB = [
private const SINGULARIZE_MAP = [
'news' => 'new',
];

/**
* @var string
* @see https://regex101.com/r/lbQaGC/3
*/
private const CAMELCASE_REGEX = '#(?<camelcase>([a-z]+|[A-Z]{1,}[a-z]+|_))#';
private const CAMELCASE_REGEX = '#(?<camelcase>([a-z\d]+|[A-Z\d]{1,}[a-z\d]+|_))#';

/**
* @var string
Expand All @@ -45,8 +48,9 @@ public function resolve(string $currentName): string
return Strings::substring($currentName, 0, -strlen($matchBy['by']));
}

if (array_key_exists($currentName, self::SINGULAR_VERB)) {
return self::SINGULAR_VERB[$currentName];
$resolvedValue = $this->resolveSingularizeMap($currentName);
if ($resolvedValue !== null) {
return $resolvedValue;
}

if (str_starts_with($currentName, self::SINGLE)) {
Expand All @@ -59,11 +63,7 @@ public function resolve(string $currentName): string
$singularValueVarName .= $this->inflector->singularize($camelCase['camelcase']);
}

if ($singularValueVarName === '') {
return $currentName;
}

if ($singularValueVarName === '_') {
if (in_array($singularValueVarName, ['', '_'], true)) {
return $currentName;
}

Expand All @@ -81,4 +81,23 @@ public function resolve(string $currentName): string

return $currentName;
}

private function resolveSingularizeMap(string $currentName): string|null
{
foreach (self::SINGULARIZE_MAP as $plural => $singular) {
if ($currentName === $plural) {
return $singular;
}

if (Strings::match($currentName, '#' . ucfirst($plural) . '#')) {
return Strings::replace($currentName, '#' . ucfirst($plural) . '#', ucfirst($singular));
}

if (Strings::match($currentName, '#' . $plural . '#')) {
return Strings::replace($currentName, '#' . $plural . '#', $singular);
}
}

return null;
}
}
14 changes: 7 additions & 7 deletions rules/Transform/Rector/New_/NewToMethodCallRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ public function getNodeTypes(): array
*/
public function refactor(Node $node): ?Node
{
foreach ($this->newsToMethodCalls as $newsToMethodCall) {
if (! $this->isObjectType($node, $newsToMethodCall->getNewObjectType())) {
foreach ($this->newsToMethodCalls as $newToMethodCalls) {
if (! $this->isObjectType($node, $newToMethodCalls->getNewObjectType())) {
continue;
}

$serviceObjectType = $newsToMethodCall->getServiceObjectType();
$serviceObjectType = $newToMethodCalls->getServiceObjectType();
$className = $node->getAttribute(AttributeKey::CLASS_NAME);
if ($className === $serviceObjectType->getClassName()) {
continue;
Expand All @@ -106,25 +106,25 @@ public function refactor(Node $node): ?Node

$propertyName = $this->getExistingFactoryPropertyName(
$class,
$newsToMethodCall->getServiceObjectType()
$newToMethodCalls->getServiceObjectType()
);

if ($propertyName === null) {
$serviceObjectType = $newsToMethodCall->getServiceObjectType();
$serviceObjectType = $newToMethodCalls->getServiceObjectType();
$propertyName = $this->classNaming->getShortName($serviceObjectType->getClassName());
$propertyName = lcfirst($propertyName);

$propertyMetadata = new PropertyMetadata(
$propertyName,
$newsToMethodCall->getServiceObjectType(),
$newToMethodCalls->getServiceObjectType(),
Class_::MODIFIER_PRIVATE
);
$this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata);
}

$propertyFetch = new PropertyFetch(new Variable('this'), $propertyName);

return new MethodCall($propertyFetch, $newsToMethodCall->getServiceMethod(), $node->args);
return new MethodCall($propertyFetch, $newToMethodCalls->getServiceMethod(), $node->args);
}

return $node;
Expand Down
6 changes: 3 additions & 3 deletions rules/Transform/Rector/StaticCall/StaticCallToNewRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ public function getNodeTypes(): array
*/
public function refactor(Node $node): ?Node
{
foreach ($this->staticCallsToNews as $staticCallToNews) {
if (! $this->isName($node->class, $staticCallToNews->getClass())) {
foreach ($this->staticCallsToNews as $staticCallsToNew) {
if (! $this->isName($node->class, $staticCallsToNew->getClass())) {
continue;
}

if (! $this->isName($node->name, $staticCallToNews->getMethod())) {
if (! $this->isName($node->name, $staticCallsToNew->getMethod())) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace Rector\Core\Tests\Naming\ExpectedNameResolver;

use Iterator;
use Rector\Naming\ExpectedNameResolver\InflectorSingularResolver;
use Rector\Testing\PHPUnit\AbstractTestCase;

final class InflectorSingularResolverTest extends AbstractTestCase
{
private InflectorSingularResolver $inflectorSingularResolver;

protected function setUp(): void
{
$this->boot();
$this->inflectorSingularResolver = $this->getService(InflectorSingularResolver::class);
}

/**
* @dataProvider provideData()
*/
public function testResolveForForeach(string $currentName, string $expectedSingularName): void
{
$singularValue = $this->inflectorSingularResolver->resolve($currentName);
$this->assertSame($expectedSingularName, $singularValue);
}

/**
* @return Iterator<string[]>
*/
public function provideData(): Iterator
{
yield ['psr4NamespacesToPaths', 'psr4NamespaceToPath'];
yield ['nestedNews', 'nestedNew'];
yield ['news', 'new'];
yield ['argsOrOptions', 'argOrOption'];
}
}

0 comments on commit c6d2339

Please sign in to comment.