Skip to content

Commit

Permalink
Add repeat() (#193)
Browse files Browse the repository at this point in the history
  • Loading branch information
phanan authored and lstrojny committed Sep 26, 2019
1 parent 79639d4 commit 8099470
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 4 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"src/Functional/ReduceRight.php",
"src/Functional/Reindex.php",
"src/Functional/Reject.php",
"src/Functional/Repeat.php",
"src/Functional/Retry.php",
"src/Functional/Select.php",
"src/Functional/SelectKeys.php",
Expand Down
20 changes: 16 additions & 4 deletions docs/functional-php.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
- [const_function()](#const_function)
- [id()](#id)
- [tap()](#tap)
- [repeat()](#repeat)

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

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

## concat()
Concatenates zero or more strings
Concatenates zero or more strings.

```php
<?php
Expand All @@ -1034,7 +1035,7 @@ $fooBar = concat('foo', 'bar');
```

## const_function()
Returns new function, that will constantly return its first argument (constant function)
Returns a new function that will constantly return its first argument.

```php
<?php
Expand All @@ -1046,7 +1047,7 @@ $one(); // -> 1


## id()
Proxy function, that do nothing, except returning its first argument
Proxy function that does nothing except returning its first argument.

```php
<?php
Expand All @@ -1058,7 +1059,7 @@ use function Functional\id;
## tap()
``mixed tap(mixed $value, callable $callback)``

Call the given Closure with the given value, then return the value.
Calls the given Closure with the given value, then returns the value.

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

## repeat()

Creates and returns a function that can be used to execute the given closure multiple times.

```php
<?php
use function Functional\repeat;
repeat(function () {
echo 'foo';
})(3); // 'foofoofoo'
```
5 changes: 5 additions & 0 deletions src/Functional/Functional.php
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,11 @@ final class Functional
*/
const reject = '\Functional\reject';

/**
* @see \Functional\repeat
*/
const repeat = '\Functional\repeat';

/**
* @see \Functional\retry
*/
Expand Down
44 changes: 44 additions & 0 deletions src/Functional/Repeat.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/**
* Copyright (C) 2011-2017 by Lars Strojny <lstrojny@php.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Functional;

use Closure;
use Functional\Exceptions\InvalidArgumentException;

/**
* Creates a function that can be used to repeat the execution of $callback.
*
* @param callable $callback
*
* @return Closure
*/
function repeat(callable $callback)
{
return function ($times) use ($callback) {
InvalidArgumentException::assertPositiveInteger($times, __FUNCTION__, 1);

for ($i = 0; $i < $times; $i++) {
$callback();
}
};
}
65 changes: 65 additions & 0 deletions tests/Functional/RepeatTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
/**
* Copyright (C) 2011-2017 by Lars Strojny <lstrojny@php.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the 'Software'), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Functional\Tests;

use Functional\Exceptions\InvalidArgumentException;
use function Functional\repeat;
use PHPUnit\Framework\MockObject\MockObject;

class Repeated
{
public function foo()
{
}
}

class RepeatTest extends AbstractTestCase
{
/** @var Repeated|MockObject */
private $repeated;

public function setUp()
{
parent::setUp();
$this->repeated = $this->createMock(Repeated::class);
}

public function test()
{
$this->repeated
->expects($this->exactly(10))
->method('foo');

repeat([$this->repeated, 'foo'])(10);
}

public function testNegativeRepeatedTimes()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(
'Functional\{closure}() expects parameter 1 to be positive integer, negative integer given'
);

repeat([$this->repeated, 'foo'])(-1);
}
}

0 comments on commit 8099470

Please sign in to comment.