Skip to content

Commit

Permalink
decouple TemplateVariablesFactory
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Oct 23, 2018
1 parent d24aea7 commit a8fe5ab
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 90 deletions.
9 changes: 5 additions & 4 deletions create-rector.yml.dist
@@ -1,9 +1,10 @@
package: 'CodeQuality'
name: 'SimplifyMirrorAssignRector' # w/wo suffix
package: "CodeQuality"
name: "SimplifyMirrorAssignRector"
node_types:
- 'Assign'
- "Assign" # put main node first

description: 'Removes unneeded $a = $a assigns'
description: "Removes unneeded $a = $a assigns"
code_before: "$a = $a;"
code_after: ""
source: "" # e.g. link to RFC or headline in upgrade guide
level: "" # e.g. symfony30.yml, target config to append this rector to
2 changes: 1 addition & 1 deletion ecs-after-rector.yml
Expand Up @@ -22,4 +22,4 @@ services:
allowFallbackGlobalConstants: true

# add spaces between class elements
PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer: ~
PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer: ~
129 changes: 44 additions & 85 deletions packages/ContributorTools/src/Command/CreateRectorCommand.php
Expand Up @@ -4,15 +4,10 @@

use Nette\Utils\FileSystem;
use Nette\Utils\Strings;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Name\FullyQualified;
use Rector\CodingStyle\AfterRectorCodingStyle;
use Rector\Console\ConsoleStyle;
use Rector\ContributorTools\Configuration\Configuration;
use Rector\ContributorTools\Configuration\ConfigurationFactory;
use Rector\Printer\BetterStandardPrinter;
use Rector\ContributorTools\TemplateVariablesFactory;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
Expand Down Expand Up @@ -42,11 +37,6 @@ final class CreateRectorCommand extends Command
*/
private $configurationFactory;

/**
* @var BetterStandardPrinter
*/
private $betterStandardPrinter;

/**
* @var FinderSanitizer
*/
Expand All @@ -62,19 +52,29 @@ final class CreateRectorCommand extends Command
*/
private $afterRectorCodingStyle;

/**
* @var TemplateVariablesFactory
*/
private $templateVariablesFactory;

/**
* @var string
*/
private $testCasePath;

public function __construct(
ConsoleStyle $consoleStyle,
ConfigurationFactory $configurationFactory,
BetterStandardPrinter $betterStandardPrinter,
FinderSanitizer $finderSanitizer,
AfterRectorCodingStyle $afterRectorCodingStyle
AfterRectorCodingStyle $afterRectorCodingStyle,
TemplateVariablesFactory $templateVariablesFactory
) {
parent::__construct();
$this->consoleStyle = $consoleStyle;
$this->configurationFactory = $configurationFactory;
$this->betterStandardPrinter = $betterStandardPrinter;
$this->finderSanitizer = $finderSanitizer;
$this->afterRectorCodingStyle = $afterRectorCodingStyle;
$this->templateVariablesFactory = $templateVariablesFactory;
}

