Skip to content

Commit 75528b1

Browse files
mtk3dakondas
andauthored
Add tuple generator (#71)
* Add tuple generator * Remove text comparing test for tuple class generator * Arrange Tuple methods order in the old way * Remove ReturnTypeWillChange in all files * Remove unecessery types changes * Add tests to fully cover Tuples * Add tuples generating validator * Change Tuple message * Move basic concat method to Tuple abstract class * Change size const to inline * Change chema version for phpunit * Fix phpstan problems * Add generate tuples command to composer * Refactor tuples generating command * Add diff check to generator command * Keep .tuple dir * Keep .tuple dir * Fix tuple1 formatting * fixes after merge master * lock phpstan --------- Co-authored-by: Arkadiusz Kondas <arkadiusz.kondas@gmail.com>
1 parent 9ec74be commit 75528b1

36 files changed

Lines changed: 2107 additions & 73 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ clover.xml
66
.idea
77
composer.lock
88
/.phpunit.cache/
9+
.tuple/*
10+
!.tuple/.gitkeep

.php-cs-fixer.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
$finder = PhpCsFixer\Finder::create()
44
->in(__DIR__.'/src')
55
->in(__DIR__.'/tests')
6+
->in(__DIR__.'/generators')
67
;
78

89
$config = new PhpCsFixer\Config();

.tuple/.gitkeep

Whitespace-only changes.

bin/generate-tuples

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
declare(strict_types=1);
5+
6+
require __DIR__.'/../vendor/autoload.php';
7+
8+
use Munus\Generators\Tuple\TupleGeneratorConfiguration;
9+
use Munus\Tuple;
10+
11+
const VALIDATE_OPT = 'validate';
12+
13+
$options = getopt('', [VALIDATE_OPT]);
14+
$validateOnly = array_key_exists(VALIDATE_OPT, $options);
15+
16+
$tupleGenerator = TupleGeneratorConfiguration::getTupleGenerator();
17+
$tupleGenerator->prepareTuples(Tuple::TUPLE_MAX_SIZE);
18+
19+
$anyDiffs = false;
20+
21+
foreach ($tupleGenerator->getPreparedTuplesNames() as $className) {
22+
passthru(
23+
sprintf('diff -u .tuple/%s.php src/Tuple/%s.php', $className, $className),
24+
$foundDiff
25+
);
26+
27+
if ($foundDiff) {
28+
$anyDiffs = true;
29+
}
30+
}
31+
32+
if ($anyDiffs && $validateOnly) {
33+
error_log('Differences between exising and generated Tuples found.');
34+
error_log('Please regenerate tuples and try again.');
35+
exit(1);
36+
}
37+
38+
if (!$validateOnly) {
39+
$tupleGenerator->commitPreparedTuples();
40+
print_r('Tuples successfully generated.'.PHP_EOL);
41+
}
42+
43+
exit(0);

composer.json

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
},
1515
"require-dev": {
1616
"friendsofphp/php-cs-fixer": "^3.27",
17+
"nette/php-generator": "^4.0",
1718
"phpunit/phpunit": "^9.6.13",
18-
"phpstan/phpstan": "^1.11.0"
19+
"phpstan/phpstan": "1.11.1"
1920
},
2021
"autoload": {
2122
"psr-4": {
@@ -28,7 +29,8 @@
2829
},
2930
"autoload-dev": {
3031
"psr-4": {
31-
"Munus\\Tests\\": "tests/"
32+
"Munus\\Tests\\": "tests/",
33+
"Munus\\Generators\\": "generators/"
3234
}
3335
},
3436

@@ -51,7 +53,14 @@
5153
"coverage-html": [
5254
"phpunit --coverage-html coverage"
5355
],
56+
"generate-tuples": [
57+
"./bin/generate-tuples"
58+
],
59+
"validate-tuples": [
60+
"./bin/generate-tuples --validate"
61+
],
5462
"tests": [
63+
"@validate-tuples",
5564
"@check-cs",
5665
"@phpstan",
5766
"@phpunit-coverage"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Munus\Generators\Tuple;
6+
7+
interface ClassPersister
8+
{
9+
public function save(string $directory, string $className, string $content): void;
10+
11+
public function moveClass(string $fromDir, string $toDir, string $className): void;
12+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Munus\Generators\Tuple;
6+
7+
class FilePutContentsClassPersister implements ClassPersister
8+
{
9+
public function __construct(private string $sourcePath)
10+
{
11+
}
12+
13+
public function save(string $directory, string $className, string $content): void
14+
{
15+
$filePath = $this->sourcePath.$directory.'/'.$className.'.php';
16+
file_put_contents($filePath, $content);
17+
}
18+
19+
public function moveClass(string $fromDir, string $toDir, string $className): void
20+
{
21+
copy(sprintf('%s/%s.php', $fromDir, $className), sprintf('%s/%s.php', $toDir, $className));
22+
}
23+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Munus\Generators\Tuple;
6+
7+
use Nette\PhpGenerator\ClassType;
8+
use Nette\PhpGenerator\PhpNamespace;
9+
10+
abstract class FragmentGenerator
11+
{
12+
private const TYPE_TEMPLATE = 'T%s';
13+
private const VALUE_TEMPLATE = '$value%s';
14+
private const CLASS_VALUE_TEMPLATE = '$this->value%s';
15+
private const PARAMETER_NAMES_TEMPLATE = 'value%s';
16+
protected const EMPTY_COMMENT_LINE = '';
17+
18+
abstract public function append(PhpNamespace $namespace, ClassType $class, int $tupleSize, int $maxTupleSize): void;
19+
20+
protected function isMaxSizeTuple(int $tupleSize, int $maxTupleSize): bool
21+
{
22+
return $tupleSize === $maxTupleSize;
23+
}
24+
25+
protected function isTupleZero(int $tupleSize): bool
26+
{
27+
return 0 === $tupleSize;
28+
}
29+
30+
/**
31+
* @return string[]
32+
*/
33+
protected function types(int $tupleSize): array
34+
{
35+
return $this->listOfTemplate(self::TYPE_TEMPLATE, $tupleSize);
36+
}
37+
38+
/**
39+
* @return string[]
40+
*/
41+
protected function values(int $tupleSize): array
42+
{
43+
return $this->listOfTemplate(self::VALUE_TEMPLATE, $tupleSize);
44+
}
45+
46+
/**
47+
* @return string[]
48+
*/
49+
protected function classValues(int $tupleSize): array
50+
{
51+
return $this->listOfTemplate(self::CLASS_VALUE_TEMPLATE, $tupleSize);
52+
}
53+
54+
/**
55+
* @return string[]
56+
*/
57+
protected function parameterNames(int $tupleSize): array
58+
{
59+
return $this->listOfTemplate(self::PARAMETER_NAMES_TEMPLATE, $tupleSize);
60+
}
61+
62+
/**
63+
* @return string[]
64+
*/
65+
protected function listOfTemplate(string $template, int $tupleSize): array
66+
{
67+
if ($this->isTupleZero($tupleSize)) {
68+
return [];
69+
}
70+
71+
return array_map(
72+
fn (int $n): string => sprintf($template, $n),
73+
range(1, $tupleSize),
74+
);
75+
}
76+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Munus\Generators\Tuple\FragmentGenerator;
6+
7+
class AppendMethodGenerator extends AppendPrependMethodAbstractGenerator
8+
{
9+
protected function methodName(): string
10+
{
11+
return 'append';
12+
}
13+
14+
protected function listOfTypes(int $tupleSize): string
15+
{
16+
return join(', ', [...$this->types($tupleSize), 'T']);
17+
}
18+
19+
protected function listOfValues(int $tupleSize): string
20+
{
21+
return join(', ', [...$this->classValues($tupleSize), '$value']);
22+
}
23+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Munus\Generators\Tuple\FragmentGenerator;
6+
7+
use Munus\Exception\UnsupportedOperationException;
8+
use Munus\Generators\Tuple\FragmentGenerator;
9+
use Nette\PhpGenerator\ClassType;
10+
use Nette\PhpGenerator\PhpNamespace;
11+
12+
abstract class AppendPrependMethodAbstractGenerator extends FragmentGenerator
13+
{
14+
public function append(PhpNamespace $namespace, ClassType $class, int $tupleSize, int $maxTupleSize): void
15+
{
16+
$resultTupleSize = $tupleSize + 1;
17+
18+
$method = $class->addMethod($this->methodName());
19+
$method->addParameter('value');
20+
21+
if ($this->isMaxSizeTuple($tupleSize, $maxTupleSize)) {
22+
$namespace->addUse(UnsupportedOperationException::class);
23+
$method->setBody($this->getMaxTupleSizeExceptionThrowBody());
24+
25+
return;
26+
}
27+
28+
$method->setReturnType($this->getMethodReturnType($namespace, $resultTupleSize));
29+
$method->addComment('@template T');
30+
$method->addComment(self::EMPTY_COMMENT_LINE);
31+
$method->addComment('@param T $value');
32+
$method->addComment(self::EMPTY_COMMENT_LINE);
33+
$method->addComment($this->getReturnTypeComment($resultTupleSize, $tupleSize));
34+
$method->setBody($this->getMethodBody($resultTupleSize, $tupleSize));
35+
}
36+
37+
private function getMaxTupleSizeExceptionThrowBody(): string
38+
{
39+
return sprintf(
40+
'throw new UnsupportedOperationException(\'Can\\\'t %s next value. This is biggest possible Tuple\');',
41+
$this->methodName(),
42+
);
43+
}
44+
45+
private function getMethodReturnType(PhpNamespace $namespace, int $resultTupleSize): string
46+
{
47+
return sprintf('%s\Tuple%s', $namespace->getName(), $resultTupleSize);
48+
}
49+
50+
private function getReturnTypeComment(int $resultTupleSize, int $tupleSize): string
51+
{
52+
return sprintf('@returns Tuple%s<%s>', $resultTupleSize, $this->listOfTypes($tupleSize));
53+
}
54+
55+
private function getMethodBody(int $resultTupleSize, int $tupleSize): string
56+
{
57+
return sprintf('return new Tuple%s(%s);', $resultTupleSize, $this->listOfValues($tupleSize));
58+
}
59+
60+
abstract protected function listOfValues(int $tupleSize): string;
61+
62+
abstract protected function listOfTypes(int $tupleSize): string;
63+
64+
abstract protected function methodName(): string;
65+
}

0 commit comments

Comments
 (0)