Skip to content

Commit 8099470

Browse files
phananlstrojny
authored andcommitted
Add repeat() (lstrojny#193)
1 parent 79639d4 commit 8099470

File tree

5 files changed

+131
-4
lines changed

5 files changed

+131
-4
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
"src/Functional/ReduceRight.php",
9393
"src/Functional/Reindex.php",
9494
"src/Functional/Reject.php",
95+
"src/Functional/Repeat.php",
9596
"src/Functional/Retry.php",
9697
"src/Functional/Select.php",
9798
"src/Functional/SelectKeys.php",

docs/functional-php.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
- [const_function()](#const_function)
6666
- [id()](#id)
6767
- [tap()](#tap)
68+
- [repeat()](#repeat)
6869

6970
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
7071

@@ -1024,7 +1025,7 @@ just a shortcut to `compare_on` as it composes the given key function with `spl_
10241025
# Miscellaneous
10251026

10261027
## concat()
1027-
Concatenates zero or more strings
1028+
Concatenates zero or more strings.
10281029

10291030
```php
10301031
<?php
@@ -1034,7 +1035,7 @@ $fooBar = concat('foo', 'bar');
10341035
```
10351036

10361037
## const_function()
1037-
Returns new function, that will constantly return its first argument (constant function)
1038+
Returns a new function that will constantly return its first argument.
10381039

10391040
```php
10401041
<?php
@@ -1046,7 +1047,7 @@ $one(); // -> 1
10461047

10471048

10481049
## id()
1049-
Proxy function, that do nothing, except returning its first argument
1050+
Proxy function that does nothing except returning its first argument.
10501051

10511052
```php
10521053
<?php
@@ -1058,7 +1059,7 @@ use function Functional\id;
10581059
## tap()
10591060
``mixed tap(mixed $value, callable $callback)``
10601061

1061-
Call the given Closure with the given value, then return the value.
1062+
Calls the given Closure with the given value, then returns the value.
10621063

10631064
```php
10641065
<?php
@@ -1068,3 +1069,14 @@ tap(User::create('John Doe'), function (User $user) {
10681069
})->login();
10691070
```
10701071

1072+
## repeat()
1073+
1074+
Creates and returns a function that can be used to execute the given closure multiple times.
1075+
1076+
```php
1077+
<?php
1078+
use function Functional\repeat;
1079+
repeat(function () {
1080+
echo 'foo';
1081+
})(3); // 'foofoofoo'
1082+
```

src/Functional/Functional.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,11 @@ final class Functional
349349
*/
350350
const reject = '\Functional\reject';
351351

352+
/**
353+
* @see \Functional\repeat
354+
*/
355+
const repeat = '\Functional\repeat';
356+
352357
/**
353358
* @see \Functional\retry
354359
*/

src/Functional/Repeat.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
/**
3+
* Copyright (C) 2011-2017 by Lars Strojny <lstrojny@php.net>
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
namespace Functional;
24+
25+
use Closure;
26+
use Functional\Exceptions\InvalidArgumentException;
27+
28+
/**
29+
* Creates a function that can be used to repeat the execution of $callback.
30+
*
31+
* @param callable $callback
32+
*
33+
* @return Closure
34+
*/
35+
function repeat(callable $callback)
36+
{
37+
return function ($times) use ($callback) {
38+
InvalidArgumentException::assertPositiveInteger($times, __FUNCTION__, 1);
39+
40+
for ($i = 0; $i < $times; $i++) {
41+
$callback();
42+
}
43+
};
44+
}

tests/Functional/RepeatTest.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
/**
3+
* Copyright (C) 2011-2017 by Lars Strojny <lstrojny@php.net>
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the 'Software'), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
namespace Functional\Tests;
24+
25+
use Functional\Exceptions\InvalidArgumentException;
26+
use function Functional\repeat;
27+
use PHPUnit\Framework\MockObject\MockObject;
28+
29+
class Repeated
30+
{
31+
public function foo()
32+
{
33+
}
34+
}
35+
36+
class RepeatTest extends AbstractTestCase
37+
{
38+
/** @var Repeated|MockObject */
39+
private $repeated;
40+
41+
public function setUp()
42+
{
43+
parent::setUp();
44+
$this->repeated = $this->createMock(Repeated::class);
45+
}
46+
47+
public function test()
48+
{
49+
$this->repeated
50+
->expects($this->exactly(10))
51+
->method('foo');
52+
53+
repeat([$this->repeated, 'foo'])(10);
54+
}
55+
56+
public function testNegativeRepeatedTimes()
57+
{
58+
$this->expectException(InvalidArgumentException::class);
59+
$this->expectExceptionMessage(
60+
'Functional\{closure}() expects parameter 1 to be positive integer, negative integer given'
61+
);
62+
63+
repeat([$this->repeated, 'foo'])(-1);
64+
}
65+
}

0 commit comments

Comments
 (0)