protected function configure(): void
Expand All @@ -86,91 +86,32 @@ protected function configure(): void
protected function execute(InputInterface $input, OutputInterface $output): int
{
$configuration = $this->configurationFactory->createFromConfigFile(getcwd() . '/create-rector.yml');
$data = $this->prepareData($configuration);

$testCasePath = null;
$templateVariables = $this->templateVariablesFactory->createFromConfiguration($configuration);

foreach ($this->findTemplateFileInfos() as $smartFileInfo) {
$destination = $smartFileInfo->getRelativeFilePathFromDirectory(self::TEMPLATES_DIRECTORY);
$destination = $this->applyData($destination, $data);

$content = $this->applyData($smartFileInfo->getContents(), $data);
$destination = $this->resolveDestination($smartFileInfo, $templateVariables);
$content = $this->resolveContent($smartFileInfo, $templateVariables);
FileSystem::write($destination, $content);

$this->generatedFiles[] = $destination;

if (! $testCasePath && Strings::endsWith($destination, 'Test.php')) {
$testCasePath = dirname($destination);
if (Strings::endsWith($destination, 'Test.php')) {
$this->testCasePath = dirname($destination);
}
}

$this->applyCodingStyle();

$this->printSuccess($configuration, $testCasePath);
$this->printSuccess($configuration->getName());

return ShellCode::SUCCESS;
}

/**
* @return mixed[]
* @param mixed[] $variables
*/
private function prepareData(Configuration $configuration): array
private function applyVariables(string $content, array $variables): string
{
$data = [
'_Package_' => $configuration->getPackage(),
'_Category_' => $configuration->getCategory(),
'_Description_' => $configuration->getDescription(),
'_Name_' => $configuration->getName(),
'_CodeBefore_' => trim($configuration->getCodeBefore()) . PHP_EOL,
'_CodeBeforeExample_' => $this->prepareCodeForDefinition($configuration->getCodeBefore()),
'_CodeAfter_' => trim($configuration->getCodeAfter()) . PHP_EOL,
'_CodeAfterExample_' => $this->prepareCodeForDefinition($configuration->getCodeAfter()),
'_Source_' => $this->prepareSourceDocBlock($configuration->getSource()),
];

$arrayNodes = [];
foreach ($configuration->getNodeTypes() as $nodeType) {
$arrayNodes[] = new ArrayItem(new ClassConstFetch(new FullyQualified($nodeType), 'class'));
}
$data['_NodeTypes_Php_'] = $this->betterStandardPrinter->prettyPrint([new Array_($arrayNodes)]);

$data['_NodeTypes_Doc_'] = '\\' . implode('|\\', $configuration->getNodeTypes());

return $data;
}

/**
* @param mixed[] $data
*/
private function applyData(string $content, array $data): string
{
return str_replace(array_keys($data), array_values($data), $content);
}

private function prepareCodeForDefinition(string $code): string
{
if (Strings::contains($code, PHP_EOL)) {
// multi lines
return sprintf("<<<'CODE_SAMPLE'%s%sCODE_SAMPLE%s", PHP_EOL, $code, PHP_EOL);
}

// single line
return "'" . str_replace("'", '"', $code) . "'";
}

private function prepareSourceDocBlock(string $source): string
{
if (! $source) {
return $source;
}

$sourceDocBlock = <<<'CODE_SAMPLE'
/**
* @see %s
*/
CODE_SAMPLE;

return sprintf($sourceDocBlock, $source);
return str_replace(array_keys($variables), array_values($variables), $content);
}

/**
Expand All @@ -184,16 +125,16 @@ private function findTemplateFileInfos(): array
return $this->finderSanitizer->sanitize($finder);
}

private function printSuccess(Configuration $configuration, string $testCasePath): void
private function printSuccess(string $name): void
{
$this->consoleStyle->title(sprintf('New files generated for "%s"', $configuration->getName()));
$this->consoleStyle->title(sprintf('New files generated for "%s"', $name));
sort($this->generatedFiles);
$this->consoleStyle->listing($this->generatedFiles);

$this->consoleStyle->success(sprintf(
'Now make these tests green again:%svendor/bin/phpunit %s',
PHP_EOL,
$testCasePath
$this->testCasePath
));
}

Expand All @@ -206,4 +147,22 @@ private function applyCodingStyle(): void

$this->afterRectorCodingStyle->apply($generatedPhpFiles);
}

/**
* @param string[] $templateVariables
*/
private function resolveDestination(SmartFileInfo $smartFileInfo, array $templateVariables): string
{
$destination = $smartFileInfo->getRelativeFilePathFromDirectory(self::TEMPLATES_DIRECTORY);

return $this->applyVariables($destination, $templateVariables);
}

/**
* @param string[] $templateVariables
*/
private function resolveContent(SmartFileInfo $smartFileInfo, array $templateVariables): string
{
return $this->applyVariables($smartFileInfo->getContents(), $templateVariables);
}
}
84 changes: 84 additions & 0 deletions packages/ContributorTools/src/TemplateVariablesFactory.php
@@ -0,0 +1,84 @@
<?php declare(strict_types=1);

namespace Rector\ContributorTools;

use Nette\Utils\Strings;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Name\FullyQualified;
use Rector\ContributorTools\Configuration\Configuration;
use Rector\Printer\BetterStandardPrinter;
use function Safe\sprintf;

final class TemplateVariablesFactory
{
/**
* @var BetterStandardPrinter
*/
private $betterStandardPrinter;

public function __construct(BetterStandardPrinter $betterStandardPrinter)
{
$this->betterStandardPrinter = $betterStandardPrinter;
}

/**
* @return mixed[]
*/
public function createFromConfiguration(Configuration $configuration): array
{
$data = [
'_Package_' => $configuration->getPackage(),
'_Category_' => $configuration->getCategory(),
'_Description_' => $configuration->getDescription(),
'_Name_' => $configuration->getName(),
'_CodeBefore_' => trim($configuration->getCodeBefore()) . PHP_EOL,
'_CodeBeforeExample_' => $this->createCodeForDefinition($configuration->getCodeBefore()),
'_CodeAfter_' => trim($configuration->getCodeAfter()) . PHP_EOL,
'_CodeAfterExample_' => $this->createCodeForDefinition($configuration->getCodeAfter()),
'_Source_' => $this->createSourceDocBlock($configuration->getSource()),
];

$data['_NodeTypes_Php_'] = $this->createNodeTypePhp($configuration);
$data['_NodeTypes_Doc_'] = '\\' . implode('|\\', $configuration->getNodeTypes());

return $data;
}

private function createCodeForDefinition(string $code): string
{
if (Strings::contains($code, PHP_EOL)) {
// multi lines
return sprintf("<<<'CODE_SAMPLE'%s%sCODE_SAMPLE%s", PHP_EOL, $code, PHP_EOL);
}

// single line
return "'" . str_replace("'", '"', $code) . "'";
}

private function createSourceDocBlock(string $source): string
{
if (! $source) {
return $source;
}

$sourceDocBlock = <<<'CODE_SAMPLE'
/**
* @see %s
*/
CODE_SAMPLE;

return sprintf($sourceDocBlock, $source);
}

private function createNodeTypePhp(Configuration $configuration): string
{
$arrayNodes = [];
foreach ($configuration->getNodeTypes() as $nodeType) {
$arrayNodes[] = new ArrayItem(new ClassConstFetch(new FullyQualified($nodeType), 'class'));
}

return $this->betterStandardPrinter->prettyPrint([new Array_($arrayNodes)]);
}
}

0 comments on commit a8fe5ab

Please sign in to comment.