Skip to content

Commit 85cffda

Browse files
authored
Merge pull request #34 from xp-forge/feature/yield-in-flatten
Add ability to use yield statements inside flatten()
2 parents 30fbcaf + 1617f4b commit 85cffda

File tree

5 files changed

+49
-38
lines changed

5 files changed

+49
-38
lines changed

src/main/php/util/data/AbstractMapper.class.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,20 @@
55
* iterator returns and returns its result.
66
*/
77
abstract class AbstractMapper extends \lang\Object implements \Iterator {
8-
protected $it, $func;
8+
protected $it, $func, $yieldMap;
99
private $current, $key, $valid;
1010

1111
/**
1212
* Creates a new Mapper instance
1313
*
1414
* @param php.Mapper $it
1515
* @param php.Closure $func
16+
* @param bool $yieldMap Whether yield $key => $value should be used to create maps
1617
*/
17-
public function __construct(\Iterator $it, \Closure $func) {
18+
public function __construct(\Iterator $it, \Closure $func, $yieldMap= true) {
1819
$this->it= $it;
1920
$this->func= $func;
21+
$this->yieldMap= $yieldMap;
2022
}
2123

2224
/** @return var */
@@ -26,7 +28,7 @@ protected abstract function map();
2628
protected function forward() {
2729
if ($this->valid= $this->it->valid()) {
2830
$result= $this->map();
29-
if ($result instanceof \Generator) {
31+
if ($this->yieldMap && $result instanceof \Generator) {
3032
foreach ($result as $this->key => $this->current) { }
3133
} else {
3234
$this->key= $this->it->key();

src/main/php/util/data/Sequence.class.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,9 +393,9 @@ public function flatten($function= null) {
393393
if (null === $function) {
394394
$it= $this->getIterator();
395395
} else if (Functions::$APPLY_WITH_KEY->isInstance($function)) {
396-
$it= new MapperWithKey($this->getIterator(), Functions::$APPLY_WITH_KEY->cast($function));
396+
$it= new MapperWithKey($this->getIterator(), Functions::$APPLY_WITH_KEY->cast($function), false);
397397
} else {
398-
$it= new Mapper($this->getIterator(), Functions::$APPLY->newInstance($function));
398+
$it= new Mapper($this->getIterator(), Functions::$APPLY->newInstance($function), false);
399399
}
400400
return new self(new Flattener($it));
401401
}

src/test/php/util/data/unittest/Enumerables.class.php

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@
1515
* @see php://generators
1616
*/
1717
abstract class Enumerables extends Object {
18-
private static $generators;
19-
20-
static function __static() {
21-
self::$generators= class_exists('Generator', false);
22-
}
2318

2419
/**
2520
* Returns valid arguments for the `of()` method.
@@ -32,7 +27,7 @@ public static function valid() {
3227

3328
/**
3429
* Returns valid arguments for the `of()` method: Arrays, iterables,
35-
* iterators and generators (the latter only if available).
30+
* iterators and generators.
3631
*
3732
* @return var[][]
3833
*/
@@ -42,7 +37,7 @@ public static function validArrays() {
4237

4338
/**
4439
* Returns valid arguments for the `of()` method: Maps, iterables,
45-
* iterators and generators (the latter only if available).
40+
* iterators and generators.
4641
*
4742
* @return var[][]
4843
*/
@@ -70,24 +65,21 @@ public static function fixedArrays() {
7065
* @return var[][]
7166
*/
7267
public static function streamedArrays() {
73-
return array_merge(
74-
self::$generators ? [
75-
[eval('return function() { yield 1; yield 2; yield 3; };'), 'closure'],
76-
[eval('$f= function() { yield 1; yield 2; yield 3; }; return $f();'), 'generator']
77-
] : [],
78-
[
79-
[newinstance(XPIterator::class, [], '{
80-
protected $numbers= [1, 2, 3];
81-
public function hasNext() { return !empty($this->numbers); }
82-
public function next() { return array_shift($this->numbers); }
83-
}'), 'xp-iterator'],
84-
[Sequence::of(newinstance(XPIterator::class, [], '{
85-
protected $numbers= [1, 2, 3];
86-
public function hasNext() { return !empty($this->numbers); }
87-
public function next() { return array_shift($this->numbers); }
88-
}')), 'self-of-xp-iterator']
89-
]
90-
);
68+
$f= function() { yield 1; yield 2; yield 3; };
69+
return [
70+
[$f, 'closure'],
71+
[$f(), 'generator'],
72+
[newinstance(XPIterator::class, [], '{
73+
protected $numbers= [1, 2, 3];
74+
public function hasNext() { return !empty($this->numbers); }
75+
public function next() { return array_shift($this->numbers); }
76+
}'), 'xp-iterator'],
77+
[Sequence::of(newinstance(XPIterator::class, [], '{
78+
protected $numbers= [1, 2, 3];
79+
public function hasNext() { return !empty($this->numbers); }
80+
public function next() { return array_shift($this->numbers); }
81+
}')), 'self-of-xp-iterator']
82+
];
9183
}
9284

9385
/**
@@ -110,10 +102,8 @@ public static function fixedMaps() {
110102
* @return var[][]
111103
*/
112104
public static function streamedMaps() {
113-
return self::$generators ? [
114-
[eval('return function() { yield "color" => "green"; yield "price" => 12.99; };'), 'closure'],
115-
[eval('$f= function() { yield "color" => "green"; yield "price" => 12.99; }; return $f();'), 'generator']
116-
] : [];
105+
$f= function() { yield 'color' => 'green'; yield 'price' => 12.99; };
106+
return [[$f, 'closure'], [$f(), 'generator']];
117107
}
118108
/**
119109
* Returns invalid arguments for the `of()` method: Primitives, non-iterable

src/test/php/util/data/unittest/SequenceFlatteningTest.class.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,23 @@ public function map_key_is_passed_to_function() {
4444
Sequence::of(['one' => [1], 'two' => [2], 'three' => [3]])->flatten(function($e, $key) use(&$keys) { $keys[]= $key; return $e; })->each();
4545
$this->assertEquals(['one', 'two', 'three'], $keys);
4646
}
47+
48+
#[@test]
49+
public function flatten_generator() {
50+
$this->assertSequence([2, 4, 0, 4, 1], Sequence::of([2])->flatten(function($n) {
51+
yield $n;
52+
yield $n + $n;
53+
yield $n - $n;
54+
yield $n * $n;
55+
yield $n / $n;
56+
}));
57+
}
58+
59+
#[@test]
60+
public function flatten_generator_with_key() {
61+
$this->assertSequence([3, 6], Sequence::of([1 => 2])->flatten(function($n, $key) {
62+
yield $n + $key;
63+
yield $n * ($n + $key);
64+
}));
65+
}
4766
}

src/test/php/util/data/unittest/SequenceMappingTest.class.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,17 @@ public function with_instance_method() {
4444
);
4545
}
4646

47-
#[@test, @action(new VerifyThat(function() { return class_exists('Generator', false); }))]
47+
#[@test]
4848
public function with_generator() {
4949
$records= Sequence::of([['unit' => 'yellow', 'amount' => 20], ['unit' => 'blue', 'amount' => 19]]);
50-
$generator= eval('return function($record) { yield $record["unit"] => $record["amount"]; };');
50+
$generator= function($record) { yield $record['unit'] => $record['amount']; };
5151
$this->assertEquals(['yellow' => 20, 'blue' => 19], $records->map($generator)->toMap());
5252
}
5353

54-
#[@test, @action(new VerifyThat(function() { return class_exists('Generator', false); }))]
54+
#[@test]
5555
public function with_generator_and_key() {
5656
$records= Sequence::of(['color' => 'green', 'price' => 12.99]);
57-
$generator= eval('return function($value, $key) { yield strtoupper($key) => $value; };');
57+
$generator= function($value, $key) { yield strtoupper($key) => $value; };
5858
$this->assertEquals(['COLOR' => 'green', 'PRICE' => 12.99], $records->map($generator)->toMap());
5959
}
6060
}

0 commit comments

Comments
 (0)