Skip to content

Commit 8850859

Browse files
committed
Refactored factory
1 parent 55d69d3 commit 8850859

File tree

5 files changed

+113
-106
lines changed

5 files changed

+113
-106
lines changed

lib/Core/GeneratorFactory.php

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace PhpBench\Pipeline\Core;
44

5+
use PhpBench\Pipeline\Core\Exception\InvalidStage;
6+
57
class GeneratorFactory
68
{
79
/**
@@ -14,9 +16,53 @@ public function __construct(StageRegistry $registry)
1416
$this->registry = $registry;
1517
}
1618

17-
public function generatorFor(string $stageName, array $config): ConfiguredGenerator
19+
public function generatorFor($stage, array $config = []): ConfiguredGenerator
20+
{
21+
if (is_callable($stage)) {
22+
$generator = $stage();
23+
24+
if (false === $generator instanceof Generator) {
25+
throw new InvalidStage(sprintf(
26+
'Callable stages must return Generators, got "%s"',
27+
is_object($generator) ? get_class($generator) : gettype($generator)
28+
));
29+
}
30+
31+
return new ConfiguredGenerator($generator, []);
32+
}
33+
34+
if (false === is_array($stage)) {
35+
throw new InvalidStage(sprintf(
36+
'Stage must either be an stage config element or a callable, got "%s"',
37+
is_object($stage) ? get_class($stage) : gettype($stage)
38+
));
39+
}
40+
41+
if (false === isset($stage[0])) {
42+
throw new InvalidStage(sprintf(
43+
'Stage config element must be a 1 to 2 element tuple (e.g. ["stage\/alias",{"config1":"value1"}]), got "%s"',
44+
json_encode($stage)
45+
));
46+
}
47+
48+
switch (count($stage)) {
49+
case 1:
50+
list($stage) = $stage;
51+
return $this->generatorForAliasAndConfig($stage);
52+
case 2:
53+
list($stage, $config) = $stage;
54+
return $this->generatorForAliasAndConfig($stage, $config);
55+
default:
56+
throw new InvalidStage(sprintf(
57+
'Stage config element cannot have more than 2 elements, got %s',
58+
count($stage)
59+
));
60+
}
61+
}
62+
63+
private function generatorForAliasAndConfig($stage, array $config = []): ConfiguredGenerator
1864
{
19-
$stage = $this->registry->get($stageName);
65+
$stage = $this->registry->get($stage);
2066
$schema = new Schema();
2167
$stage->configure($schema);
2268

lib/Core/Pipeline.php

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -61,41 +61,12 @@ private function buildGenerators(array $config): array
6161
{
6262
$generators = [];
6363
foreach ($config['stages'] as $stage) {
64-
if (is_callable($stage)) {
65-
$generators[] = new ConfiguredGenerator($stage(), $config);
66-
continue;
67-
}
68-
69-
if (is_array($stage)) {
70-
$generators[] = $this->buildGeneratorFromArray($stage, $config);
71-
continue;
72-
}
73-
74-
throw new InvalidStage(sprintf(
75-
'Stage must either be a callable or a stage alias, got "%s"',
76-
is_object($stage) ? get_class($stage) : gettype($stage)
77-
));
64+
$generators[] = $config['generator_factory']->generatorFor($stage);
7865
}
7966

8067
return $generators;
8168
}
8269

83-
private function buildGeneratorFromArray(array $stage, array $config): ConfiguredGenerator
84-
{
85-
if (count($stage) > 2) {
86-
throw new InvalidArgumentException(sprintf(
87-
'Stage must be at least a 1 and at most a 2 element array ([ (string) stage-name, (array) stage-config ], got %s elements',
88-
count($stage)
89-
));
90-
}
91-
92-
$stageName = $stage[0];
93-
$stageConfig = isset($stage[1]) ? $stage[1] : [];
94-
$generator = $config['generator_factory']->generatorFor($stageName, $stageConfig);
95-
96-
return $generator;
97-
}
98-
9970
/**
10071
* {@inheritdoc}
10172
*/

lib/Core/PipelineBuilder.php

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -51,40 +51,6 @@ public function build(): BuiltPipeline
5151
public function load(array $stages): self
5252
{
5353
foreach ($stages as $stage) {
54-
if (is_callable($stage) || is_string($stage)) {
55-
$this->stage($stage);
56-
continue;
57-
}
58-
59-
if (is_array($stage)) {
60-
if (false === isset($stage[0])) {
61-
throw new InvalidStage(sprintf(
62-
'Stage config element must be a 1 to 2 element tuple (e.g. ["stage\/alias",{"config1":"value1"}]), got "%s"',
63-
json_encode($stage)
64-
));
65-
}
66-
67-
switch (count($stage)) {
68-
case 1:
69-
list($stage) = $stage;
70-
$this->stage($stage);
71-
continue 2;
72-
case 2:
73-
list($stage, $config) = $stage;
74-
$this->stage($stage, $config);
75-
continue 2;
76-
default:
77-
throw new InvalidStage(sprintf(
78-
'Stage config element cannot have more than 2 elements, got %s',
79-
count($stage)
80-
));
81-
}
82-
}
83-
84-
throw new InvalidStage(sprintf(
85-
'Stage must either be an array config element or a callable, got "%s"',
86-
is_object($stage) ? get_class($stage) : gettype($stage)
87-
));
8854
}
8955

9056
return $this;

tests/Unit/Core/GeneratorFactoryTest.php

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use PhpBench\Pipeline\Core\Schema;
1212
use Generator;
1313
use PhpBench\Pipeline\Core\ConfiguredGenerator;
14+
use PhpBench\Pipeline\Core\Exception\InvalidStage;
15+
use stdClass;
1416

1517
class GeneratorFactoryTest extends TestCase
1618
{
@@ -46,7 +48,7 @@ public function testProducesAGeneratorFromTheGivenStageNameAndConfig()
4648
$this->stage1->__invoke()->will(function () {
4749
yield;
4850
});
49-
$generator = $this->factory->generatorFor('foobar', []);
51+
$generator = $this->factory->generatorFor(['foobar', []]);
5052
$this->assertInstanceOf(ConfiguredGenerator::class, $generator);
5153
$this->assertInstanceOf(Generator::class, $generator->generator());
5254
}
@@ -67,11 +69,46 @@ public function testResolvesConfig()
6769
$this->stage1->__invoke()->will(function () use (&$config) {
6870
yield;
6971
});
70-
$configuredGenerator = $this->factory->generatorFor('foobar', [
72+
$configuredGenerator = $this->factory->generatorFor(['foobar', [
7173
'bar' => 'six',
72-
]);
74+
]]);
7375
$this->assertInstanceOf(ConfiguredGenerator::class, $configuredGenerator);
7476
$this->assertInstanceOf(Generator::class, $configuredGenerator->generator());
7577
$this->assertEquals(['foo' => 'bar', 'bar' => 'six'], $configuredGenerator->config());
7678
}
79+
80+
public function testThrowsExceptionIfCallableDoesntReturnAGenerator()
81+
{
82+
$this->expectException(InvalidStage::class);
83+
$this->expectExceptionMessage('Callable stages must return Generators, got "stdClass"');
84+
85+
$this->factory->generatorFor(function () {
86+
return new stdClass();
87+
});
88+
}
89+
90+
public function testThrowsExceptionIfStageNotStageOrCallable()
91+
{
92+
$this->expectException(InvalidStage::class);
93+
$this->expectExceptionMessage('Stage must either be an stage config element or a callable, got "stdClass"');
94+
95+
$this->factory->generatorFor(new stdClass());
96+
}
97+
98+
public function testThrowsExceptionOnInvalidTuple()
99+
{
100+
$this->expectException(InvalidStage::class);
101+
$this->expectExceptionMessage('Stage config element must be a 1 to 2 element tuple (e.g. ["stage\/alias",{"config1":"value1"}]), got "{"foobar":{"foo":"bar"}}"');
102+
103+
$this->factory->generatorFor(['foobar' => [ 'foo' => 'bar' ]]);
104+
}
105+
106+
public function testInvalidStageArity()
107+
{
108+
$this->expectException(InvalidStage::class);
109+
$this->expectExceptionMessage('Stage config element cannot have more than 2 elements, got 3');
110+
111+
$this->factory->generatorFor(['asd', 'asd', 'asd']);
112+
}
113+
77114
}

tests/Unit/Core/PipelineTest.php

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
use PhpBench\Pipeline\Core\Exception\InvalidArgumentException;
1111
use PhpBench\Pipeline\Core\Exception\InvalidYieldedValue;
1212
use PhpBench\Pipeline\Core\ConfiguredGenerator;
13+
use Prophecy\Argument;
14+
use Generator;
1315

1416
class PipelineTest extends TestCase
1517
{
@@ -31,19 +33,24 @@ public function testRunsAnEmptyPipeline()
3133

3234
public function testPipesToCallableStage()
3335
{
36+
$this->factory->generatorFor(Argument::type('callable'))->will(function (array $args) {
37+
return new ConfiguredGenerator($args[0](), []);
38+
});
39+
3440
$data = $this->runPipeline([
3541
function () {
3642
list($config, $data) = yield;
3743
$data[] = 'Goodbye';
3844
yield $data;
3945
},
4046
], ['Hello']);
47+
4148
$this->assertEquals(['Hello', 'Goodbye'], $data);
4249
}
4350

4451
public function testPipesToAConfiguredStageWithNoConfig()
4552
{
46-
$this->factory->generatorFor('test/foobar', [])->will(function () {
53+
$this->factory->generatorFor(['test/foobar'])->will(function () {
4754
return new ConfiguredGenerator((function () {
4855
list($config, $data) = yield;
4956
$data[] = 'Goodbye';
@@ -58,17 +65,11 @@ public function testPipesToAConfiguredStageWithNoConfig()
5865

5966
public function testPipesToAConfiguredStageWithConfig()
6067
{
61-
$this->factory->generatorFor('test/foobar', [
62-
'key' => 'value',
63-
])->will(function () {
64-
return new ConfiguredGenerator((function () {
68+
$this->setUpFactory(['test/foobar', [ 'key' => 'value' ]], (function () {
6569
list($config, $data) = yield;
6670
$data[] = 'Goodbye';
6771
yield $data;
68-
})(), [
69-
'key' => 'value',
70-
]);
71-
});
72+
})(), [ 'key' => 'value' ]);
7273

7374
$data = $this->runPipeline([
7475
['test/foobar', ['key' => 'value']],
@@ -87,17 +88,10 @@ public function testSubstitutesConfig($configValue, array $data, array $expected
8788
$this->expectExceptionMessage($expectedMessage);
8889
}
8990

90-
$this->factory->generatorFor('test/foobar', [
91-
'key' => $configValue,
92-
])->will(function () use ($configValue) {
93-
return new ConfiguredGenerator((function () {
91+
$this->setUpFactory(['test/foobar', [ 'key' => $configValue ]], (function () {
9492
list($config, $data) = yield;
9593
yield [$config['key']];
96-
97-
})(), [
98-
'key' => $configValue,
99-
]);
100-
});
94+
})(), [ 'key' => $configValue ]);
10195

10296
$data = $this->runPipeline([
10397
['test/foobar', ['key' => $configValue]],
@@ -149,25 +143,6 @@ public function provideSubstitutesConfigTokensWithDataValues()
149143
];
150144
}
151145

152-
public function testThrowsExceptionIfStageNotStageOrCallable()
153-
{
154-
$this->expectException(InvalidStage::class);
155-
$this->expectExceptionMessage('Stage must either be a callable or a stage alias, got "stdClass"');
156-
$this->runPipeline([
157-
new stdClass(),
158-
]);
159-
}
160-
161-
public function testInvalidStageArity()
162-
{
163-
$this->expectException(InvalidArgumentException::class);
164-
$this->expectExceptionMessage('Stage must be at least a 1 and at most a 2 element array ([ (string) stage-name, (array) stage-config ], got 3 elements');
165-
166-
$this->runPipeline([
167-
['foobar', ['barfoo' => 'asd'], 'googoo'],
168-
]);
169-
}
170-
171146
public function testThrowsAnExceptionIfStageDoesNotYieldAnArray()
172147
{
173148
$this->expectException(InvalidYieldedValue::class);
@@ -191,6 +166,10 @@ public function testCanEnableFeedback()
191166
}
192167
};
193168

169+
$this->factory->generatorFor(Argument::type('callable'))->will(function ($args) {
170+
return new ConfiguredGenerator($args[0](), []);
171+
});
172+
194173
$result = $this->runPipeline([
195174
$stage,
196175
$stage,
@@ -222,4 +201,12 @@ private function runPipeline(array $stages, array $data = [], bool $feedback = f
222201

223202
return $return;
224203
}
204+
205+
private function setUpFactory($stage, Generator $generator, array $resolvedConfig = [])
206+
{
207+
$this->factory->generatorFor($stage)
208+
->willReturn(
209+
new ConfiguredGenerator($generator, $resolvedConfig)
210+
);
211+
}
225212
}

0 commit comments

Comments
 (0)