diff --git a/.github/workflows/cs.yml b/.github/workflows/cs.yml
new file mode 100644
index 0000000..a269994
--- /dev/null
+++ b/.github/workflows/cs.yml
@@ -0,0 +1,37 @@
+on:
+ pull_request:
+
+name: Coding Standards
+
+jobs:
+ phpstan:
+ name: PHP CS
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 7.4
+ tools: composer
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache dependencies
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Install dependencies
+ run: composer install --prefer-dist
+
+ - name: PHP-CS-Fixer
+ run: vendor/bin/php-cs-fixer fix --dry-run -v
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
new file mode 100644
index 0000000..31f3146
--- /dev/null
+++ b/.github/workflows/static-analysis.yml
@@ -0,0 +1,37 @@
+on:
+ pull_request:
+
+name: Static Analysis
+
+jobs:
+ phpstan:
+ name: PHPStan
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 7.4
+ tools: composer
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache dependencies
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Install dependencies
+ run: composer install --prefer-dist
+
+ - name: PHPStan
+ run: vendor/bin/phpstan
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..1e78057
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,90 @@
+name: Unit Tests
+
+on:
+ push:
+ branches:
+ - master
+ pull_request: ~
+
+jobs:
+ unit-test:
+ name: Unit ( PHP ${{ matrix.php }} )
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - php: 7.2
+ - php: 7.3
+ - php: 7.4
+ - php: 8.0
+ - php: 8.1
+ - php: 8.2
+ - php: 8.3
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: opcache
+ tools: composer
+
+ - name: Get composer cache directory
+ id: composercache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache dependencies
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.composercache.outputs.dir }}
+ key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json composer.lock') }}
+ restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer-
+
+ - name: Install dependencies
+ run: composer update
+
+ - name: Run unit tests
+ run: vendor/bin/phpunit
+
+ lowest:
+ name: Unit ( PHP ${{ matrix.php }} + Lowest )
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - php: 7.2
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: :xdebug
+ tools: composer
+
+ - name: Get composer cache directory
+ id: composercache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache dependencies
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.composercache.outputs.dir }}
+ key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json composer.lock') }}
+ restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer-
+
+ - name: Install dependencies
+ run: composer update --prefer-lowest --prefer-stable
+
+ - name: Run unit tests
+ run: vendor/bin/phpunit
diff --git a/.gitignore b/.gitignore
index 3a9875b..ff6836c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,7 @@
/vendor/
-composer.lock
+/composer.lock
+/vendor-bin/**/vendor
+/.php_cs.cache
+/src/compiled.php
+.idea
+.phpunit.result.cache
diff --git a/.php-version b/.php-version
new file mode 100644
index 0000000..5904f7a
--- /dev/null
+++ b/.php-version
@@ -0,0 +1 @@
+7.2
diff --git a/.php_cs b/.php_cs
new file mode 100644
index 0000000..0208b81
--- /dev/null
+++ b/.php_cs
@@ -0,0 +1,18 @@
+in('src')
+ ->in('tests')
+ ->notName('compiled.php');
+
+return PhpCsFixer\Config::create()
+ ->setRules(
+ [
+ '@PSR1' => true,
+ '@PSR2' => true,
+ 'array_syntax' => ['syntax' => 'short'],
+ 'single_import_per_statement' => false,
+ ]
+ )
+ ->setFinder($finder)
+;
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 14ba5f4..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-language: php
-
-sudo: false
-
-env:
- - COMPOSER_OPTIONS="
-
-php:
- - 7.1
-
-matrix:
- fast_finish: true
- include:
- - php: 7.1
- env:
- - COMPOSER_OPTIONS="--prefer-lowest"
- - php: 7.1
- env:
- - COMPOSER_OPTIONS="--prefer-stable"
- - php: 7.2
- - php: nightly
- allow_failures:
- - php: nightly
-
-cache:
- directories:
- - $HOME/.composer/cache/files
-
-before_install:
- - composer self-update
-
-install:
- - composer update -n "$COMPOSER_OPTIONS"
-
-script:
- - vendor/bin/phpunit
diff --git a/README.md b/README.md
index d61da20..3d9cc8a 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,10 @@ Lodash-PHP is a port of the [Lodash JS library](https://lodash.com/) to PHP. It
Lodash-PHP tries to mimick lodash.js as close as possible
+# Requirements
+
+Lodash-PHP requires minimum PHP 7.2+, but the latest version of PHP is always recommended.
+
# Installation
Install Lodash-PHP through composer:
@@ -44,6 +48,8 @@ _::each([1, 2, 3], function (int $item) {
- [Lang](#lang)
- [Math](#math)
- [Number](#number)
+- [Object](#object)
+- [Seq](#seq)
- [String](#string)
- [Util](#util)
@@ -52,10 +58,12 @@ _::each([1, 2, 3], function (int $item) {
### chunk
Creates an array of elements split into groups the length of `size`.
-
If `array` can't be split evenly, the final chunk will be the remaining
elements.
+
+
+
**Arguments:**
@param array $array array The array to process.
@@ -87,6 +95,7 @@ Creates an array with all falsey values removed. The values `false`, `null`,
+
**Arguments:**
@param array $array The array to compact.
@@ -113,11 +122,13 @@ and/or values.
+
+
**Arguments:**
@param array $array The array to concatenate.
-@param mixed $values The values to concatenate.
+@param array
fred, barney, & pebbles
' + +``` +## Lang + +### eq + +Performs a comparison between two values to determine if they are equivalent. + + + + +**Arguments:** + +@param mixed $value The value to compare. + +@param mixed $other The other value to compare. + + + +**Return:** + +@return boolean Returns `true` if the values are equivalent, else `false`. + +Example: +```php + 1]; +$other = (object) ['a' => 1]; + +eq($object, $object); // => true eq($object, $other); @@ -2697,6 +3420,10 @@ DateTime objects, exception objects, SPLObjectStorage, numbers, strings, typed arrays, resources, DOM Nodes. objects are compared by their own, not inherited, enumerable properties. + + + + **Arguments:** @param mixed $value The value to compare. @@ -2731,6 +3458,8 @@ Checks if `value` is an `\Exception`, `\ParseError`, \Error`, \Throwable`, \Soap + + **Arguments:** @param mixed $value The value to check. @@ -2739,7 +3468,7 @@ Checks if `value` is an `\Exception`, `\ParseError`, \Error`, \Throwable`, \Soap **Return:** -@return bool Returns `true` if `value` is an error object, else `false`. +@return boolean Returns `true` if `value` is an error object, else `false`. Example: ```php @@ -2751,6 +3480,7 @@ isError(new \Exception()) isError(\Exception::Class) // => false + ``` ## Math @@ -2760,17 +3490,19 @@ Adds two numbers. + + **Arguments:** -@param int|float|string $augend The first number in an addition. +@param (int | float | string) $augend The first number in an addition. -@param int|float|string $addend The second number in an addition. +@param (int | float | string) $addend The second number in an addition. **Return:** -@return int|float Returns the total. +@return (int | float) Returns the total. Example: ```php @@ -2787,15 +3519,16 @@ Computes the maximum value of `array`. If `array` is empty or falsey, null is re + **Arguments:** -@param array $ array The array to iterate over. +@param (array | null) $array The array to iterate over. **Return:** -@return int|null Returns the maximum value. +@return (int | null) Returns the maximum value. Example: ```php @@ -2817,11 +3550,12 @@ the value is ranked. The iteratee is invoked with one argument: (value). + **Arguments:** @param array $array The array to iterate over. -@param callable|string $iteratee The iteratee invoked per element. +@param (callable | string) $iteratee The iteratee invoked per element. @@ -2842,6 +3576,7 @@ maxBy($objects, function($o) { return $o['n']; }); // The `property` iteratee shorthand. maxBy($objects, 'n'); // => ['n' => 2] + ``` ## Number @@ -2851,13 +3586,15 @@ Clamps `number` within the inclusive `lower` and `upper` bounds. + + **Arguments:** -@param int $ number The number to clamp. +@param int $number The number to clamp. -@param int $ lower The lower bound. +@param int $lower The lower bound. -@param int $ upper The upper bound. +@param int $upper The upper bound. @@ -2881,13 +3618,16 @@ clamp(10, -5, 5) Checks if `number` is between `start` and up to, but not including, `end`. If `end` is not specified, it's set to `start` with `start` then set to `0`. - If `start` is greater than `end` the params are swapped to support negative ranges. + + + + **Arguments:** -@param float $ number The number to check. +@param float $number The number to check. @param float $start The start of the range. @@ -2897,7 +3637,7 @@ negative ranges. **Return:** -@return bool Returns `true` if `number` is in the range, else `false`. +@return boolean Returns `true` if `number` is in the range, else `false`. Example: ```php @@ -2929,29 +3669,33 @@ inRange(-3, -2, -6) ### random Produces a random number between the inclusive `lower` and `upper` bounds. - If only one argument is provided a number between `0` and the given number is returned. If `floating` is `true`, or either `lower` or `upper` are floats, a floating-point number is returned instead of an integer. + + + + **Arguments:** -@param int|float $lower The lower bound. +@param (int | float | bool) $lower The lower bound. -@param int|float $upper The upper bound. +@param (int | float | bool) $upper The upper bound. -@param bool $floating Specify returning a floating-point number. +@param (bool | null) $floating Specify returning a floating-point number. **Return:** -@return int|float Returns the random number. +@return (int | float) Returns the random number. Example: ```php an integer between 0 and 5 @@ -2963,6 +3707,151 @@ random(5, true) random(1.2, 5.2) // => a floating-point number between 1.2 and 5.2 + +``` +## Object + +### get + +Gets the value at path of object. If the resolved value is null the defaultValue is returned in its place. + + + + + + +**Arguments:** + +@param mixed $object The associative array or object to fetch value from + +@param (array | string) $path Dot separated or array of string + +@param mixed $defaultValue (optional)The value returned for unresolved or null values. + + + +**Return:** + +@return mixed Returns the resolved value. + +Example: +```php + ["key2" => ["key3" => "val1", "key4" => ""]]]; +get($sampleArray, 'key1.key2.key3'); +// => "val1" + +get($sampleArray, 'key1.key2.key5', "default"); +// => "default" + +get($sampleArray, 'key1.key2.key4', "default"); +// => "" + +``` +### pick + +Creates an object composed of the picked `object` properties. + + + + +**Arguments:** + +@param object $object The source object. + +@param (string | string[]) $paths The property paths to pick. + + + +**Return:** + +@return \stdClass Returns the new object. + +Example: +```php + 1, 'b' => '2', 'c' => 3]; + +pick($object, ['a', 'c']); +// => (object) ['a' => 1, 'c' => 3] + +``` +### pickBy + +Creates an object composed of the `object` properties `predicate` returns +truthy for. The predicate is invoked with two arguments: (value, key). + + + + +**Arguments:** + +@param (object | null) $object The source object. + +@param callable $predicate The function invoked per property. + + + +**Return:** + +@return \stdClass Returns the new object. + +Example: +```php + 1, 'b' => 'abc', 'c' => 3]; + +pickBy(object, 'is_numeric'); +// => (object) ['a' => 1, 'c' => 3] + +``` +## Seq + +### chain + +Creates a `lodash` wrapper instance that wraps `value` with explicit method +chain sequences enabled. The result of such sequences must be unwrapped +with `->value()`. + + + + +**Arguments:** + +@param mixed $value The value to wrap. + + + +**Return:** + +@return \_ Returns the new `lodash` wrapper instance. + +Example: +```php + 'barney', 'age' => 36], +['user' => 'fred', 'age' => 40], +['user' => 'pebbles', 'age' => 1 ], +]; + +$youngest = chain($users) +->sortBy('age') +->map(function($o) { +return $o['user'] . ' is ' . $o['age']; +}) +->head() +->value(); +// => 'pebbles is 1' + ``` ## String @@ -2972,6 +3861,8 @@ Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). + + **Arguments:** @param string $string The string to convert. @@ -3004,6 +3895,7 @@ to lower case. + **Arguments:** @param string $string The string to capitalize. @@ -3033,6 +3925,8 @@ letters to basic Latin letters and removing + + **Arguments:** @param string $string The string to deburr. @@ -3047,8 +3941,10 @@ Example: ```php 'deja vu' + ``` ### endsWith @@ -3056,6 +3952,7 @@ Checks if `string` ends with the given target string. + **Arguments:** @param string $string The string to inspect. @@ -3068,7 +3965,7 @@ Checks if `string` ends with the given target string. **Return:** -@return bool Returns `true` if `string` ends with `target`, else `false`. +@return boolean Returns `true` if `string` ends with `target`, else `false`. Example: ```php @@ -3090,6 +3987,7 @@ endsWith('abc', 'b', 2) Converts the characters "&", "<", ">", '"', and "'" in `string` to their corresponding HTML entities. + Though the ">" character is escaped for symmetry, characters like ">" and "/" don't need escaping in HTML and have no special meaning unless they're part of a tag or unquoted attribute value. See @@ -3100,6 +3998,9 @@ When working with HTML you should always [quote attribute values](http://wonko.com/post/html-escaping) to reduce XSS vectors. + + + **Arguments:** @param string $string The string to escape. @@ -3126,6 +4027,7 @@ Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", + **Arguments:** @param string $string The string to escape. @@ -3152,6 +4054,7 @@ Converts `string` to + **Arguments:** @param string $string The string to convert. @@ -3183,6 +4086,7 @@ Converts `string`, as space separated words, to lower case. + **Arguments:** @param string $string The string to convert. @@ -3214,6 +4118,7 @@ Converts the first character of `string` to lower case. + **Arguments:** @param string $string The string to convert. @@ -3239,9 +4144,12 @@ lowerFirst('FRED') ### pad Pads `string` on the left and right sides if it's shorter than `length`. - Padding characters are truncated if they can't be evenly divided by `length`. + + + + **Arguments:** @param string $string The string to pad. @@ -3278,6 +4186,8 @@ characters are truncated if they exceed `length`. + + **Arguments:** @param string $string The string to pad. @@ -3314,6 +4224,7 @@ characters are truncated if they exceed `length`. +s **Arguments:** @param string $string ='' The string to pad. @@ -3341,7 +4252,7 @@ padStart('abc', 6, '_-') padStart('abc', 2) // => 'abc' -s + ``` ### parseInt @@ -3352,9 +4263,13 @@ hexadecimal, in which case a `radix` of `16` is used. **Note:** This method uses PHP's built-in integer casting, which does not necessarily align with the [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`. + + + + **Arguments:** -@param int|float|string $string The string to convert. +@param (int | float | string) $string The string to convert. @param int $radix The radix to interpret `string` by. @@ -3379,6 +4294,8 @@ Repeats the given string `n` times. + + **Arguments:** @param string $string The string to repeat. @@ -3413,13 +4330,17 @@ Replaces matches for `pattern` in `string` with `replacement`. **Note:** This method is based on [`String#replace`](https://mdn.io/String/replace). + + + + **Arguments:** @param string $string The string to modify. @param string $pattern The pattern to replace. -@param callable|string $ replacement The match replacement. +@param (callable | string) $replacement The match replacement. @@ -3442,7 +4363,6 @@ Converts `string` to [snake case](https://en.wikipedia.org/wiki/Snake_case). - **Arguments:** @param string $string The string to convert. @@ -3457,6 +4377,7 @@ Example: ```php 'foo_bar' @@ -3465,6 +4386,7 @@ snakeCase('fooBar') snakeCase('--FOO-BAR--') // => 'foo_bar' + ``` ### split @@ -3473,9 +4395,12 @@ Splits `string` by `separator`. **Note:** This method is based on [`String#split`](https://mdn.io/String/split). + + + **Arguments:** -@param string $ string The string to split. +@param string $string The string to split. @param string $separator The separator pattern to split by. @@ -3503,6 +4428,7 @@ Converts `string` to + **Arguments:** @param string $string The string to convert. @@ -3534,6 +4460,7 @@ Checks if `string` starts with the given target string. + **Arguments:** @param string $string The string to inspect. @@ -3546,7 +4473,7 @@ Checks if `string` starts with the given target string. **Return:** -@return bool Returns `true` if `string` starts with `target`, else `false`. +@return boolean Returns `true` if `string` starts with `target`, else `false`. Example: ```php @@ -3572,16 +4499,18 @@ properties may be accessed as free variables in the template. If a setting object is given, it takes precedence over `$templateSettings` values. +RegExp $options['escape'] = _::$templateSettings['escape'] The HTML "escape" delimiter. +RegExp $options['evaluate'] = _::$templateSettings['evaluate'] The "evaluate" delimiter. +array $options['imports'] = _::$templateSettings['imports'] An object to import into the template as free variables. +RegExp $options['interpolate'] = _::$templateSettings['interpolate'] The "interpolate" delimiter. + + **Arguments:** @param string $string The template string. @param array $options The options array. -RegExp $options['escape'] = _::$templateSettings['escape'] The HTML "escape" delimiter. -RegExp $options['evaluate'] = _::$templateSettings['evaluate'] The "evaluate" delimiter. -array $options['imports'] = _::$templateSettings['imports'] An object to import into the template as free variables. -RegExp $options['interpolate'] = _::$templateSettings['interpolate'] The "interpolate" delimiter. @@ -3641,6 +4570,7 @@ Converts `string`, as a whole, to lower case + **Arguments:** @param string $string The string to convert. @@ -3672,6 +4602,7 @@ Converts `string`, as a whole, to upper case + **Arguments:** @param string $string The string to convert. @@ -3695,6 +4626,7 @@ toUpper('fooBar') toUpper('__foo_bar__') // => '__FOO_BAR__' + ``` ### trim @@ -3702,6 +4634,7 @@ Removes leading and trailing whitespace or specified characters from `string`. + **Arguments:** @param string $string The string to trim. @@ -3732,6 +4665,7 @@ Removes trailing whitespace or specified characters from `string`. + **Arguments:** @param string $string The string to trim. @@ -3748,11 +4682,13 @@ Example: ```php ' abc' trimEnd('-_-abc-_-', '_-') // => '-_-abc' + ``` ### trimStart @@ -3760,6 +4696,7 @@ Removes leading whitespace or specified characters from `string`. + **Arguments:** @param string $string The string to trim. @@ -3787,18 +4724,21 @@ trimStart('-_-abc-_-', '_-') ### truncate Truncates `string` if it's longer than the given maximum string length. - The last characters of the truncated string are replaced with the omission string which defaults to "...". + +length = 30 The maximum string length. +omission = '...' The string to indicate text is omitted. +separator The separator pattern to truncate to. + + + **Arguments:** @param string $string The string to truncate. @param array $options The options object. -length = 30 The maximum string length. -omission = '...' The string to indicate text is omitted. -separator The separator pattern to truncate to. @@ -3815,19 +4755,19 @@ truncate('hi-diddly-ho there, neighborino') // => 'hi-diddly-ho there, neighbo...' truncate('hi-diddly-ho there, neighborino', [ - 'length' => 24, - 'separator' => ' ' +'length' => 24, +'separator' => ' ' ]) // => 'hi-diddly-ho there,...' truncate('hi-diddly-ho there, neighborino', [ - 'length' => 24, - 'separator' => '/,? +/' +'length' => 24, +'separator' => '/,? +/' ]) // => 'hi-diddly-ho there...' truncate('hi-diddly-ho there, neighborino', [ - 'omission' => ' [...]' +'omission' => ' [...]' ]) // => 'hi-diddly-ho there, neig [...]' @@ -3840,6 +4780,7 @@ their corresponding characters. + **Arguments:** @param string $string The string to unescape. @@ -3864,7 +4805,6 @@ unescape('fred, barney, & pebbles') Converts `string`, as space separated words, to upper case. - **Arguments:** @param string $string The string to convert. @@ -3896,6 +4836,7 @@ Converts the first character of `string` to upper case. + **Arguments:** @param string $string The string to convert. @@ -3924,6 +4865,8 @@ Splits `string` into an array of its words. + + **Arguments:** @param string $string The string to inspect. @@ -3957,17 +4900,19 @@ object. Any additional arguments are provided to `func` when it's invoked. + +s **Arguments:** @param callable $func The function to attempt. -@param array $args The arguments to invoke `func` with. +@param arraygetBasename(), ['bootstrap.php', 'lodash.php', 'compiled.php', 'Lodash.php'], true)) {
+ continue;
+ }
+
+ $code .= getCode($file);
+}
+
+file_put_contents(dirname(__DIR__).'/src/compiled.php', $code);
+
diff --git a/bin/build b/bin/generate-readme
similarity index 60%
rename from bin/build
rename to bin/generate-readme
index d2aea5f..a3d3419 100755
--- a/bin/build
+++ b/bin/generate-readme
@@ -1,11 +1,18 @@
#!/usr/bin/env php
create($reflection->getDocComment());
+ $docblock = $parser->parse(new TokenIterator((new Lexer())->tokenize($reflection->getDocComment())));
- $category = (string) $docblock->getTagsByName('category')[0];
+ $category = (string) current($docblock->getTagsByName('@category'))->value;
$readme[$category][$function] = '';
$readme[$category][$function] .= "### $function\n\n";
- $readme[$category][$function] .= $docblock->getSummary().PHP_EOL.PHP_EOL;
- $readme[$category][$function] .= $docblock->getDescription().PHP_EOL.PHP_EOL;
+
+ foreach (array_filter($docblock->children, function (PhpDocChildNode $child): bool {
+ return $child instanceof PhpDocTextNode;
+ }) as $text) {
+ $readme[$category][$function] .= (string) $text.PHP_EOL;
+ }
$readme[$category][$function] .= "**Arguments:**\n\n";
- foreach ($docblock->getTagsByName('param') as $param) {
- $readme[$category][$function] .= $param->render().PHP_EOL.PHP_EOL;
+ foreach ($docblock->getTagsByName('@param') as $param) {
+ $readme[$category][$function] .= (string) $param.PHP_EOL.PHP_EOL;
}
$readme[$category][$function] .= PHP_EOL.PHP_EOL;
$readme[$category][$function] .= "**Return:**\n\n";
- $readme[$category][$function] .= $docblock->getTagsByName('return')[0]->render();
+ $readme[$category][$function] .= (string) current($docblock->getTagsByName('@return'));
$readme[$category][$function] .= PHP_EOL.PHP_EOL;
- if ($docblock->hasTag('example')) {
+ if (\preg_match('#((.|\n)*?)
#', $readme[$category][$function], $matches)) {
+
+ $readme[$category][$function] = str_replace($matches[0], '', $readme[$category][$function]);
- $example = str_replace(['', '
'], '', $docblock->getTagsByName('example')[0] ?? '');
+ $example = $matches[1];
- if ($example) {
- $readme[$category][$function] .= "Example:\n```php\n\\=\" between int\\<0, max\\> and 0 is always true\\.$#"
+ count: 1
+ path: src/String/startsWith.php
+
+ -
+ message: "#^Offset mixed on \\*NEVER\\* in isset\\(\\) always exists and is not nullable\\.$#"
+ count: 1
+ path: src/internal/baseIntersection.php
+
+ -
+ message: "#^Unreachable statement \\- code above always terminates\\.$#"
+ count: 1
+ path: src/internal/isIterateeCall.php
+
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000..08970a1
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,15 @@
+includes:
+ - phpstan-baseline.neon
+
+parameters:
+ paths:
+ - src
+ bootstrapFiles:
+ - src/bootstrap.php
+ level: 5
+ excludePaths:
+ - src/compiled.php
+ - src/Lodash.php
+ - src/internal/memoizeCapped.php # Exclude internal function due to dynamic class usage
+ ignoreErrors:
+ - "#^PHPDoc tag \\@param references unknown parameter\\: \\$[a-zA-Z]+$#"
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 3c500fe..192a663 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,8 +1,7 @@
diff --git a/src/Array/concat.php b/src/Array/concat.php
index fe84ff0..945f2f8 100644
--- a/src/Array/concat.php
+++ b/src/Array/concat.php
@@ -17,8 +17,9 @@
*
* @category Array
*
- * @param array $array The array to concatenate.
- * @param mixed $values The values to concatenate.
+ * @param array $array The array to concatenate.
+ * @param array $values The values to concatenate.
+ *
* @return array Returns the new concatenated array.
*
* @example
@@ -26,10 +27,10 @@
* $array = [1];
* $other = concat($array, 2, [3], [[4]]);
*
- * var_dump(other)
+ * var_dump($other)
* // => [1, 2, 3, [4]]
*
- * var_dump(array)
+ * var_dump($array)
* // => [1]
*
*/
diff --git a/src/Array/difference.php b/src/Array/difference.php
index 9bdba36..22c779c 100644
--- a/src/Array/difference.php
+++ b/src/Array/difference.php
@@ -21,8 +21,8 @@
*
* @category Array
*
- * @param array $array The array to inspect.
- * @param mixed[] $values The values to exclude.
+ * @param array $array The array to inspect.
+ * @param array ...$values The values to exclude.
*
* @return array Returns the new array of filtered values.
*
diff --git a/src/Array/differenceBy.php b/src/Array/differenceBy.php
index 89a7492..8c5a7ca 100644
--- a/src/Array/differenceBy.php
+++ b/src/Array/differenceBy.php
@@ -24,16 +24,17 @@
*
* @category Array
*
- * @param array $array The array to inspect.
- * @param array $values The values to exclude.
- * @param callable iteratee The iteratee invoked per element.
+ * @param array $array The array to inspect.
+ * @param array
* differenceBy([2.1, 1.2], [2.3, 3.4], 'floor')
* // => [1.2]
+ *
*/
function differenceBy(array $array, ...$values): array
{
@@ -45,6 +46,7 @@ function differenceBy(array $array, ...$values): array
return difference($array, ...$values);
}
+ /** @var callable $iteratee */
$iteratee = \array_pop($values);
$values = \array_map($iteratee, baseFlatten($values, 1, 'is_array', true, null));
diff --git a/src/Array/differenceWith.php b/src/Array/differenceWith.php
index e77725e..912e117 100644
--- a/src/Array/differenceWith.php
+++ b/src/Array/differenceWith.php
@@ -23,11 +23,14 @@
*
* @category Array
*
- * @param array $array The array to inspect.
- * @param array[] $values The values to exclude.
+ * @param array
* $objects = [[ 'x' => 1, 'y' => 2 ], [ 'x' => 2, 'y' => 1 ]]
@@ -46,6 +49,7 @@ function differenceWith(array $array, ...$values): array
return difference($array, ...$values);
}
+ /** @var callable $comparator */
$comparator = \array_pop($values);
$values = baseFlatten($values, 1, 'is_array', true, null);
diff --git a/src/Array/dropWhile.php b/src/Array/dropWhile.php
index ce62b5f..36020df 100644
--- a/src/Array/dropWhile.php
+++ b/src/Array/dropWhile.php
@@ -40,11 +40,13 @@ function dropWhile(array $array, callable $predicate): array
$count = \count($array);
$length = 0;
$index = \key($array);
- while ($length <= $count && $predicate($array[$index], $index, $array)) {
+ $value = \current($array);
+ while ($length <= $count && $predicate($value, $index, $array)) {
array_shift($array);
\reset($array);
$length++;
$index = \key($array);
+ $value = \current($array);
}
return $array;
diff --git a/src/Array/flatten.php b/src/Array/flatten.php
index 7c4a002..be6371b 100644
--- a/src/Array/flatten.php
+++ b/src/Array/flatten.php
@@ -22,9 +22,10 @@
*
* @return array the new flattened array.
* @example
- *
+ *
* flatten([1, [2, [3, [4]], 5]])
* // => [1, 2, [3, [4]], 5]
+ *
*/
function flatten(array $array = null): array
{
diff --git a/src/Array/flattenDeep.php b/src/Array/flattenDeep.php
index 45e96a6..61a9933 100644
--- a/src/Array/flattenDeep.php
+++ b/src/Array/flattenDeep.php
@@ -29,5 +29,5 @@
*/
function flattenDeep(array $array): array
{
- return baseFlatten($array, INF);
+ return baseFlatten($array, PHP_INT_MAX);
}
diff --git a/src/Array/fromPairs.php b/src/Array/fromPairs.php
index d9dcfbb..7541e04 100644
--- a/src/Array/fromPairs.php
+++ b/src/Array/fromPairs.php
@@ -19,7 +19,8 @@
*
* @param array $pairs The key-value pairs.
*
- * @return object the new object.
+ * @return \stdClass the new object.
+ *
* @example
*
* fromPairs([['a', 1], ['b', 2]])
diff --git a/src/Array/initial.php b/src/Array/initial.php
index 5f25bab..8368454 100644
--- a/src/Array/initial.php
+++ b/src/Array/initial.php
@@ -20,9 +20,10 @@
*
* @return array the slice of `array`.
* @example
- *
+ *
* initial([1, 2, 3])
* // => [1, 2]
+ *
*/
function initial(array $array): array
{
diff --git a/src/Array/intersection.php b/src/Array/intersection.php
index d0b7186..6d05520 100644
--- a/src/Array/intersection.php
+++ b/src/Array/intersection.php
@@ -19,13 +19,15 @@
*
* @category Array
*
- * @param array[] $arrays
+ * @param array ...$arrays
*
* @return array the new array of intersecting values.
- * @example
*
+ * @example
+ *
* intersection([2, 1], [2, 3])
* // => [2]
+ *
*/
function intersection(array ...$arrays): array
{
diff --git a/src/Array/intersectionBy.php b/src/Array/intersectionBy.php
index 066a2a3..44ca1c5 100644
--- a/src/Array/intersectionBy.php
+++ b/src/Array/intersectionBy.php
@@ -23,7 +23,7 @@
*
* @category Array
*
- * @param array[] $arrays
+ * @param array ...$arrays
* @param callable $iteratee The iteratee invoked per element.
*
* @return array the new array of intersecting values.
diff --git a/src/Array/intersectionWith.php b/src/Array/intersectionWith.php
index 330413a..be8dbd4 100644
--- a/src/Array/intersectionWith.php
+++ b/src/Array/intersectionWith.php
@@ -21,10 +21,11 @@
*
* @category Array
*
- * @param array[] $arrays
+ * @param array ...$arrays
* @param callable $comparator The comparator invoked per element.
*
* @return array the new array of intersecting values.
+ *
* @example
*
* $objects = [[ 'x' => 1, 'y' => 2 ], [ 'x' => 2, 'y' => 1 ]]
@@ -37,7 +38,7 @@
function intersectionWith(...$arrays /*, callable $comparator = null*/): array
{
$copy = $arrays;
- $comparator = array_pop($arrays);
+ $comparator = \array_pop($arrays);
if (!\is_callable($comparator)) {
$arrays = $copy;
diff --git a/src/Array/nth.php b/src/Array/nth.php
index 32d142c..4b037fa 100644
--- a/src/Array/nth.php
+++ b/src/Array/nth.php
@@ -22,7 +22,7 @@
*
* @return mixed Returns the nth element of `array`.
* @example
- *
+ *
* $array = ['a', 'b', 'c', 'd']
*
* nth($array, 1)
@@ -30,6 +30,7 @@
*
* nth($array, -2)
* // => 'c'
+ *
*/
function nth(array $array, int $n)
{
diff --git a/src/Array/pull.php b/src/Array/pull.php
index 8ad6e98..f585be2 100644
--- a/src/Array/pull.php
+++ b/src/Array/pull.php
@@ -21,10 +21,11 @@
*
* @category Array
*
- * @param array $array The array to modify.
- * @param mixed[] $values The values to remove.
+ * @param array $array The array to modify.
+ * @param array $values The values to remove.
*
* @return array
+ *
* @example
*
* $array = ['a', 'b', 'c', 'a', 'b', 'c']
diff --git a/src/Array/pullAllBy.php b/src/Array/pullAllBy.php
index b1e458f..5e50a76 100644
--- a/src/Array/pullAllBy.php
+++ b/src/Array/pullAllBy.php
@@ -29,12 +29,13 @@
*
* @return array `array`.
* @example
- *
+ *
* $array = [[ 'x' => 1 ], [ 'x' => 2 ], [ 'x' => 3 ], [ 'x' => 1 ]]
*
* pullAllBy($array, [[ 'x' => 1 ], [ 'x' => 3 ]], 'x')
* var_dump($array)
* // => [[ 'x' => 2 ]]
+ *
*/
function pullAllBy(array &$array, array $values, $iteratee): array
{
diff --git a/src/Array/remove.php b/src/Array/remove.php
index 70ff6cc..a939bf5 100644
--- a/src/Array/remove.php
+++ b/src/Array/remove.php
@@ -26,7 +26,7 @@
*
* @return array the new array of removed elements.
* @example
- *
+ *
* $array = [1, 2, 3, 4]
* $evens = remove($array, function ($n) { return $n % 2 === 0; })
*
@@ -35,6 +35,7 @@
*
* var_dump($evens)
* // => [2, 4]
+ *
*/
function remove(array &$array, callable $predicate): array
{
diff --git a/src/Array/union.php b/src/Array/union.php
index d8aebcb..e02f4f7 100644
--- a/src/Array/union.php
+++ b/src/Array/union.php
@@ -18,7 +18,7 @@
*
* @category Array
*
- * @param array[] $arrays The arrays to inspect.
+ * @param array ...$arrays The arrays to inspect.
*
* @return array the new array of combined values.
*
diff --git a/src/Array/unionBy.php b/src/Array/unionBy.php
index a8f0dc6..af400c6 100644
--- a/src/Array/unionBy.php
+++ b/src/Array/unionBy.php
@@ -24,8 +24,8 @@
*
* @category Array
*
- * @param array[] $arrays The arrays to inspect.
- * @param callable $iteratee The iteratee invoked per element.
+ * @param array ...$arrays The arrays to inspect.
+ * @param callable $iteratee The iteratee invoked per element.
*
* @return array the new array of combined values.
*
diff --git a/src/Array/unionWith.php b/src/Array/unionWith.php
index 5ac71d9..56b2071 100644
--- a/src/Array/unionWith.php
+++ b/src/Array/unionWith.php
@@ -22,19 +22,30 @@
*
* @category Array
*
- * @param array[] $arrays The arrays to inspect.
+ * @param array ...$arrays The arrays to inspect.
* @param callable $comparator The comparator invoked per element.
*
* @return array the new array of combined values.
- * @example
*
+ * @throws \InvalidArgumentException
+ *
+ * @example
+ *
* $objects = [['x' => 1, 'y' => 2], ['x' => 2, 'y' => 1]]
* $others = [['x' => 1, 'y' => 1], ['x' => 1, 'y' => 2]]
*
* unionWith($objects, $others, '_::isEqual')
* // => [['x' => 1, 'y' => 2], ['x' => 2, 'y' => 1], ['x' => 1, 'y' => 1]]
+ *
*/
function unionWith(... $arrays): array
{
- return baseUniq(baseFlatten($arrays, 1, '\is_array', true), null, \array_pop($arrays));
+ /** @var callable $comparator */
+ $comparator = \array_pop($arrays);
+
+ if (!\is_callable($comparator)) {
+ throw new \InvalidArgumentException(__FUNCTION__.' expects the last value passed to be callable');
+ }
+
+ return baseUniq(baseFlatten($arrays, 1, '\is_array', true), null, $comparator);
}
diff --git a/src/Array/uniq.php b/src/Array/uniq.php
index ffe09f0..4aa7515 100644
--- a/src/Array/uniq.php
+++ b/src/Array/uniq.php
@@ -29,7 +29,7 @@
* // => [2, 1]s
*
*/
-function uniq(array $array = null): array
+function uniq(array $array = []): array
{
return \array_unique($array);
}
diff --git a/src/Array/unzipWith.php b/src/Array/unzipWith.php
index fc9a5ca..17365f8 100644
--- a/src/Array/unzipWith.php
+++ b/src/Array/unzipWith.php
@@ -20,10 +20,11 @@
*
* @category Array
*
- * @param array $array The array of grouped elements to process.
- * @param callable $iteratee The function to combine regrouped values.
+ * @param array $array The array of grouped elements to process.
+ * @param callable|null $iteratee The function to combine regrouped values.
*
* @return array the new array of regrouped elements.
+ *
* @example
*
* $zipped = zip([1, 2], [10, 20], [100, 200])
@@ -33,14 +34,14 @@
* // => [3, 30, 300]
*
*/
-function unzipWith(array $array, callable $iteratee): array
+function unzipWith(array $array, ?callable $iteratee = null): array
{
if (!\count($array)) {
return [];
}
$result = unzip($array);
- if (null === $iteratee) {
+ if (!is_callable($iteratee)) {
return $result;
}
diff --git a/src/Array/without.php b/src/Array/without.php
index ed367ff..7976e97 100644
--- a/src/Array/without.php
+++ b/src/Array/without.php
@@ -22,8 +22,8 @@
*
* @category Array
*
- * @param array $array The array to inspect.
- * @param mixed[] $values The values to exclude.
+ * @param array $array The array to inspect.
+ * @param array $values The values to exclude.
*
* @return array the new array of filtered values.
* @example
@@ -34,5 +34,5 @@
*/
function without(array $array, ...$values): array
{
- return baseRest('\_\difference')($array, $values);
+ return baseRest('\_\difference')($array, ...$values);
}
diff --git a/src/Array/zip.php b/src/Array/zip.php
index c163319..24c8cbd 100644
--- a/src/Array/zip.php
+++ b/src/Array/zip.php
@@ -20,7 +20,7 @@
*
* @category Array
*
- * @param array[] $arrays The arrays to process.
+ * @param array ...$arrays The arrays to process.
*
* @return array the new array of grouped elements.
* @example
@@ -31,5 +31,5 @@
*/
function zip(array ...$arrays): array
{
- return baseRest('\_\unzip')($arrays);
+ return baseRest('\_\unzip')(...$arrays);
}
diff --git a/src/Array/zipObjectDeep.php b/src/Array/zipObjectDeep.php
index 88a6ea9..dd8defc 100644
--- a/src/Array/zipObjectDeep.php
+++ b/src/Array/zipObjectDeep.php
@@ -21,7 +21,8 @@
* @param array $props The property identifiers.
* @param array $values The property values.
*
- * @return object the new object.
+ * @return \stdClass the new object.
+ *
* @example
*
* zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2])
@@ -41,7 +42,7 @@
* *\/
*
*/
-function zipObjectDeep(array $props = [], array $values = []): object
+function zipObjectDeep(array $props = [], array $values = []): \stdClass
{
$result = new \stdClass;
$index = -1;
diff --git a/src/Array/zipWith.php b/src/Array/zipWith.php
index b30bf7f..58727f0 100644
--- a/src/Array/zipWith.php
+++ b/src/Array/zipWith.php
@@ -18,10 +18,11 @@
*
* @category Array
*
- * @param array[] $arrays The arrays to process.
+ * @param array ...$arrays The arrays to process.
* @param callable $iteratee The function to combine grouped values.
*
* @return array the new array of grouped elements.
+ *
* @example
*
* zipWith([1, 2], [10, 20], [100, 200], function($a, $b, $c) { return $a + $b + $c; })
@@ -30,6 +31,7 @@
*/
function zipWith(...$arrays): array
{
+ /** @var callable|null $iteratee */
$iteratee = \is_callable(\end($arrays)) ? \array_pop($arrays) : null;
return unzipWith($arrays, $iteratee);
diff --git a/src/Collection/countBy.php b/src/Collection/countBy.php
index 9890829..ae2dd51 100644
--- a/src/Collection/countBy.php
+++ b/src/Collection/countBy.php
@@ -46,4 +46,4 @@ function countBy(iterable $collection, callable $iteratee): array
return $result;
})($collection, $iteratee);
-}
\ No newline at end of file
+}
diff --git a/src/Collection/each.php b/src/Collection/each.php
index 9ef3ad5..a78a041 100644
--- a/src/Collection/each.php
+++ b/src/Collection/each.php
@@ -22,11 +22,11 @@
*
* @category Collection
*
- * @param array|object $collection The collection to iterate over.
- * @param callable $iteratee The function invoked per iteration.
+ * @param array|iterable|object $collection The collection to iterate over.
+ * @param callable $iteratee The function invoked per iteration.
*
* @return array|object Returns `collection`.
- * @related forEachRight, forIn, forInRight, forOwn, forOwnRight
+ *
* @example
*
* each([1, 2], function ($value) { echo $value; })
@@ -38,12 +38,9 @@
*/
function each($collection, callable $iteratee)
{
- $values = $collection;
-
- if (\is_object($collection)) {
- $values = \get_object_vars($collection);
- }
+ $values = \is_object($collection) ? \get_object_vars($collection) : $collection;
+ /** @var array $values */
foreach ($values as $index => $value) {
if (false === $iteratee($value, $index, $collection)) {
break;
diff --git a/src/Collection/eachRight.php b/src/Collection/eachRight.php
index b2d0d19..94d3130 100644
--- a/src/Collection/eachRight.php
+++ b/src/Collection/eachRight.php
@@ -17,8 +17,8 @@
*
* @category Collection
*
- * @param array|object $collection The collection to iterate over.
- * @param callable $iteratee The function invoked per iteration.
+ * @param array|iterable|object $collection The collection to iterate over.
+ * @param callable $iteratee The function invoked per iteration.
*
* @return array|object Returns `collection`.
* @example
@@ -29,11 +29,7 @@
*/
function eachRight($collection, callable $iteratee)
{
- $values = $collection;
-
- if (\is_object($collection)) {
- $values = \get_object_vars($collection);
- }
+ $values = \is_object($collection) ? \get_object_vars($collection) : $collection;
foreach (\array_reverse($values, true) as $index => $value) {
if (false === $iteratee($value, $index, $collection)) {
@@ -42,4 +38,4 @@ function eachRight($collection, callable $iteratee)
}
return $collection;
-}
\ No newline at end of file
+}
diff --git a/src/Collection/every.php b/src/Collection/every.php
index a2d261a..6ee989a 100644
--- a/src/Collection/every.php
+++ b/src/Collection/every.php
@@ -64,4 +64,4 @@ function every(iterable $collection, $predicate): bool
}
return true;
-}
\ No newline at end of file
+}
diff --git a/src/Collection/filter.php b/src/Collection/filter.php
index bfd013b..3c3b9bf 100644
--- a/src/Collection/filter.php
+++ b/src/Collection/filter.php
@@ -26,6 +26,7 @@
* @param callable $predicate The function invoked per iteration.
*
* @return array the new filtered array.
+ *
* @example
*
* $users = [
@@ -54,14 +55,12 @@ function filter(iterable $array, $predicate = null): array
$iteratee = baseIteratee($predicate);
$result = \array_filter(
- $array,
+ \is_array($array) ? $array : \iterator_to_array($array),
function ($value, $key) use ($array, $iteratee) {
return $iteratee($value, $key, $array);
},
\ARRAY_FILTER_USE_BOTH
);
- \sort($result);
-
- return $result;
-}
\ No newline at end of file
+ return \array_values($result);
+}
diff --git a/src/Collection/find.php b/src/Collection/find.php
index b1be2a8..e38807f 100644
--- a/src/Collection/find.php
+++ b/src/Collection/find.php
@@ -54,11 +54,11 @@ function find(iterable $collection, $predicate = null, int $fromIndex = 0)
{
$iteratee = baseIteratee($predicate);
- foreach (\array_slice($collection, $fromIndex) as $key => $value) {
+ foreach (\array_slice(\is_array($collection) ? $collection : \iterator_to_array($collection), $fromIndex) as $key => $value) {
if ($iteratee($value, $key, $collection)) {
return $value;
}
}
return null;
-}
\ No newline at end of file
+}
diff --git a/src/Collection/findLast.php b/src/Collection/findLast.php
index 60e5ab6..2e7cb05 100644
--- a/src/Collection/findLast.php
+++ b/src/Collection/findLast.php
@@ -18,25 +18,28 @@
* `collection` from right to left.
*
* @category Collection
+ *
* @param iterable $collection The collection to inspect.
- * @param callable $predicate The function invoked per iteration.
- * @param int $fromIndex The index to search from.
+ * @param callable $predicate The function invoked per iteration.
+ * @param int $fromIndex The index to search from.
+ *
* @return mixed Returns the matched element, else `undefined`.
+ *
* @example
*
* findLast([1, 2, 3, 4], function ($n) { return $n % 2 == 1; })
* // => 3
- *
+ *
*/
function findLast(iterable $collection, $predicate = null, int $fromIndex = 0)
{
$iteratee = baseIteratee($predicate);
- foreach (\array_slice(\array_reverse($collection, true), $fromIndex) as $key => $value) {
+ foreach (\array_slice(\array_reverse(\is_array($collection) ? $collection : \iterator_to_array($collection), true), $fromIndex) as $key => $value) {
if ($iteratee($value, $key, $collection)) {
return $value;
}
}
return null;
-}
\ No newline at end of file
+}
diff --git a/src/Collection/flatMap.php b/src/Collection/flatMap.php
index 2fe47f0..889cead 100644
--- a/src/Collection/flatMap.php
+++ b/src/Collection/flatMap.php
@@ -20,10 +20,11 @@
*
* @category Collection
*
- * @param iterable collection The collection to iterate over.
+ * @param iterable $collection The collection to iterate over.
* @param callable $iteratee The function invoked per iteration.
*
* @return array the new flattened array.
+ *
* @example
*
* function duplicate($n) {
@@ -34,7 +35,7 @@
* // => [1, 1, 2, 2]
*
*/
-function flatMap(iterable $collection, callable $iteratee = null): array
+function flatMap(iterable $collection, callable $iteratee): array
{
return baseFlatten(map($collection, $iteratee), 1);
-}
\ No newline at end of file
+}
diff --git a/src/Collection/flatMapDeep.php b/src/Collection/flatMapDeep.php
index 5b1a34c..5c09dd7 100644
--- a/src/Collection/flatMapDeep.php
+++ b/src/Collection/flatMapDeep.php
@@ -19,7 +19,7 @@
*
* @category Collection
*
- * @param iterable collection The collection to iterate over.
+ * @param iterable $collection The collection to iterate over.
* @param callable $iteratee The function invoked per iteration.
*
* @return array Returns the new flattened array.
@@ -33,7 +33,7 @@
* // => [1, 1, 2, 2]
*
*/
-function flatMapDeep(iterable $collection, callable $iteratee = null): array
+function flatMapDeep(iterable $collection, callable $iteratee): array
{
return baseFlatten(map($collection, $iteratee), \PHP_INT_MAX);
-}
\ No newline at end of file
+}
diff --git a/src/Collection/flatMapDepth.php b/src/Collection/flatMapDepth.php
index 835ac24..4bdd5ad 100644
--- a/src/Collection/flatMapDepth.php
+++ b/src/Collection/flatMapDepth.php
@@ -19,7 +19,7 @@
*
* @category Collection
*
- * @param iterable collection The collection to iterate over.
+ * @param iterable $collection The collection to iterate over.
* @param callable $iteratee The function invoked per iteration.
* @param int $depth The maximum recursion depth.
*
@@ -34,7 +34,7 @@
* // => [[1, 1], [2, 2]]
*
*/
-function flatMapDepth(iterable $collection, callable $iteratee = null, int $depth = 1): array
+function flatMapDepth(iterable $collection, callable $iteratee, int $depth = 1): array
{
return baseFlatten(map($collection, $iteratee), $depth);
-}
\ No newline at end of file
+}
diff --git a/src/Collection/groupBy.php b/src/Collection/groupBy.php
index 2a9602e..2295d56 100644
--- a/src/Collection/groupBy.php
+++ b/src/Collection/groupBy.php
@@ -22,7 +22,7 @@
*
* @category Collection
*
- * @param iterable collection The collection to iterate over.
+ * @param iterable $collection The collection to iterate over.
* @param callable $iteratee The iteratee to transform keys.
*
* @return array Returns the composed aggregate object.
@@ -46,4 +46,4 @@ function groupBy(iterable $collection, $iteratee): array
return $result;
})($collection, $iteratee);
-}
\ No newline at end of file
+}
diff --git a/src/Collection/invokeMap.php b/src/Collection/invokeMap.php
index 148b117..b5b4ddd 100644
--- a/src/Collection/invokeMap.php
+++ b/src/Collection/invokeMap.php
@@ -47,5 +47,5 @@ function invokeMap(iterable $collection, $path, array $args = []): array
});
return $result;
- })($collection, $path, $args);
-}
\ No newline at end of file
+ })($collection, $path, ...$args);
+}
diff --git a/src/Collection/keyBy.php b/src/Collection/keyBy.php
index db94603..229206b 100644
--- a/src/Collection/keyBy.php
+++ b/src/Collection/keyBy.php
@@ -46,4 +46,4 @@ function keyBy(iterable $collection, $iteratee): array
return $result;
})($collection, $iteratee);
-}
\ No newline at end of file
+}
diff --git a/src/Collection/orderBy.php b/src/Collection/orderBy.php
index 548ccb3..346fb75 100644
--- a/src/Collection/orderBy.php
+++ b/src/Collection/orderBy.php
@@ -21,7 +21,7 @@
*
* @category Collection
*
- * @param iterable $collection The collection to iterate over.
+ * @param iterable|null $collection The collection to iterate over.
* @param array[]|callable[]|string[] $iteratee The iteratee(s) to sort by.
* @param string[] $orders The sort orders of `iteratees`.
*
@@ -40,11 +40,11 @@
* // => [['user' => 'barney', 'age' => 36], ['user' => 'barney', 'age' => 34], ['user' => 'fred', 'age' => 48], ['user' => 'fred', 'age' => 40]]
*
*/
-function orderBy(?iterable $collection, $iteratee, $orders): array
+function orderBy(?iterable $collection, array $iteratee, array $orders): array
{
if (null === $collection) {
return [];
}
- return baseOrderBy($collection, (array) $iteratee, (array) $orders);
-}
\ No newline at end of file
+ return baseOrderBy($collection, $iteratee, $orders);
+}
diff --git a/src/Collection/partition.php b/src/Collection/partition.php
index 7c5764d..ac4eae5 100644
--- a/src/Collection/partition.php
+++ b/src/Collection/partition.php
@@ -26,7 +26,7 @@
*
* @return array the array of grouped elements.
* @example
- *
+ *
* $users = [
* ['user' => 'barney', 'age' => 36, 'active' => false],
* ['user' => 'fred', 'age' => 40, 'active' => true],
@@ -35,6 +35,7 @@
*
* partition($users, function($user) { return $user['active']; })
* // => objects for [['fred'], ['barney', 'pebbles']]
+ *
*/
function partition(iterable $collection, $predicate = null): array
{
@@ -42,5 +43,7 @@ function partition(iterable $collection, $predicate = null): array
$result[$key ? 0 : 1][] = $value;
return $result;
- }, function () { return [[], []]; })($collection, $predicate);
-}
\ No newline at end of file
+ }, function () {
+ return [[], []];
+ })($collection, $predicate);
+}
diff --git a/src/Collection/reduce.php b/src/Collection/reduce.php
index 9b7b179..703be86 100644
--- a/src/Collection/reduce.php
+++ b/src/Collection/reduce.php
@@ -55,10 +55,10 @@
function reduce(iterable $collection, $iteratee, $accumulator = null)
{
$func = function (iterable $array, $iteratee, $accumulator, $initAccum = null) {
- $length = count($array);
+ $length = \count(\is_array($array) ? $array : \iterator_to_array($array));
if ($initAccum && $length) {
- $accumulator = current($array);
+ $accumulator = \current($array);
}
foreach ($array as $key => $value) {
$accumulator = $iteratee($accumulator, $value, $key, $array);
@@ -68,4 +68,4 @@ function reduce(iterable $collection, $iteratee, $accumulator = null)
};
return $func($collection, baseIteratee($iteratee), $accumulator, null === $accumulator);
-}
\ No newline at end of file
+}
diff --git a/src/Collection/reduceRight.php b/src/Collection/reduceRight.php
index 14a9991..8a51c16 100644
--- a/src/Collection/reduceRight.php
+++ b/src/Collection/reduceRight.php
@@ -32,8 +32,9 @@
*
* reduceRight(array, (flattened, other) => flattened.concat(other), [])
* // => [4, 5, 2, 3, 0, 1]
+ *
*/
function reduceRight(iterable $collection, $iteratee, $accumulator = null)
{
return baseReduce(\array_reverse($collection instanceof \Traversable ? \iterator_to_array($collection, true) : $collection, true), baseIteratee($iteratee), $accumulator, null === $accumulator);
-}
\ No newline at end of file
+}
diff --git a/src/Collection/reject.php b/src/Collection/reject.php
index eb70956..1a63722 100644
--- a/src/Collection/reject.php
+++ b/src/Collection/reject.php
@@ -38,4 +38,4 @@
function reject(iterable $collection, $predicate = null): array
{
return filter($collection, negate(baseIteratee($predicate)));
-}
\ No newline at end of file
+}
diff --git a/src/Collection/sample.php b/src/Collection/sample.php
index dc062fd..43dec1f 100644
--- a/src/Collection/sample.php
+++ b/src/Collection/sample.php
@@ -19,6 +19,7 @@
* @param array $array The array to sample.
*
* @return mixed Returns the random element.
+ *
* @example
*
* sample([1, 2, 3, 4])
@@ -27,5 +28,8 @@
*/
function sample(array $array)
{
- return $array[\array_rand($array, 1)];
-}
\ No newline at end of file
+ /** @var string|int $key */
+ $key = \array_rand($array, 1);
+
+ return $array[$key];
+}
diff --git a/src/Collection/sampleSize.php b/src/Collection/sampleSize.php
index 521b7a1..199842a 100644
--- a/src/Collection/sampleSize.php
+++ b/src/Collection/sampleSize.php
@@ -22,12 +22,13 @@
*
* @return array the random elements.
* @example
- *
+ *
* sampleSize([1, 2, 3], 2)
* // => [3, 1]
*
* sampleSize([1, 2, 3], 4)
* // => [2, 3, 1]
+ *
*/
function sampleSize(array $array, int $n = 1): array
{
@@ -39,4 +40,4 @@ function sampleSize(array $array, int $n = 1): array
}
return $result;
-}
\ No newline at end of file
+}
diff --git a/src/Collection/shuffle.php b/src/Collection/shuffle.php
index b731701..5dc4242 100644
--- a/src/Collection/shuffle.php
+++ b/src/Collection/shuffle.php
@@ -20,13 +20,14 @@
*
* @return array the new shuffled array.
* @example
- *
+ *
* shuffle([1, 2, 3, 4])
* // => [4, 1, 3, 2]
+ *
*/
function shuffle(array $array = []): array
{
\shuffle($array);
return $array;
-}
\ No newline at end of file
+}
diff --git a/src/Collection/size.php b/src/Collection/size.php
index 0fc29e3..5116e9e 100644
--- a/src/Collection/size.php
+++ b/src/Collection/size.php
@@ -21,7 +21,7 @@
*
* @return int Returns the collection size.
* @example
- *
+ *
* size([1, 2, 3]);
* // => 3
*
@@ -30,6 +30,7 @@
*
* size('pebbles');
* // => 7
+ *
*/
function size($collection): int
{
@@ -50,4 +51,4 @@ function size($collection): int
}
return 0;
-}
\ No newline at end of file
+}
diff --git a/src/Collection/some.php b/src/Collection/some.php
index 4e69e79..02d8b9d 100644
--- a/src/Collection/some.php
+++ b/src/Collection/some.php
@@ -58,4 +58,4 @@ function some(iterable $collection, $predicate = null): bool
}
return false;
-}
\ No newline at end of file
+}
diff --git a/src/Collection/sortBy.php b/src/Collection/sortBy.php
index 881bab4..0e2e41c 100644
--- a/src/Collection/sortBy.php
+++ b/src/Collection/sortBy.php
@@ -21,8 +21,8 @@
*
* @category Collection
*
- * @param array|object $collection The collection to iterate over.
- * @param callable|callable[] $iteratees The iteratees to sort by.
+ * @param array|object|null $collection The collection to iterate over.
+ * @param callable|callable[] $iteratees The iteratees to sort by.
*
* @return array Returns the new sorted array.
* @example
@@ -41,13 +41,13 @@
* // => [['user' => 'barney', 'age' => 34], ['user' => 'barney', 'age' => 36], ['user' => 'fred', 'age' => 40], ['user' => 'fred', 'age' => 48]]
*
*/
-function sortBy($collection, $iteratees)
+function sortBy($collection, $iteratees): array
{
if (null === $collection) {
return [];
};
- if (\is_callable($iteratees)) {
+ if (\is_callable($iteratees) || !\is_iterable($iteratees)) {
$iteratees = [$iteratees];
}
@@ -58,7 +58,7 @@ function sortBy($collection, $iteratees)
$iteratees = [$iteratees[0]];
}*/
- $result = $collection;
+ $result = \is_object($collection) ? \get_object_vars($collection) : $collection;
foreach ($iteratees as $callable) {
usort($result, function ($a, $b) use ($callable) {
diff --git a/src/Function/after.php b/src/Function/after.php
new file mode 100644
index 0000000..6a972c1
--- /dev/null
+++ b/src/Function/after.php
@@ -0,0 +1,46 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+/**
+ * The opposite of `before`; this method creates a function that invokes
+ * `func` once it's called `n` or more times.
+ *
+ * @category Function
+ *
+ * @param int $n The number of calls before `func` is invoked.
+ * @param Callable $func The function to restrict.
+ *
+ * @return Callable Returns the new restricted function.
+ *
+ * @example
+ *
+ * $saves = ['profile', 'settings'];
+ *
+ * $done = after(count($saves), function() {
+ * echo 'done saving!';
+ * });
+ *
+ * forEach($saves, function($type) use($done) {
+ * asyncSave([ 'type' => $type, 'complete' => $done ]);
+ * });
+ * // => Prints 'done saving!' after the two async saves have completed.
+ *
+ */
+function after(int $n, callable $func): callable
+{
+ return function (...$args) use (&$n, $func) {
+ if (--$n < 1) {
+ return $func(...$args);
+ }
+ };
+}
diff --git a/src/Function/ary.php b/src/Function/ary.php
new file mode 100644
index 0000000..47d5436
--- /dev/null
+++ b/src/Function/ary.php
@@ -0,0 +1,38 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+/**
+ * Creates a function that invokes `func`, with up to `n` arguments,
+ * ignoring any additional arguments.
+ *
+ * @category Function
+ *
+ * @param callable $func The function to cap arguments for.
+ * @param int $n The arity cap.
+ *
+ * @return Callable Returns the new capped function.
+ *
+ * @example
+ *
+ * map(['6', '8', '10'], ary('intval', 1));
+ * // => [6, 8, 10]
+ *
+ */
+function ary(callable $func, int $n): callable
+{
+ return function (...$args) use ($func, $n) {
+ \array_splice($args, $n);
+
+ return $func(...$args);
+ };
+}
diff --git a/src/Function/before.php b/src/Function/before.php
new file mode 100644
index 0000000..1dcacd4
--- /dev/null
+++ b/src/Function/before.php
@@ -0,0 +1,44 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+/**
+ * Creates a function that invokes `func`, with the arguments
+ * of the created function, while it's called less than `n` times. Subsequent
+ * calls to the created function return the result of the last `func` invocation.
+ *
+ * @category Function
+ *
+ * @param int $n The number of calls at which `func` is no longer invoked.
+ * @param callable $func The function to restrict.
+ *
+ * @return callable Returns the new restricted function.
+ *
+ * @example
+ *
+ * $users = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ * $result = uniqBy(map($users, before(5, [$repository, 'find'])), 'id')
+ * // => Fetch up to 4 results.
+ *
+ */
+function before(int $n, callable $func): callable
+{
+ $result = null;
+
+ return function (...$args) use (&$result, &$n, &$func) {
+ if (--$n > 0) {
+ $result = $func(...$args);
+ }
+
+ return $result;
+ };
+}
diff --git a/src/Function/bind.php b/src/Function/bind.php
new file mode 100644
index 0000000..e69e0bd
--- /dev/null
+++ b/src/Function/bind.php
@@ -0,0 +1,47 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+/**
+ * Creates a function that invokes `func` with the `this` binding of `object`
+ * and `partials` prepended to the arguments it receives.
+ *
+ * @category Function
+ *
+ * @param callable $function The function to bind.
+ * @param object|mixed $object The `object` binding of `func`.
+ * @param array $partials The arguments to be partially applied.
+ *
+ * @return callable Returns the new bound function.
+ * @example
+ *
+ * function greet($greeting, $punctuation) {
+ * return $greeting . ' ' . $this->user . $punctuation;
+ * }
+ *
+ * $object = $object = new class {
+ * public $user = 'fred';
+ * };
+ *
+ * $bound = bind('greet', $object, 'hi');
+ * $bound('!');
+ * // => 'hi fred!'
+ *
+ */
+function bind(callable $function, $object, ...$partials): callable
+{
+ return function (...$args) use ($object, $function, $partials) {
+ $function = \Closure::fromCallable($function)->bindTo($object, $function instanceof \Closure ? $object : null);
+
+ return $function(...array_merge($partials, $args));
+ };
+}
diff --git a/src/Function/bindKey.php b/src/Function/bindKey.php
new file mode 100644
index 0000000..636cec6
--- /dev/null
+++ b/src/Function/bindKey.php
@@ -0,0 +1,49 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+/**
+ * Creates a function that invokes the method `$function` of `$object` with `$partials`
+ * prepended to the arguments it receives.
+ *
+ * This method differs from `bind` by allowing bound functions to reference
+ * methods that may be redefined or don't yet exist
+ *
+ * @category Function
+ *
+ * @param object $object The object to invoke the method on.
+ * @param string $function The name of the method.
+ * @param array $partials The arguments to be partially applied.
+ *
+ * @return callable Returns the new bound function.
+ * @example
+ *
+ * $object = new class {
+ * private $user = 'fred';
+ * function greet($greeting, $punctuation) {
+ * return $greeting.' '.$this->user.$punctuation;
+ * }
+ * };
+ *
+ * $bound = bindKey($object, 'greet', 'hi');
+ * $bound('!');
+ * // => 'hi fred!'
+ *
+ */
+function bindKey($object, string $function, ...$partials): callable
+{
+ return function (...$args) use ($object, $function, $partials) {
+ $function = \Closure::fromCallable([$object, $function])->bindTo($object, get_class($object));
+
+ return $function(...array_merge($partials, $args));
+ };
+}
diff --git a/src/Function/curry.php b/src/Function/curry.php
new file mode 100644
index 0000000..d4cdd1c
--- /dev/null
+++ b/src/Function/curry.php
@@ -0,0 +1,85 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+/**
+ * Creates a function that accepts arguments of `func` and either invokes
+ * `func` returning its result, if at least `arity` number of arguments have
+ * been provided, or returns a function that accepts the remaining `func`
+ * arguments, and so on. The arity of `func` may be specified if `func.length`
+ * is not sufficient.
+ *
+ * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method doesn't set the "length" property of curried functions.
+ *
+ * @category Function
+ *
+ * @param callable $func The function to curry.
+ * @param int|null $arity The arity of `func`.
+ *
+ * @return callable Returns the new curried function.
+ * @example
+ *
+ * $abc = function($a, $b, $c) {
+ * return [$a, $b, $c];
+ * };
+ *
+ * $curried = curry($abc);
+ *
+ * $curried(1)(2)(3);
+ * // => [1, 2, 3]
+ *
+ * $curried(1, 2)(3);
+ * // => [1, 2, 3]
+ *
+ * $curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // Curried with placeholders.
+ * $curried(1)(_, 3)(2);
+ * // => [1, 2, 3]
+ *
+ */
+function curry(callable $func, ?int $arity = null)
+{
+ $curry = function ($arguments) use ($func, &$curry, $arity) {
+ $requiredArguments = (new \ReflectionFunction($func))->getNumberOfParameters();
+ $arity = $arity ?? $requiredArguments;
+
+ return function (...$args) use ($func, $arguments, $curry, $arity) {
+ if (false !== \array_search(_, $arguments)) {
+ foreach ($arguments as $i => $argument) {
+ if (_ !== $argument) {
+ continue;
+ }
+
+ $arguments[$i] = current($args);
+ next($args);
+ }
+ } else {
+ $arguments = \array_merge($arguments, $args);
+ }
+
+ if ($arity <= \count(\array_filter($arguments, function ($value) {
+ return _ !== $value;
+ }))) {
+ return $func(...$arguments);
+ }
+
+ return $curry($arguments);
+ };
+ };
+
+ return $curry([]);
+}
diff --git a/src/Function/delay.php b/src/Function/delay.php
new file mode 100644
index 0000000..53418fe
--- /dev/null
+++ b/src/Function/delay.php
@@ -0,0 +1,40 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+/**
+ * Invokes `func` after `wait` milliseconds. Any additional arguments are
+ * provided to `func` when it's invoked.
+ *
+ * @category Function
+ *
+ * @param callable $func The function to delay.
+ * @param int $wait The number of milliseconds to delay invocation.
+ * @param array $args
+ *
+ * @return int the timer id.
+ * @example
+ *
+ * delay(function($text) {
+ * echo $text;
+ * }, 1000, 'later');
+ * // => Echo 'later' after one second.
+ *
+ */
+function delay(callable $func, int $wait = 1, ...$args): int
+{
+ usleep($wait * 1000);
+
+ $func(...$args);
+
+ return 1;
+}
diff --git a/src/Function/flip.php b/src/Function/flip.php
new file mode 100644
index 0000000..91c1e33
--- /dev/null
+++ b/src/Function/flip.php
@@ -0,0 +1,41 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+use function _\internal\baseRest;
+use function _\internal\castSlice;
+
+/**
+ * Creates a function that invokes `func` with arguments reversed.
+ *
+ * @category Function
+ *
+ * @param callable $func The function to flip arguments for.
+ *
+ * @return callable Returns the new flipped function.
+ *
+ * @example
+ *
+ * $flipped = flip(function() {
+ * return func_get_args();
+ * });
+ *
+ * flipped('a', 'b', 'c', 'd');
+ * // => ['d', 'c', 'b', 'a']
+ *
+ */
+function flip(callable $func): callable
+{
+ return function (...$values) use ($func) {
+ return \array_reverse($func(...$values), false);
+ };
+}
diff --git a/src/Function/memoize.php b/src/Function/memoize.php
index e32658d..13ec3a1 100644
--- a/src/Function/memoize.php
+++ b/src/Function/memoize.php
@@ -25,8 +25,8 @@
*
* @category Function
*
- * @param callable $func The function to have its output memoized.
- * @param callable $resolver The function to resolve the cache key.
+ * @param callable $func The function to have its output memoized.
+ * @param callable|null $resolver The function to resolve the cache key.
*
* @return callable Returns the new memoized function.
*
@@ -52,9 +52,10 @@
* // => ['a', 'b']
*
*/
-function memoize(callable $func = null, callable $resolver = null)
+function memoize(callable $func, callable $resolver = null)
{
$memoized = new class($func, $resolver ?? null) {
+
/**
* @var CacheInterface
*/
@@ -87,7 +88,7 @@ public function __invoke()
}
$result = ($this->func)(...$args);
- $this->cache = $this->cache->set($key, $result) ?: $this->cache;
+ $this->cache = $this->cache->set($key, $result);
return $result;
}
diff --git a/src/Function/negate.php b/src/Function/negate.php
index 90352d5..4032304 100644
--- a/src/Function/negate.php
+++ b/src/Function/negate.php
@@ -28,6 +28,7 @@
*
* filter([1, 2, 3, 4, 5, 6], negate($isEven));
* // => [1, 3, 5]
+ *
*/
function negate(callable $predicate): callable
@@ -35,4 +36,4 @@ function negate(callable $predicate): callable
return function () use ($predicate) {
return !$predicate(...\func_get_args());
};
-}
\ No newline at end of file
+}
diff --git a/src/Function/once.php b/src/Function/once.php
new file mode 100644
index 0000000..2ff0909
--- /dev/null
+++ b/src/Function/once.php
@@ -0,0 +1,36 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+/**
+ * Creates a function that is restricted to invoking `func` once. Repeat calls
+ * to the function return the value of the first invocation. The `func` is
+ * invoked with the arguments of the created function.
+ *
+ * @category Function
+ *
+ * @param callable $func The function to restrict.
+ *
+ * @return callable the new restricted function.
+ *
+ * @example
+ *
+ * $initialize = once('createApplication');
+ * $initialize();
+ * $initialize();
+ * // => `createApplication` is invoked once
+ *
+ */
+function once(callable $func): callable
+{
+ return before(2, $func);
+}
diff --git a/src/Function/overArgs.php b/src/Function/overArgs.php
new file mode 100644
index 0000000..386c27e
--- /dev/null
+++ b/src/Function/overArgs.php
@@ -0,0 +1,72 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+use function _\internal\arrayMap;
+use function _\internal\baseFlatten;
+use function _\internal\baseRest;
+use function _\internal\baseUnary;
+
+/**
+ * Creates a function that invokes `func` with its arguments transformed.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ *
+ * @param callable $func The function to wrap.
+ * @param callable[] $transforms The argument transforms.
+ *
+ * @return callable the new function.
+ *
+ * @example
+ *
+ * function doubled($n) {
+ * return $n * 2;
+ * }
+ *
+ * function square($n) {
+ * return $n * $n;
+ * }
+ *
+ * $func = overArgs(function($x, $y) {
+ * return [$x, $y];
+ * }, ['square', 'doubled']);
+ *
+ * $func(9, 3);
+ * // => [81, 6]
+ *
+ * $func(10, 5);
+ * // => [100, 10]
+ *
+ */
+function overArgs(callable $func, array $transforms): callable
+{
+ return baseRest(function ($func, $transforms) {
+ $transforms = (\count($transforms) == 1 && \is_array($transforms[0]))
+ ? arrayMap($transforms[0], baseUnary('\_\internal\baseIteratee'))
+ : arrayMap(baseFlatten($transforms, 1), baseUnary('\_\internal\baseIteratee'));
+
+ $funcsLength = \count($transforms);
+
+ return baseRest(function ($args) use ($funcsLength, $transforms, $func) {
+ $index = -1;
+ $length = \min(\count($args), $funcsLength);
+
+ while (++$index < $length) {
+ $args[$index] = $transforms[$index]($args[$index]);
+ }
+
+ return $func(...$args);
+ });
+ })($func, $transforms);
+}
diff --git a/src/Function/partial.php b/src/Function/partial.php
new file mode 100644
index 0000000..8ada3d7
--- /dev/null
+++ b/src/Function/partial.php
@@ -0,0 +1,62 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+use function _\internal\baseRest;
+use function _\internal\shortOut;
+
+/**
+ * Creates a function that invokes `func` with `partials` prepended to the
+ * arguments it receives.
+ *
+ * @category Function
+ *
+ * @param callable $func The function to partially apply arguments to.
+ * @param array
+ * function greet($greeting, $name) {
+ * return $greeting . ' ' . $name;
+ * }
+ *
+ * $sayHelloTo = partial('greet', 'hello');
+ * $sayHelloTo('fred');
+ * // => 'hello fred'
+ *
+ */
+function partial(callable $func, ...$partials): callable
+{
+ return baseRest(function ($func, $partials) {
+ $wrapper = function () use ($func, $partials) {
+ $arguments = \func_get_args();
+ $argsIndex = -1;
+ $argsLength = \func_num_args();
+ $leftIndex = -1;
+ $leftLength = \count($partials);
+ $args = [];
+
+ while (++$leftIndex < $leftLength) {
+ $args[$leftIndex] = $partials[$leftIndex];
+ }
+ while ($argsLength--) {
+ $args[$leftIndex++] = $arguments[++$argsIndex];
+ }
+
+ return $func(...$args);
+ };
+
+ return shortOut($wrapper);
+ })($func, ...$partials);
+}
diff --git a/src/Function/rest.php b/src/Function/rest.php
new file mode 100644
index 0000000..1402941
--- /dev/null
+++ b/src/Function/rest.php
@@ -0,0 +1,42 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+use function _\internal\baseRest;
+
+/**
+ * Creates a function that invokes `func` with the `this` binding of the
+ * created function and arguments from `start` and beyond provided as
+ * an array.
+ *
+ * @category Function
+ *
+ * @param callable $func The function to apply a rest parameter to.
+ * @param int|null $start The start position of the rest parameter.
+ *
+ * @return callable Returns the new function.
+ *
+ * @example
+ *
+ * $say = rest(function($what, $names) {
+ * return $what . ' ' . implode(', ', initial($names)) .
+ * (size($names) > 1 ? ', & ' : '') . last($names);
+ * });
+ *
+ * $say('hello', 'fred', 'barney', 'pebbles');
+ * // => 'hello fred, barney, & pebbles'
+ *
+ */
+function rest(callable $func, ?int $start = null): callable
+{
+ return baseRest($func, $start);
+}
diff --git a/src/Function/spread.php b/src/Function/spread.php
new file mode 100644
index 0000000..7dfab5f
--- /dev/null
+++ b/src/Function/spread.php
@@ -0,0 +1,59 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+use function _\internal\baseRest;
+use function _\internal\castSlice;
+
+/**
+ * Creates a function that invokes `func` with the `this` binding of the
+ * create function and an array of arguments much like
+ * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply).
+ *
+ * **Note:** This method is based on the
+ * [spread operator](https://mdn.io/spread_operator).
+ *
+ * @static
+ * @memberOf _
+ * @since 3.2.0
+ * @category Function
+ *
+ * @param callable $func The function to spread arguments over.
+ * @param int $start The start position of the spread.
+ *
+ * @return callable Returns the new function.
+ *
+ * @example
+ *
+ * $say = spread(function($who, $what) {
+ * return $who . ' says ' . $what;
+ * });
+ *
+ * $say(['fred', 'hello']);
+ * // => 'fred says hello'
+ *
+ */
+function spread(callable $func, ?int $start = null)
+{
+ $start = null === $start ? 0 : \max($start, 0);
+
+ return baseRest(function ($args) use ($start, $func) {
+ $array = $args[$start];
+ $otherArgs = castSlice($args, 0, $start);
+
+ if ($array) {
+ $otherArgs = \array_merge($otherArgs, $array);
+ }
+
+ return $func(...$otherArgs);
+ });
+}
diff --git a/src/Function/unary.php b/src/Function/unary.php
new file mode 100644
index 0000000..d179ba8
--- /dev/null
+++ b/src/Function/unary.php
@@ -0,0 +1,32 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+/**
+ * Creates a function that accepts up to one argument, ignoring any
+ * additional arguments.
+ *
+ * @category Function
+ *
+ * @param callable $func The function to cap arguments for.
+ *
+ * @return callable the new capped function.
+ * @example
+ *
+ * map(['6', '8', '10'], unary('intval'));
+ * // => [6, 8, 10]
+ *
+ */
+function unary(callable $func): callable
+{
+ return ary($func, 1);
+}
diff --git a/src/Function/wrap.php b/src/Function/wrap.php
new file mode 100644
index 0000000..84df495
--- /dev/null
+++ b/src/Function/wrap.php
@@ -0,0 +1,38 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+/**
+ * Creates a function that provides `value` to `wrapper` as its first
+ * argument. Any additional arguments provided to the function are appended
+ * to those provided to the `wrapper`.
+ *
+ * @category Function
+ *
+ * @param mixed $value The value to wrap.
+ * @param callable $wrapper The wrapper function.
+ *
+ * @return callable the new function.
+ * @example
+ *
+ * $p = wrap('_\escape', function($func, $text) {
+ * return '' . $func($text) . '
';
+ * });
+ *
+ * $p('fred, barney, & pebbles');
+ * // => 'fred, barney, & pebbles
'
+ *
+ */
+function wrap($value, callable $wrapper = null): callable
+{
+ return partial($wrapper ?? '\_\identity', $value);
+}
diff --git a/src/Lang/isError.php b/src/Lang/isError.php
index a31596c..0a9598f 100644
--- a/src/Lang/isError.php
+++ b/src/Lang/isError.php
@@ -27,6 +27,7 @@
*
* isError(\Exception::Class)
* // => false
+ *
*/
function isError($value): bool
{
diff --git a/src/ListCache.php b/src/ListCache.php
index 89afee2..0c8931d 100644
--- a/src/ListCache.php
+++ b/src/ListCache.php
@@ -14,6 +14,10 @@
use _\internal\Traits\CacheDataTrait;
use function _\internal\assocIndexOf;
+/**
+ * @property array $__data__
+ * @property int $size
+ */
final class ListCache implements CacheInterface
{
use CacheDataTrait;
@@ -71,7 +75,7 @@ final public function delete($key)
$lastIndex = \count($this->__data__) - 1;
if ($index === $lastIndex) {
- \array_pop($data);
+ \array_pop($this->__data__);
} else {
\array_splice($this->__data__, $index, 1);
}
diff --git a/src/Lodash.php b/src/Lodash.php
index 2c0835c..08a6e01 100644
--- a/src/Lodash.php
+++ b/src/Lodash.php
@@ -11,6 +11,8 @@
final class _
{
+ public $__chain__ = false;
+
public const reInterpolate = '<%=([\s\S]+?)%>';
public const reEvaluate = "<%([\s\S]+?)%>";
public const reEscape = "<%-([\s\S]+?)%>";
@@ -44,6 +46,13 @@ final class _
],
];
+ private $value;
+
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
/**
* @param string $method
* @param array $args
@@ -53,6 +62,40 @@ final class _
*/
public static function __callStatic(string $method, array $args)
{
+ if (!\is_callable("_\\$method")) {
+ throw new \InvalidArgumentException("Function _::$method is not valid");
+ }
+
return ("_\\$method")(...$args);
}
+
+ public function __call($method, $arguments)
+ {
+ $this->value = self::__callStatic($method, \array_merge([$this->value], $arguments));
+
+ return $this;
+ }
+
+ public function value()
+ {
+ return $this->value;
+ }
+}
+
+function lodash($value): _
+{
+ return new _($value);
+}
+
+// We can't use "_" as a function name, since it collides with the "_" function in the gettext extension
+// Laravel uses a function __, so only register the alias if the function name is not in use
+if (!function_exists('__')) {
+ function __($value): _
+ {
+ return new _($value);
+ }
+}
+
+if (!defined('_')) {
+ define('_', _::class);
}
diff --git a/src/MapCache.php b/src/MapCache.php
index ff4e0f4..7726fad 100644
--- a/src/MapCache.php
+++ b/src/MapCache.php
@@ -13,6 +13,10 @@
use _\internal\Traits\CacheDataTrait;
+/**
+ * @property array $__data__
+ * @property int $size
+ */
final class MapCache implements CacheInterface
{
use CacheDataTrait;
diff --git a/src/Math/max.php b/src/Math/max.php
index c454d02..bc61451 100644
--- a/src/Math/max.php
+++ b/src/Math/max.php
@@ -16,7 +16,7 @@
*
* @category Math
*
- * @param array array The array to iterate over.
+ * @param array|null $array The array to iterate over.
*
* @return int|null Returns the maximum value.
* @example
@@ -31,4 +31,4 @@
function max(?array $array): ?int
{
return $array ? \max($array) : null;
-}
\ No newline at end of file
+}
diff --git a/src/Math/maxBy.php b/src/Math/maxBy.php
index 97d9c7c..3127605 100644
--- a/src/Math/maxBy.php
+++ b/src/Math/maxBy.php
@@ -34,6 +34,7 @@
* // The `property` iteratee shorthand.
* maxBy($objects, 'n');
* // => ['n' => 2]
+ *
*/
function maxBy(?array $array, $iteratee)
{
@@ -51,4 +52,4 @@ function maxBy(?array $array, $iteratee)
}
return $result;
-}
\ No newline at end of file
+}
diff --git a/src/Number/clamp.php b/src/Number/clamp.php
index d2c2993..2ab5ddc 100644
--- a/src/Number/clamp.php
+++ b/src/Number/clamp.php
@@ -16,9 +16,9 @@
*
* @category Number
*
- * @param int number The number to clamp.
- * @param int lower The lower bound.
- * @param int upper The upper bound.
+ * @param int $number The number to clamp.
+ * @param int $lower The lower bound.
+ * @param int $upper The upper bound.
*
* @return int Returns the clamped number.
*
diff --git a/src/Number/inRange.php b/src/Number/inRange.php
index ac58b20..f1408ae 100644
--- a/src/Number/inRange.php
+++ b/src/Number/inRange.php
@@ -19,11 +19,12 @@
*
* @category Number
*
- * @param float number The number to check.
- * @param float $start The start of the range.
- * @param float $end The end of the range.
+ * @param float $number The number to check.
+ * @param float $start The start of the range.
+ * @param float $end The end of the range.
*
* @return boolean Returns `true` if `number` is in the range, else `false`.
+ *
* @example
*
* inRange(3, 2, 4)
@@ -50,7 +51,7 @@
*/
function inRange(float $number, float $start = 0, float $end = 0): bool
{
- if (0 === $end || 0.0 === $end) {
+ if (0.0 === $end) {
$end = $start;
$start = 0;
}
diff --git a/src/Number/random.php b/src/Number/random.php
index 1bf799d..8d322af 100644
--- a/src/Number/random.php
+++ b/src/Number/random.php
@@ -19,14 +19,14 @@
*
* @category Number
*
- * @param int|float $lower The lower bound.
- * @param int|float $upper The upper bound.
- * @param bool $floating Specify returning a floating-point number.
+ * @param int|float|bool $lower The lower bound.
+ * @param int|float|bool $upper The upper bound.
+ * @param bool|null $floating Specify returning a floating-point number.
*
* @return int|float Returns the random number.
*
* @example
- *
+ *
* random(0, 5)
* // => an integer between 0 and 5
*
@@ -38,6 +38,7 @@
*
* random(1.2, 5.2)
* // => a floating-point number between 1.2 and 5.2
+ *
*/
function random($lower = null, $upper = null, $floating = null)
{
@@ -73,5 +74,5 @@ function random($lower = null, $upper = null, $floating = null)
return $lower + \abs($upper - $lower) * \mt_rand(0, $randMax) / $randMax;
}
- return \rand((int) $lower, (int) $upper);
+ return \random_int((int) $lower, (int) $upper);
}
diff --git a/src/Object/get.php b/src/Object/get.php
new file mode 100644
index 0000000..3a0c66d
--- /dev/null
+++ b/src/Object/get.php
@@ -0,0 +1,45 @@
+
+ * @copyright Copyright (c) 2019
+ */
+
+namespace _;
+
+use function _\internal\baseGet;
+
+/**
+ * Gets the value at path of object. If the resolved value is null the defaultValue is returned in its place.
+ *
+ * @category Object
+ *
+ * @param mixed $object The associative array or object to fetch value from
+ * @param array|string $path Dot separated or array of string
+ * @param mixed $defaultValue (optional)The value returned for unresolved or null values.
+ *
+ * @return mixed Returns the resolved value.
+ *
+ * @author punit-kulal
+ *
+ * @example
+ *
+ * $sampleArray = ["key1" => ["key2" => ["key3" => "val1", "key4" => ""]]];
+ * get($sampleArray, 'key1.key2.key3');
+ * // => "val1"
+ *
+ * get($sampleArray, 'key1.key2.key5', "default");
+ * // => "default"
+ *
+ * get($sampleArray, 'key1.key2.key4', "default");
+ * // => ""
+ *
+ */
+function get($object, $path, $defaultValue = null)
+{
+ return ($object !== null ? baseGet($object, $path) : null) ?? $defaultValue;
+}
diff --git a/src/Object/pick.php b/src/Object/pick.php
new file mode 100644
index 0000000..9813514
--- /dev/null
+++ b/src/Object/pick.php
@@ -0,0 +1,39 @@
+
+ * @copyright Copyright (c) 2018
+ */
+
+namespace _;
+
+use function _\internal\basePick;
+use function _\internal\flatRest;
+
+/**
+ * Creates an object composed of the picked `object` properties.
+ *
+ * @category Object
+ *
+ * @param object $object The source object.
+ * @param string|string[] $paths The property paths to pick.
+ *
+ * @return \stdClass Returns the new object.
+ * @example
+ *
+ * $object = (object) ['a' => 1, 'b' => '2', 'c' => 3];
+ *
+ * pick($object, ['a', 'c']);
+ * // => (object) ['a' => 1, 'c' => 3]
+ *
+ */
+function pick($object, $paths): \stdClass
+{
+ return flatRest(function ($object, $paths) {
+ return basePick($object, $paths);
+ })($object, $paths);
+}
diff --git a/src/Object/pickBy.php b/src/Object/pickBy.php
new file mode 100644
index 0000000..7d85cc0
--- /dev/null
+++ b/src/Object/pickBy.php
@@ -0,0 +1,50 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+use function _\internal\arrayMap;
+use function _\internal\baseIteratee;
+use function _\internal\basePickBy;
+
+/**
+ * Creates an object composed of the `object` properties `predicate` returns
+ * truthy for. The predicate is invoked with two arguments: (value, key).
+ *
+ * @category Object
+ *
+ * @param object|null $object The source object.
+ * @param callable $predicate The function invoked per property.
+ *
+ * @return \stdClass Returns the new object.
+ * @example
+ *
+ * $object = (object) ['a' => 1, 'b' => 'abc', 'c' => 3];
+ *
+ * pickBy(object, 'is_numeric');
+ * // => (object) ['a' => 1, 'c' => 3]
+ *
+ */
+function pickBy($object, callable $predicate): \stdClass
+{
+ if (null === $object) {
+ return new \stdClass;
+ }
+
+ $props = arrayMap(\array_keys(\get_object_vars($object)), function ($prop) {
+ return [$prop];
+ });
+ $predicate = baseIteratee($predicate);
+
+ return basePickBy($object, $props, function ($value, $path) use ($predicate) {
+ return $predicate($value, $path[0]);
+ });
+}
diff --git a/src/Seq/chain.php b/src/Seq/chain.php
new file mode 100644
index 0000000..63e3149
--- /dev/null
+++ b/src/Seq/chain.php
@@ -0,0 +1,49 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+namespace _;
+
+/**
+ * Creates a `lodash` wrapper instance that wraps `value` with explicit method
+ * chain sequences enabled. The result of such sequences must be unwrapped
+ * with `->value()`.
+ *
+ * @category Seq
+ *
+ * @param mixed $value The value to wrap.
+ *
+ * @return \_ Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * $users = [
+ * ['user' => 'barney', 'age' => 36],
+ * ['user' => 'fred', 'age' => 40],
+ * ['user' => 'pebbles', 'age' => 1 ],
+ * ];
+ *
+ * $youngest = chain($users)
+ * ->sortBy('age')
+ * ->map(function($o) {
+ * return $o['user'] . ' is ' . $o['age'];
+ * })
+ * ->head()
+ * ->value();
+ * // => 'pebbles is 1'
+ *
+ */
+function chain($value): \_
+{
+ /** @var \_ $result */
+ $result = __($value);
+ $result->__chain__ = true;
+
+ return $result;
+}
diff --git a/src/String/deburr.php b/src/String/deburr.php
index 579ae6b..a850d78 100644
--- a/src/String/deburr.php
+++ b/src/String/deburr.php
@@ -96,9 +96,10 @@
* @return string Returns the deburred string.
*
* @example
- *
+ *
* deburr('déjà vu')
* // => 'deja vu'
+ *
*/
function deburr(string $string): string
{
diff --git a/src/String/replace.php b/src/String/replace.php
index a19f5bb..9e308f6 100644
--- a/src/String/replace.php
+++ b/src/String/replace.php
@@ -19,9 +19,9 @@
*
* @category String
*
- * @param string $string The string to modify.
- * @param string $pattern The pattern to replace.
- * @param callable|string replacement The match replacement.
+ * @param string $string The string to modify.
+ * @param string $pattern The pattern to replace.
+ * @param callable|string $replacement The match replacement.
*
* @return string Returns the modified string.
*
@@ -31,23 +31,23 @@
* // => 'Hi Barney'
*
*/
-function replace(string $string, string $pattern, $replacement = ''): string
+function replace(string $string, string $pattern, $replacement = null): string
{
$callback = function (array $matches) use ($replacement): ?string {
if (!\array_filter($matches)) {
return null;
}
- return $replacement(...$matches);
+ return \is_callable($replacement) ? $replacement(...$matches) : null;
};
if (\preg_match(reRegExpChar, $pattern)) {
- if (!is_callable($replacement)) {
- return \preg_replace($pattern, $replacement, $string);
+ if (!\is_callable($replacement)) {
+ return \preg_replace($pattern, \is_string($replacement) || \is_array($replacement) ? $replacement : '', $string);
}
return \preg_replace_callback($pattern, $callback, $string);
}
- return \str_replace($pattern, $replacement, $string);
+ return \str_replace($pattern, \is_string($replacement) || \is_array($replacement) ? $replacement : '', $string);
}
diff --git a/src/String/snakeCase.php b/src/String/snakeCase.php
index fcb4a50..07c3d0f 100644
--- a/src/String/snakeCase.php
+++ b/src/String/snakeCase.php
@@ -19,7 +19,7 @@
* @param string $string The string to convert.
* @return string Returns the snake cased string.
* @example
- *
+ *
* snakeCase('Foo Bar')
* // => 'foo_bar'
*
@@ -28,6 +28,7 @@
*
* snakeCase('--FOO-BAR--')
* // => 'foo_bar'
+ *
*/
function snakeCase(string $string): string
{
diff --git a/src/String/split.php b/src/String/split.php
index 0f3b06c..73916c3 100644
--- a/src/String/split.php
+++ b/src/String/split.php
@@ -19,7 +19,7 @@
*
* @category String
*
- * @param string string The string to split.
+ * @param string $string The string to split.
* @param string $separator The separator pattern to split by.
* @param int $limit The length to truncate results to.
*
@@ -30,12 +30,13 @@
* // => ['a', 'b']
*
*/
-function split(string $string, string $separator, int $limit = null): array
+function split(string $string, string $separator, int $limit = 0): array
{
if (\preg_match(reRegExpChar, $separator)) {
- return \preg_split($separator, $string, $limit ?? -1, PREG_SPLIT_DELIM_CAPTURE);
+ return \preg_split($separator, $string, $limit ?: -1, PREG_SPLIT_DELIM_CAPTURE) ?: [];
}
+ /** @var array $result */
$result = \explode($separator, $string);
if ($limit > 0) {
diff --git a/src/String/template.php b/src/String/template.php
index f1f99fd..8b76ef0 100644
--- a/src/String/template.php
+++ b/src/String/template.php
@@ -106,13 +106,13 @@ function template(string $string, array $options = []): callable
($options['evaluate'] ?? reNoMatch),
]);
- $string = \preg_replace_callback('#'.$reDelimiters.'#u', function ($matches) use (&$options) {
- list(,
+ $string = \preg_replace_callback('#'.$reDelimiters.'#u', function ($matches) {
+ [,
$escapeValue,
$interpolateValue,
$esTemplateValue,
$evaluateValue,
- ) = \array_merge($matches, \array_fill(\count($matches), 5 - \count($matches), null));
+ ] = \array_merge($matches, \array_fill(\count($matches), 5 - \count($matches), null));
$interpolateValue = $interpolateValue ?: $esTemplateValue;
@@ -120,17 +120,17 @@ function template(string $string, array $options = []): callable
if ($escapeValue) {
$escapeValue = \trim($escapeValue);
- $source .= "=__e(\$${escapeValue});?>";
+ $source .= "=__e(\${$escapeValue});?>";
}
if ($evaluateValue) {
- $source .= "";
+ $source .= "";
}
if ($interpolateValue) {
- $interpolateValue = \trim($interpolateValue ?? $esTemplateValue);
+ $interpolateValue = \trim($interpolateValue);
$interpolateValue = \preg_replace('#^([\p{L}\p{N}_]+)$#u', '$$1', $interpolateValue);
- $source .= "=${interpolateValue};?>";
+ $source .= "={$interpolateValue};?>";
}
return $source;
@@ -145,8 +145,14 @@ function template(string $string, array $options = []): callable
return new class($string, $imports) {
public $source;
+ /**
+ * @var array
* trimEnd(' abc ')
* // => ' abc'
*
* trimEnd('-_-abc-_-', '_-')
* // => '-_-abc'
+ *
*/
function trimEnd(string $string, string $chars = ' '): string
{
diff --git a/src/String/truncate.php b/src/String/truncate.php
index 2b6c7ed..381c0df 100644
--- a/src/String/truncate.php
+++ b/src/String/truncate.php
@@ -101,11 +101,11 @@ function truncate($string, array $options = [])
$newEnd = \end($match[0])[1];
}
- $result = \substr($result, 0, null === $newEnd ? $end : $newEnd);
+ $result = \substr($result, 0, $newEnd ?? $end);
}
} elseif (\strpos($string, $separator) !== $end) {
$index = \strrpos($result, $separator);
- if ($index > -1) {
+ if (false !== $index) {
$result = \substr($result, 0, $index);
}
}
diff --git a/src/Util/attempt.php b/src/Util/attempt.php
index c104d41..2b1895b 100644
--- a/src/Util/attempt.php
+++ b/src/Util/attempt.php
@@ -18,7 +18,7 @@
* @category Util
*
* @param callable $func The function to attempt.
- * @param mixed[] $args The arguments to invoke `func` with.
+ * @param array
+ * $a = null;
+ *
+ * defaultTo($a, "default");
+ * // => "default"
+ *
+ * $a = "x";
+ *
+ * defaultTo($a, "default");
+ * // => "x"
+ *
+ */
+function defaultTo($value, $defaultValue)
+{
+ return (null !== $value && (is_object($value) || !\is_nan(\floatval($value)))) ? $value : $defaultValue;
+}
diff --git a/src/Util/property.php b/src/Util/property.php
index b44f40a..17f75f0 100644
--- a/src/Util/property.php
+++ b/src/Util/property.php
@@ -11,6 +11,8 @@
namespace _;
+use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException;
+use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
use Symfony\Component\PropertyAccess\PropertyAccess;
/**
@@ -18,7 +20,7 @@
*
* @category Util
*
- * @param array|string path The path of the property to get.
+ * @param array|string $path The path of the property to get.
*
* @return callable Returns the new accessor function.
* @example
@@ -60,6 +62,10 @@ function property($path): callable
}
}
- return $propertyAccess->getValue($value, $path);
+ try {
+ return $propertyAccess->getValue($value, $path);
+ } catch (NoSuchPropertyException | NoSuchIndexException $e) {
+ return null;
+ }
};
}
diff --git a/src/bootstrap.php b/src/bootstrap.php
index 745a01a..8bc7456 100644
--- a/src/bootstrap.php
+++ b/src/bootstrap.php
@@ -9,6 +9,14 @@
* @copyright Copyright (c) 2017
*/
-foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__, RecursiveDirectoryIterator::SKIP_DOTS)) as $file) {
- require_once $file->getRealPath();
+if (file_exists($file = __DIR__.'/compiled.php')) {
+ require_once $file;
+} else {
+ require_once __DIR__.'/internal/Traits/CacheDataTrait.php';
+ require_once __DIR__.'/internal/unicode.php';
+ require_once __DIR__.'/CacheInterface.php';
+
+ foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__, RecursiveDirectoryIterator::SKIP_DOTS)) as $file) {
+ require_once $file->getRealPath();
+ }
}
diff --git a/src/internal/Traits/CacheDataTrait.php b/src/internal/Traits/CacheDataTrait.php
index ceb2e8d..4700cce 100644
--- a/src/internal/Traits/CacheDataTrait.php
+++ b/src/internal/Traits/CacheDataTrait.php
@@ -13,7 +13,7 @@
trait CacheDataTrait
{
- private $__data__;
+ private $__data__ = [];
private $size;
diff --git a/src/internal/arrayPush.php b/src/internal/arrayPush.php
new file mode 100644
index 0000000..a0af2b3
--- /dev/null
+++ b/src/internal/arrayPush.php
@@ -0,0 +1,25 @@
+
+ * @copyright Copyright (c) 2018
+ */
+
+namespace _\internal;
+
+function arrayPush(&$array, $values)
+{
+ $index = -1;
+ $length = \is_array($values) ? \count($values) : \strlen($values);
+ $offset = \count($array);
+
+ while (++$index < $length) {
+ $array[$offset + $index] = $values[$index];
+ }
+
+ return $array;
+}
diff --git a/src/internal/baseFlatten.php b/src/internal/baseFlatten.php
index 482142b..61a7a03 100644
--- a/src/internal/baseFlatten.php
+++ b/src/internal/baseFlatten.php
@@ -16,15 +16,15 @@
*
* @private
*
- * @param array $array The array to flatten.
- * @param int $depth The maximum recursion depth.
- * @param callable $predicate The function invoked per iteration [isFlattenable].
- * @param bool $isStrict Restrict to values that pass `predicate` checks.
- * @param array $result The initial result value.
+ * @param array|null $array The array to flatten.
+ * @param int $depth The maximum recursion depth.
+ * @param callable|null $predicate The function invoked per iteration [isFlattenable].
+ * @param bool|null $isStrict Restrict to values that pass `predicate` checks.
+ * @param array|null $result The initial result value.
*
* @return array Returns the new flattened array.
*/
-function baseFlatten(?array $array, float $depth, callable $predicate = null, bool $isStrict = null, array $result = null): array
+function baseFlatten(?array $array, int $depth, callable $predicate = null, bool $isStrict = null, array $result = null): array
{
$result = $result ?? [];
@@ -32,7 +32,7 @@ function baseFlatten(?array $array, float $depth, callable $predicate = null, bo
return $result;
}
- $predicate = $predicate ?? '\_\internal\isFlattenable';
+ $predicate = $predicate ?? '_\internal\isFlattenable';
foreach ($array as $value) {
if ($depth > 0 && $predicate($value)) {
@@ -40,7 +40,7 @@ function baseFlatten(?array $array, float $depth, callable $predicate = null, bo
// Recursively flatten arrays (susceptible to call stack limits).
$result = baseFlatten($value, $depth - 1, $predicate, $isStrict, $result);
} else {
- $result = \array_merge($result, $value);
+ arrayPush($result, $value);
}
} elseif (!$isStrict) {
$result[\count($result)] = $value;
diff --git a/src/internal/baseGet.php b/src/internal/baseGet.php
new file mode 100644
index 0000000..a9ff96a
--- /dev/null
+++ b/src/internal/baseGet.php
@@ -0,0 +1,28 @@
+
+ * @copyright Copyright (c) 2018
+ */
+
+namespace _\internal;
+
+use function _\property;
+
+function baseGet($object, $path)
+{
+ $path = castPath($path, $object);
+
+ $index = 0;
+ $length = \count($path);
+
+ while ($object !== null && !is_scalar($object) && $index < $length) {
+ $object = property(toKey($path[$index++]))($object);
+ }
+
+ return ($index > 0 && $index === $length) ? $object : null;
+}
diff --git a/src/internal/baseIntersection.php b/src/internal/baseIntersection.php
index 03efbf8..e366d37 100644
--- a/src/internal/baseIntersection.php
+++ b/src/internal/baseIntersection.php
@@ -41,15 +41,15 @@ function baseIntersection($arrays, ?callable $iteratee, $comparator = null)
$computed = $iteratee ? $iteratee($value) : $value;
$value = ($comparator ?: $value !== 0) ? $value : 0;
- if (!($seen ? isset($seen[$computed]) : $includes($result, $computed, $comparator))) {
+ if (!($seen ? \is_scalar($computed) && isset($seen[$computed]) : $includes($result, $computed, $comparator))) {
$othIndex = $othLength;
while (--$othIndex) {
$cache = $caches[$othIndex];
- if (!($cache ? isset($cache[$computed]) : $includes($arrays[$othIndex], $computed, $comparator))) {
+ if (!(!empty($cache) ? isset($cache[$computed]) : $includes($arrays[$othIndex], $computed, $comparator))) {
continue 2;
}
}
- if ($seen) {
+ if (empty($seen)) {
$seen[] = $computed;
}
diff --git a/src/internal/baseInvoke.php b/src/internal/baseInvoke.php
index 583ae05..1170f84 100644
--- a/src/internal/baseInvoke.php
+++ b/src/internal/baseInvoke.php
@@ -17,7 +17,8 @@ function baseInvoke($object, $path, $args)
{
$path = castPath($path, $object);
$object = parent($object, $path);
+ /** @var callable|null $func */
$func = null === $object ? $object : [$object, toKey(last($path))];
- return null === $func ? null : $func($object, ...$args);
-}
\ No newline at end of file
+ return \is_callable($func) ? $func($object, ...$args) : null;
+}
diff --git a/src/internal/baseMatches.php b/src/internal/baseMatches.php
index d7c919b..3f39f4f 100644
--- a/src/internal/baseMatches.php
+++ b/src/internal/baseMatches.php
@@ -21,7 +21,7 @@ function baseMatches($source): callable
return true;
}
- if (\is_array($source) || $source instanceof \Traversable) {
+ if (\is_iterable($source)) {
foreach ($source as $k => $v) {
if (!isEqual(property($k)($value, $index, $collection), $v)) {
return false;
diff --git a/src/internal/baseOrderBy.php b/src/internal/baseOrderBy.php
index ca231d0..d8c2d89 100644
--- a/src/internal/baseOrderBy.php
+++ b/src/internal/baseOrderBy.php
@@ -30,4 +30,4 @@ function baseOrderBy(iterable $collection, array $iteratees, array $orders): arr
return map(sortBy($result, function ($object, $other) use ($orders) {
return compareMultiple($object, $other, $orders);
}), 'value');
-}
\ No newline at end of file
+}
diff --git a/src/internal/basePick.php b/src/internal/basePick.php
new file mode 100644
index 0000000..477ab46
--- /dev/null
+++ b/src/internal/basePick.php
@@ -0,0 +1,19 @@
+
+ * @copyright Copyright (c) 2018
+ */
+
+namespace _\internal;
+
+function basePick($object, $paths): \stdClass
+{
+ return basePickBy($object, $paths, function ($value, $path) use ($object) {
+ return property_exists($object, $path) || method_exists($object, 'get'.(ucfirst($path)));
+ });
+}
diff --git a/src/internal/basePickBy.php b/src/internal/basePickBy.php
new file mode 100644
index 0000000..3176a70
--- /dev/null
+++ b/src/internal/basePickBy.php
@@ -0,0 +1,30 @@
+
+ * @copyright Copyright (c) 2018
+ */
+
+namespace _\internal;
+
+function basePickBy($object, $paths, callable $predicate): \stdClass
+{
+ $index = -1;
+ $length = \is_array($paths) ? \count($paths) : \strlen($paths);
+ $result = new \stdClass();
+
+ while (++$index < $length) {
+ $path = $paths[$index];
+ $value = baseGet($object, $path);
+
+ if ($predicate($value, $path)) {
+ baseSet($result, castPath($path, $object), $value);
+ }
+ }
+
+ return $result;
+}
diff --git a/src/internal/basePullAll.php b/src/internal/basePullAll.php
index f4d0c12..9b69ae3 100644
--- a/src/internal/basePullAll.php
+++ b/src/internal/basePullAll.php
@@ -13,7 +13,7 @@
function basePullAll(&$array, array $values, ?callable $iteratee, callable $comparator = null)
{
- $indexOf = $comparator ? '_\internal\baseIndexOfWith' : '_\indexOf';
+ $indexOf = $comparator ? '_\\internal\\baseIndexOfWith' : '_\\indexOf';
$seen = $array;
diff --git a/src/internal/baseReduce.php b/src/internal/baseReduce.php
index 5e7b1d1..9d0f360 100644
--- a/src/internal/baseReduce.php
+++ b/src/internal/baseReduce.php
@@ -13,7 +13,7 @@
function baseReduce(iterable $array, $iteratee, $accumulator, $initAccum = null)
{
- $length = \count($array);
+ $length = \is_array($array) || $array instanceof \Countable ? \count($array) : 0;
if ($initAccum && $length) {
$accumulator = \current($array);
@@ -24,4 +24,4 @@ function baseReduce(iterable $array, $iteratee, $accumulator, $initAccum = null)
}
return $accumulator;
-}
\ No newline at end of file
+}
diff --git a/src/internal/baseUnary.php b/src/internal/baseUnary.php
index d1aa978..ddfbf80 100644
--- a/src/internal/baseUnary.php
+++ b/src/internal/baseUnary.php
@@ -16,4 +16,4 @@ function baseUnary($func)
return function ($value) use ($func) {
return $func($value);
};
-}
\ No newline at end of file
+}
diff --git a/src/internal/castSlice.php b/src/internal/castSlice.php
index fcb027c..6d50495 100644
--- a/src/internal/castSlice.php
+++ b/src/internal/castSlice.php
@@ -25,7 +25,7 @@
function castSlice(array $array, int $start, ?int $end = null): array
{
$length = \count($array);
- $end = null === $end ? $length : $end;
+ $end = $end ?? $length;
return (!$start && $end >= $length) ? $array : \array_slice($array, $start, $end);
}
diff --git a/src/internal/compareMultiple.php b/src/internal/compareMultiple.php
index 257f633..ec345de 100644
--- a/src/internal/compareMultiple.php
+++ b/src/internal/compareMultiple.php
@@ -32,4 +32,4 @@ function compareMultiple($object, $other, $orders)
}
return $object['index'] - $other['index'];
-}
\ No newline at end of file
+}
diff --git a/src/internal/createAggregator.php b/src/internal/createAggregator.php
index 0bd4a43..ea63c5a 100644
--- a/src/internal/createAggregator.php
+++ b/src/internal/createAggregator.php
@@ -28,4 +28,4 @@ function createAggregator($setter, $initializer = null)
return $func($collection, $setter, $accumulator, baseIteratee($iteratee));
};
-}
\ No newline at end of file
+}
diff --git a/src/internal/flatRest.php b/src/internal/flatRest.php
new file mode 100644
index 0000000..0cee4a8
--- /dev/null
+++ b/src/internal/flatRest.php
@@ -0,0 +1,17 @@
+
+ * @copyright Copyright (c) 2018
+ */
+
+namespace _\internal;
+
+function flatRest(callable $func): callable
+{
+ return shortOut(overRest($func, null, '\_\flatten'));
+}
diff --git a/src/internal/isFlattenable.php b/src/internal/isFlattenable.php
index 266f59e..f14b5b4 100644
--- a/src/internal/isFlattenable.php
+++ b/src/internal/isFlattenable.php
@@ -22,5 +22,5 @@
*/
function isFlattenable($value): bool
{
- return \is_array($value) && \range(0, \count($value) - 1) === \array_keys($value);
+ return \is_array($value) && ([] === $value || \range(0, \count($value) - 1) === \array_keys($value));
}
diff --git a/src/internal/isIterateeCall.php b/src/internal/isIterateeCall.php
index 08b13b2..b9c3169 100644
--- a/src/internal/isIterateeCall.php
+++ b/src/internal/isIterateeCall.php
@@ -24,7 +24,7 @@
*/
function isIterateeCall($value, $index = null, $object = null)
{
- if (!\is_object($object) || !\is_array($object)) {
+ if (!\is_object($object) && !\is_array($object)) {
return false;
}
diff --git a/src/internal/isKey.php b/src/internal/isKey.php
index 4d99db8..bb0ce5b 100644
--- a/src/internal/isKey.php
+++ b/src/internal/isKey.php
@@ -18,7 +18,7 @@
/**
* Checks if `value` is a property name and not a property path.
*
- * @param mixed value The value to check.
+ * @param mixed $value The value to check.
* @param object|array $object The object to query keys on.
*
* @return boolean Returns `true` if `value` is a property name, else `false`.
diff --git a/src/internal/overRest.php b/src/internal/overRest.php
index cfb46ce..a17be23 100644
--- a/src/internal/overRest.php
+++ b/src/internal/overRest.php
@@ -13,7 +13,8 @@
function overRest(callable $func, $start, callable $transform): callable
{
- $start = max($start ?? -1, 0);
+ $parameters = (new \ReflectionFunction($func))->getNumberOfParameters();
+ $start = max($start ?? $parameters - 1, 0);
return function () use ($func, $start, $transform) {
$args = \func_get_args();
@@ -31,6 +32,6 @@ function overRest(callable $func, $start, callable $transform): callable
}
$otherArgs[$start] = $transform($array);
- return $func(...$otherArgs[$start]);
+ return $func(...$otherArgs);
};
}
diff --git a/src/internal/parent.php b/src/internal/parent.php
index cc246b7..49b3d78 100644
--- a/src/internal/parent.php
+++ b/src/internal/parent.php
@@ -11,9 +11,7 @@
namespace _\internal;
-use function _\{slice, get};
-
function parent($object, $path)
{
- return count($path) < 2 ? $object : get($object, slice($path, 0, -1));
-}
\ No newline at end of file
+ return count($path) < 2 ? $object : null;
+}
diff --git a/src/internal/shortOut.php b/src/internal/shortOut.php
new file mode 100644
index 0000000..826ac6b
--- /dev/null
+++ b/src/internal/shortOut.php
@@ -0,0 +1,48 @@
+
+ * @copyright Copyright (c) 2018
+ */
+
+namespace _\internal;
+
+const HOT_COUNT = 800;
+const HOT_SPAN = 16;
+
+/**
+ * Creates a function that'll short out and invoke `identity` instead
+ * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
+ * milliseconds.
+ *
+ * @private
+ *
+ * @param callable $func The function to restrict.
+ *
+ * @return callable Returns the new shortable function.
+ */
+function shortOut(callable $func): callable
+{
+ $count = 0;
+ $lastCalled = 0;
+
+ return function () use ($func, &$count, &$lastCalled) {
+ $stamp = microtime(true);
+ $remaining = HOT_SPAN - ($stamp - $lastCalled);
+
+ $lastCalled = $stamp;
+ if ($remaining > 0) {
+ if (++$count >= HOT_COUNT) {
+ return func_get_arg(0);
+ }
+ } else {
+ $count = 0;
+ }
+
+ return $func(...func_get_args());
+ };
+}
diff --git a/src/internal/stringSize.php b/src/internal/stringSize.php
index b8b377e..10efb63 100644
--- a/src/internal/stringSize.php
+++ b/src/internal/stringSize.php
@@ -16,7 +16,7 @@
*
* @private
*
- * @param string string The string to inspect.
+ * @param string $string The string to inspect.
*
* @return int Returns the string size.
*/
diff --git a/src/internal/toKey.php b/src/internal/toKey.php
index b491944..d7a8117 100644
--- a/src/internal/toKey.php
+++ b/src/internal/toKey.php
@@ -14,7 +14,7 @@
/**
* Converts `value` to a string key if it's not a string.
*
- * @param mixed value The value to inspect.
+ * @param mixed $value The value to inspect.
*
* @return string Returns the key.
*/
diff --git a/src/internal/unicodeSize.php b/src/internal/unicodeSize.php
index 7604e2f..47ed627 100644
--- a/src/internal/unicodeSize.php
+++ b/src/internal/unicodeSize.php
@@ -20,7 +20,7 @@
*
* @return int Returns the string size.
*/
-function unicodeSize($string): int
+function unicodeSize(string $string): int
{
- return \preg_match_all(reUnicode, $string);
+ return \preg_match_all(reUnicode, $string) ?: 0;
}
diff --git a/src/internal/unicodeWords.php b/src/internal/unicodeWords.php
index a962b41..9f2a0c3 100644
--- a/src/internal/unicodeWords.php
+++ b/src/internal/unicodeWords.php
@@ -16,7 +16,8 @@
*
* @private
*
- * @param string The string to inspect.
+ * @param string $string The string to inspect.
+ *
* @return array Returns the words of `string`.
*/
function unicodeWords(string $string): array
diff --git a/tests/Array/DifferenceByTest.php b/tests/Array/DifferenceByTest.php
index ac23860..ac13c82 100644
--- a/tests/Array/DifferenceByTest.php
+++ b/tests/Array/DifferenceByTest.php
@@ -14,7 +14,7 @@
class DifferenceByTest extends TestCase
{
- public function testChunk()
+ public function testDifferenceBy()
{
$this->assertSame([], differenceBy([]));
$this->assertSame([1, 2], differenceBy([1, 2], [3, 4]));
diff --git a/tests/Array/DropWhileTest.php b/tests/Array/DropWhileTest.php
index 997f761..50bef5a 100644
--- a/tests/Array/DropWhileTest.php
+++ b/tests/Array/DropWhileTest.php
@@ -25,5 +25,25 @@ public function testDropWhile()
$this->assertSame([['user' => 'pebbles', 'active' => false]], dropWhile($users, function ($user) {
return $user['active'];
}));
+
+ $lines = [
+ 'Processing report:',
+ 'Processed: 1',
+ 'Successful: 1',
+ '',
+ '',
+ ];
+
+ $lines = dropWhile($lines, static function ($x) {
+ return trim((string) $x) !== '';
+ });
+
+ self::assertEquals(['', ''], $lines);
+
+ $lines = dropWhile($lines, static function ($x) {
+ return trim((string) $x) === '';
+ });
+
+ self::assertEmpty($lines);
}
}
diff --git a/tests/Array/FlattenTest.php b/tests/Array/FlattenTest.php
index 6e93890..3c28d78 100644
--- a/tests/Array/FlattenTest.php
+++ b/tests/Array/FlattenTest.php
@@ -17,5 +17,7 @@ class FlattenTest extends TestCase
public function testFlatten()
{
$this->assertSame([1, 2, [3, [4]], 5], flatten([1, [2, [3, [4]], 5]]));
+
+ $this->assertSame([1, 2, 3, 4, 5, 6], flatten([[1, 2, 3], [], [4, 5, 6]]));
}
}
diff --git a/tests/Array/IntersectionWithTest.php b/tests/Array/IntersectionWithTest.php
index fc73fa0..d8da175 100644
--- a/tests/Array/IntersectionWithTest.php
+++ b/tests/Array/IntersectionWithTest.php
@@ -19,7 +19,7 @@ public function testIntersectionWith()
$objects = [['x' => 1, 'y' => 2], ['x' => 2, 'y' => 1]];
$others = [['x' => 1, 'y' => 1], ['x' => 1, 'y' => 2]];
- $this->assertSame([['x' => 1, 'y' => 2]], intersectionWith($objects, $others, '_::isEqual'));
+ $this->assertSame([['x' => 1, 'y' => 2]], intersectionWith($objects, $others, '_\isEqual'));
$this->assertSame([['x' => 1, 'y' => 2]], intersectionWith($objects, $others));
}
}
diff --git a/tests/Collection/CountByTest.php b/tests/Collection/CountByTest.php
index c2d3bd2..0f7d329 100644
--- a/tests/Collection/CountByTest.php
+++ b/tests/Collection/CountByTest.php
@@ -19,4 +19,4 @@ public function testCountBy()
$this->assertSame(['6' => 2, '4' => 1], countBy([6.1, 4.2, 6.3], 'floor'));
$this->assertSame(['3' => 2, '5' => 1], countBy(['one', 'two', 'three'], 'strlen'));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/EachRightTest.php b/tests/Collection/EachRightTest.php
index ed62bca..ee68693 100644
--- a/tests/Collection/EachRightTest.php
+++ b/tests/Collection/EachRightTest.php
@@ -28,4 +28,4 @@ public function testForEachRight()
});
$this->assertSame([2 => true, 1 => true], $test);
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/EveryTest.php b/tests/Collection/EveryTest.php
index 37a3f07..bb118eb 100644
--- a/tests/Collection/EveryTest.php
+++ b/tests/Collection/EveryTest.php
@@ -16,7 +16,9 @@ class EveryTest extends TestCase
{
public function testEvery()
{
- $this->assertFalse(every([true, 1, null, 'yes'], function ($value) { return is_bool($value); }));
+ $this->assertFalse(every([true, 1, null, 'yes'], function ($value) {
+ return is_bool($value);
+ }));
$users = [
['user' => 'barney', 'age' => 36, 'active' => false],
@@ -32,4 +34,4 @@ public function testEvery()
// The `property` iteratee shorthand.
$this->assertFalse(every($users, 'active'));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/FilterTest.php b/tests/Collection/FilterTest.php
index e590053..0adcc8c 100644
--- a/tests/Collection/FilterTest.php
+++ b/tests/Collection/FilterTest.php
@@ -21,7 +21,9 @@ public function testFilter()
['user' => 'fred', 'age' => 40, 'active' => false],
];
- $this->assertSame([['user' => 'fred', 'age' => 40, 'active' => false]], filter($users, function ($o) { return !$o['active']; }));
+ $this->assertSame([['user' => 'fred', 'age' => 40, 'active' => false]], filter($users, function ($o) {
+ return !$o['active'];
+ }));
// The `matches` iteratee shorthand.
$this->assertSame([['user' => 'barney', 'age' => 36, 'active' => true]], filter($users, ['age' => 36, 'active' => true]));
@@ -32,4 +34,4 @@ public function testFilter()
// The `property` iteratee shorthand.
$this->assertSame([['user' => 'barney', 'age' => 36, 'active' => true]], filter($users, 'active'));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/FindLastTest.php b/tests/Collection/FindLastTest.php
index 0ee7a88..f018a06 100644
--- a/tests/Collection/FindLastTest.php
+++ b/tests/Collection/FindLastTest.php
@@ -16,6 +16,8 @@ class FindLastTest extends TestCase
{
public function testFindLast()
{
- $this->assertSame(3, findLast([1, 2, 3, 4], function ($n) { return $n % 2 == 1; }));
+ $this->assertSame(3, findLast([1, 2, 3, 4], function ($n) {
+ return $n % 2 == 1;
+ }));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/FindTest.php b/tests/Collection/FindTest.php
index 5845e64..7d28e6d 100644
--- a/tests/Collection/FindTest.php
+++ b/tests/Collection/FindTest.php
@@ -22,7 +22,9 @@ public function testFind()
['user' => 'pebbles', 'age' => 1, 'active' => true],
];
- $this->assertSame(['user' => 'barney', 'age' => 36, 'active' => true], find($users, function ($o) { return $o['age'] < 40; }));
+ $this->assertSame(['user' => 'barney', 'age' => 36, 'active' => true], find($users, function ($o) {
+ return $o['age'] < 40;
+ }));
// The `matches` iteratee shorthand.
$this->assertSame(['user' => 'pebbles', 'age' => 1, 'active' => true], find($users, ['age' => 1, 'active' => true]));
@@ -33,4 +35,4 @@ public function testFind()
// The `property` iteratee shorthand.
$this->assertSame(['user' => 'barney', 'age' => 36, 'active' => true], find($users, 'active'));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/FlatMapDeepTest.php b/tests/Collection/FlatMapDeepTest.php
index a000dcb..5a99382 100644
--- a/tests/Collection/FlatMapDeepTest.php
+++ b/tests/Collection/FlatMapDeepTest.php
@@ -22,4 +22,4 @@ public function testFlatMapDeep()
$this->assertSame([1, 1, 2, 2], flatMapDeep([1, 2], $duplicate));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/FlatMapDepthTest.php b/tests/Collection/FlatMapDepthTest.php
index f4897de..0cfea01 100644
--- a/tests/Collection/FlatMapDepthTest.php
+++ b/tests/Collection/FlatMapDepthTest.php
@@ -22,4 +22,4 @@ public function testFlatMapDepth()
$this->assertSame([[1, 1], [2, 2]], flatMapDepth([1, 2], $duplicate, 2));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/FlatMapTest.php b/tests/Collection/FlatMapTest.php
index 93285c7..17bbcd6 100644
--- a/tests/Collection/FlatMapTest.php
+++ b/tests/Collection/FlatMapTest.php
@@ -22,4 +22,4 @@ public function testFlatMap()
$this->assertSame([1, 1, 2, 2], flatMap([1, 2], $duplicate));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/GroupByTest.php b/tests/Collection/GroupByTest.php
index ff7b91f..78cf4e7 100644
--- a/tests/Collection/GroupByTest.php
+++ b/tests/Collection/GroupByTest.php
@@ -19,4 +19,4 @@ public function testCountBy()
$this->assertSame(['6' => [6.1, 6.3], '4' => [4.2]], groupBy([6.1, 4.2, 6.3], 'floor'));
$this->assertSame(['3' => ['one', 'two'], '5' => ['three']], groupBy(['one', 'two', 'three'], 'strlen'));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/InvokeMapTest.php b/tests/Collection/InvokeMapTest.php
index fddc83b..d1e4e11 100644
--- a/tests/Collection/InvokeMapTest.php
+++ b/tests/Collection/InvokeMapTest.php
@@ -16,18 +16,27 @@ class InvokeMapTest extends TestCase
{
public function testInvokeMap()
{
- $this->assertSame([[1, 5, 7], [1, 2, 3]], invokeMap([[5, 1, 7], [3, 2, 1]], function($result) { sort($result); return $result;}));
+ $this->assertSame([[1, 5, 7], [1, 2, 3]], invokeMap([[5, 1, 7], [3, 2, 1]], function ($result) {
+ sort($result);
+ return $result;
+ }));
$this->assertSame([['1', '2', '3'], ['4', '5', '6']], invokeMap([123, 456], 'str_split'));
$users = [
- new class () {
- public function getCount() { return 12; }
+ new class() {
+ public function getCount()
+ {
+ return 12;
+ }
},
- new class () {
- public function getCount() { return 24; }
+ new class() {
+ public function getCount()
+ {
+ return 24;
+ }
}
];
$this->assertEquals([12, 24], invokeMap($users, 'getCount'));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/KeyByTest.php b/tests/Collection/KeyByTest.php
index 5dee637..3ca8fc8 100644
--- a/tests/Collection/KeyByTest.php
+++ b/tests/Collection/KeyByTest.php
@@ -21,7 +21,9 @@ public function testKeyBy()
['direction' => 'right', 'code' => 100],
];
- $this->assertSame(['a' => ['direction' => 'left', 'code' => 97], 'd' => ['direction' => 'right', 'code' => 100]], keyBy($array, function ($o) { return \chr($o['code']); }));
+ $this->assertSame(['a' => ['direction' => 'left', 'code' => 97], 'd' => ['direction' => 'right', 'code' => 100]], keyBy($array, function ($o) {
+ return \chr($o['code']);
+ }));
$this->assertSame(['left' => ['direction' => 'left', 'code' => 97], 'right' => ['direction' => 'right', 'code' => 100]], keyBy($array, 'direction'));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/OrderByTest.php b/tests/Collection/OrderByTest.php
index 35b577a..1164c0d 100644
--- a/tests/Collection/OrderByTest.php
+++ b/tests/Collection/OrderByTest.php
@@ -25,4 +25,4 @@ public function testOrderBy()
$this->assertSame([['user' => 'barney', 'age' => 36], ['user' => 'barney', 'age' => 34], ['user' => 'fred', 'age' => 48], ['user' => 'fred', 'age' => 40]], orderBy($users, ['user', 'age'], ['asc', 'desc']));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/PartitionTest.php b/tests/Collection/PartitionTest.php
index 75a022b..7c228ee 100644
--- a/tests/Collection/PartitionTest.php
+++ b/tests/Collection/PartitionTest.php
@@ -32,6 +32,8 @@ public function testPartition()
],
];
- $this->assertSame($result, partition($users, function ($user) { return $user['active']; }));
+ $this->assertSame($result, partition($users, function ($user) {
+ return $user['active'];
+ }));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/ReduceRightTest.php b/tests/Collection/ReduceRightTest.php
index 2863529..905fafd 100644
--- a/tests/Collection/ReduceRightTest.php
+++ b/tests/Collection/ReduceRightTest.php
@@ -17,6 +17,8 @@ class ReduceRightTest extends TestCase
public function testReduceRight()
{
$array = [[0, 1], [2, 3], [4, 5]];
- $this->assertSame([4, 5, 2, 3, 0, 1], reduceRight($array, function ($flattened, $other) { return \array_merge($flattened, $other); }, []));
+ $this->assertSame([4, 5, 2, 3, 0, 1], reduceRight($array, function ($flattened, $other) {
+ return \array_merge($flattened, $other);
+ }, []));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/ReduceTest.php b/tests/Collection/ReduceTest.php
index b987bb8..75e38e9 100644
--- a/tests/Collection/ReduceTest.php
+++ b/tests/Collection/ReduceTest.php
@@ -16,7 +16,9 @@ class ReduceTest extends TestCase
{
public function testReduce()
{
- $this->assertSame(3, reduce([1, 2], function ($sum, $n) { return $sum + $n; }, 0));
+ $this->assertSame(3, reduce([1, 2], function ($sum, $n) {
+ return $sum + $n;
+ }, 0));
$this->assertSame(['1' => ['a', 'c'], '2' => ['b']], reduce(['a' => 1, 'b' => 2, 'c' => 1], function ($result, $value, $key) {
if (!isset($result[$value])) {
$result[$value] = [];
@@ -26,4 +28,4 @@ public function testReduce()
return $result;
}, []));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/RejectTest.php b/tests/Collection/RejectTest.php
index e340c37..bbfe2e2 100644
--- a/tests/Collection/RejectTest.php
+++ b/tests/Collection/RejectTest.php
@@ -23,4 +23,4 @@ public function testReject()
$this->assertSame([['user' => 'fred', 'active' => false]], reject($users, 'active'));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/SampleSizeTest.php b/tests/Collection/SampleSizeTest.php
index 128d581..b00bc98 100644
--- a/tests/Collection/SampleSizeTest.php
+++ b/tests/Collection/SampleSizeTest.php
@@ -22,4 +22,4 @@ public function testSampleSize()
$this->assertCount(3, sampleSize([1, 2, 3], 4));
$this->assertSame([1, 2, 3], sampleSize([1, 2, 3], 4));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/SampleTest.php b/tests/Collection/SampleTest.php
index 5358837..3730214 100644
--- a/tests/Collection/SampleTest.php
+++ b/tests/Collection/SampleTest.php
@@ -18,4 +18,4 @@ public function testSample()
{
$this->assertContains(sample([1, 2, 3, 4]), [1, 2, 3, 4]);
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/ShuffleTest.php b/tests/Collection/ShuffleTest.php
index 18890b6..76e48c7 100644
--- a/tests/Collection/ShuffleTest.php
+++ b/tests/Collection/ShuffleTest.php
@@ -16,7 +16,8 @@ class ShuffleTest extends TestCase
{
public function testShuffle()
{
- $this->assertNotSame([1, 2, 3, 4], shuffle([1, 2, 3, 4]));
- $this->assertSame([], \array_diff([1, 2, 3, 4], shuffle([1, 2, 3, 4])));
+ $arr = range(1, 10);
+ $this->assertNotSame($arr, shuffle($arr));
+ $this->assertSame([], \array_diff($arr, shuffle($arr)));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/SizeTest.php b/tests/Collection/SizeTest.php
index 9ec5eb6..b750e29 100644
--- a/tests/Collection/SizeTest.php
+++ b/tests/Collection/SizeTest.php
@@ -17,8 +17,7 @@ class SizeTest extends TestCase
public function testSize()
{
$this->assertSame(3, size([1, 2, 3]));
- $this->assertSame(2, size(new class
- {
+ $this->assertSame(2, size(new class {
public $a = 1;
public $b = 2;
@@ -26,13 +25,16 @@ public function testSize()
private $c = 3;
}));
- $this->assertSame(12, size(new class implements \Countable
- {
- public function count() { return 12; }
+ $this->assertSame(12, size(new class implements \Countable {
+ #[\ReturnTypeWillChange]
+ public function count()
+ {
+ return 12;
+ }
}));
$this->assertSame(4, size(new \ArrayIterator([1, 2, 3, 4])));
$this->assertSame(7, size('pebbles'));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Collection/SomeTest.php b/tests/Collection/SomeTest.php
index bead49c..b8c0b99 100644
--- a/tests/Collection/SomeTest.php
+++ b/tests/Collection/SomeTest.php
@@ -21,9 +21,11 @@ public function testSome()
['user' => 'fred', 'active' => false],
];
- $this->assertTrue(some([null, 0, 'yes', false], function ($value) { return \is_bool($value); }));
+ $this->assertTrue(some([null, 0, 'yes', false], function ($value) {
+ return \is_bool($value);
+ }));
$this->assertFalse(some($users, ['user' => 'barney', 'active' => false]));
$this->assertTrue(some($users, ['active', false]));
$this->assertTrue(some($users, 'active'));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Function/AfterTest.php b/tests/Function/AfterTest.php
new file mode 100644
index 0000000..ed0c6bc
--- /dev/null
+++ b/tests/Function/AfterTest.php
@@ -0,0 +1,50 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use function _\after;
+use PHPUnit\Framework\TestCase;
+
+class AfterTest extends TestCase
+{
+ public function testAfter()
+ {
+ $counter = 0;
+
+ $after = after(12, function () use (&$counter) {
+ $counter++;
+
+ return $counter;
+ });
+
+ for ($i = 0; $i < 12; $i++) {
+ $after();
+ }
+
+ $this->assertSame(1, $counter);
+ }
+
+ public function testAfterNotCalled()
+ {
+ $counter = 0;
+
+ $after = after(12, function () use (&$counter) {
+ $counter++;
+
+ return $counter;
+ });
+
+ for ($i = 0; $i < 10; $i++) {
+ $after();
+ }
+
+ $this->assertSame(0, $counter);
+ }
+}
diff --git a/tests/Function/AryTest.php b/tests/Function/AryTest.php
new file mode 100644
index 0000000..ef9ca60
--- /dev/null
+++ b/tests/Function/AryTest.php
@@ -0,0 +1,22 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use function _\ary;
+use function _\map;
+use PHPUnit\Framework\TestCase;
+
+class AryTest extends TestCase
+{
+ public function testAry()
+ {
+ $this->assertSame([6, 8, 10], map(['6', '8', '10'], ary('intval', 1)));
+ }
+}
diff --git a/tests/Function/BeforeTest.php b/tests/Function/BeforeTest.php
new file mode 100644
index 0000000..f43a968
--- /dev/null
+++ b/tests/Function/BeforeTest.php
@@ -0,0 +1,47 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use function _\before;
+use function _\map;
+use function _\uniqBy;
+use PHPUnit\Framework\TestCase;
+
+class BeforeTest extends TestCase
+{
+ public function testBefore()
+ {
+ $counter = 0;
+ $func = before(5, function () use (&$counter) {
+ $counter++;
+
+ return $counter;
+ });
+
+ for ($i = 0; $i < 20; $i++) {
+ $func();
+ }
+
+ $this->assertSame(4, $counter);
+ $this->assertSame(4, $func());
+ }
+
+ public function testBeforeMap()
+ {
+ $users = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ $result = uniqBy(map($users, before(5, function (int $id) {
+ return [
+ 'id' => $id
+ ];
+ })), 'id');
+
+ $this->assertSame([['id' => 1],['id' => 2],['id' => 3],['id' => 4]], $result);
+ }
+}
diff --git a/tests/Function/BindKeyTest.php b/tests/Function/BindKeyTest.php
new file mode 100644
index 0000000..7cfcc50
--- /dev/null
+++ b/tests/Function/BindKeyTest.php
@@ -0,0 +1,32 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use PHPUnit\Framework\TestCase;
+use function _\bindKey;
+
+class BindKeyTest extends TestCase
+{
+ public function testBindKey()
+ {
+ $object = new class {
+ private $user = 'fred';
+
+ public function greet($greeting, $punctuation)
+ {
+ return $greeting.' '.$this->user.$punctuation;
+ }
+ };
+
+ $bound = bindKey($object, 'greet', 'hi');
+
+ $this->assertSame('hi fred!', $bound('!'));
+ }
+}
diff --git a/tests/Function/BindTest.php b/tests/Function/BindTest.php
new file mode 100644
index 0000000..a99a4f9
--- /dev/null
+++ b/tests/Function/BindTest.php
@@ -0,0 +1,39 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use PHPUnit\Framework\TestCase;
+use function _\bind;
+
+class BindTest extends TestCase
+{
+ public function testBind()
+ {
+ $object = new class {
+ public $user = 'fred';
+
+ private $age = 54;
+ };
+
+ $greet = function ($greeting, $punctuation) {
+ return $greeting.' '.$this->user.$punctuation;
+ };
+
+ $bound = bind($greet, $object, 'hi');
+
+ $this->assertSame('hi fred!', $bound('!'));
+
+ $bound = bind(function ($prefix, $suffix) {
+ return $prefix.' '.$this->age.' '.$suffix;
+ }, $object, 'I\'m');
+
+ $this->assertSame('I\'m 54 years', $bound('years'));
+ }
+}
diff --git a/tests/Function/CurryTest.php b/tests/Function/CurryTest.php
new file mode 100644
index 0000000..a267362
--- /dev/null
+++ b/tests/Function/CurryTest.php
@@ -0,0 +1,31 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use PHPUnit\Framework\TestCase;
+use function _\curry;
+
+class CurryTest extends TestCase
+{
+ public function testCurry()
+ {
+ $abc = function ($a, $b, $c = null) {
+ return [$a, $b, $c];
+ };
+
+ $curried = curry($abc);
+
+ $this->assertSame([1, 2, 3], $curried(1)(2)(3));
+ $this->assertSame([1, 2, 3], $curried(1, 2)(3));
+ $this->assertSame([1, 2, 3], $curried(1, 2, 3));
+ $this->assertSame([1, 2, null], curry($abc, 2)(1)(2));
+ $this->assertSame([1, 2, 3], $curried(1)(_, 3)(2));
+ }
+}
diff --git a/tests/Function/DelayTest.php b/tests/Function/DelayTest.php
new file mode 100644
index 0000000..65e1465
--- /dev/null
+++ b/tests/Function/DelayTest.php
@@ -0,0 +1,28 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use function _\delay;
+use PHPUnit\Framework\TestCase;
+
+class DelayTest extends TestCase
+{
+ public function testDelay()
+ {
+ $a = 1;
+ $time = microtime(true);
+ delay(function ($increment) use (&$a) {
+ $a += $increment;
+ }, 20, 2);
+
+ $this->assertSame(3, $a);
+ $this->assertTrue(((microtime(true) - $time) * 1000) > 20);
+ }
+}
diff --git a/tests/Function/FlipTest.php b/tests/Function/FlipTest.php
new file mode 100644
index 0000000..2e7ef83
--- /dev/null
+++ b/tests/Function/FlipTest.php
@@ -0,0 +1,25 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use PHPUnit\Framework\TestCase;
+use function _\flip;
+
+class FlipTest extends TestCase
+{
+ public function testFlip()
+ {
+ $flipped = flip(function () {
+ return func_get_args();
+ });
+
+ $this->assertSame(['d', 'c', 'b', 'a'], $flipped('a', 'b', 'c', 'd'));
+ }
+}
diff --git a/tests/Function/OnceTest.php b/tests/Function/OnceTest.php
new file mode 100644
index 0000000..96e057e
--- /dev/null
+++ b/tests/Function/OnceTest.php
@@ -0,0 +1,30 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use PHPUnit\Framework\TestCase;
+use function _\once;
+
+class OnceTest extends TestCase
+{
+ public function testOnce()
+ {
+ $counter = 0;
+
+ $func = once(function () use (&$counter) {
+ $counter++;
+ });
+
+ $func();
+ $func();
+
+ $this->assertSame(1, $counter);
+ }
+}
diff --git a/tests/Function/OverArgsTest.php b/tests/Function/OverArgsTest.php
new file mode 100644
index 0000000..197fea6
--- /dev/null
+++ b/tests/Function/OverArgsTest.php
@@ -0,0 +1,37 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use PHPUnit\Framework\TestCase;
+use function _\overArgs;
+
+class OverArgsTest extends TestCase
+{
+ public function testOverArgs()
+ {
+ function doubled($n)
+ {
+ return $n * 2;
+ }
+
+ function square($n)
+ {
+ return $n * $n;
+ }
+
+ $func = overArgs(function ($x, $y) {
+ return [$x, $y];
+ }, ['square', 'doubled']);
+
+ $this->assertSame([81, 6], $func(9, 3));
+
+ $this->assertSame([100, 10], $func(10, 5));
+ }
+}
diff --git a/tests/Function/PartialTest.php b/tests/Function/PartialTest.php
new file mode 100644
index 0000000..2a2c8c1
--- /dev/null
+++ b/tests/Function/PartialTest.php
@@ -0,0 +1,26 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use PHPUnit\Framework\TestCase;
+use function _\partial;
+
+class PartialTest extends TestCase
+{
+ public function testPartial()
+ {
+ $greet = function ($greeting, $name) {
+ return $greeting.' '.$name;
+ };
+
+ $sayHelloTo = partial($greet, 'hello');
+ $this->assertSame('hello fred', $sayHelloTo('fred'));
+ }
+}
diff --git a/tests/Function/RestTest.php b/tests/Function/RestTest.php
new file mode 100644
index 0000000..58ad8d0
--- /dev/null
+++ b/tests/Function/RestTest.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use PHPUnit\Framework\TestCase;
+use function _\initial;
+use function _\last;
+use function _\rest;
+use function _\size;
+
+class RestTest extends TestCase
+{
+ public function testRest()
+ {
+ $say = rest(function ($what, $names) {
+ return $what.' '.implode(', ', initial($names)).
+ (size($names) > 1 ? ', & ' : '').last($names);
+ });
+
+ $this->assertSame('hello fred, barney, & pebbles', $say('hello', 'fred', 'barney', 'pebbles'));
+ }
+}
diff --git a/tests/Function/SpreadTest.php b/tests/Function/SpreadTest.php
new file mode 100644
index 0000000..b7b6cdb
--- /dev/null
+++ b/tests/Function/SpreadTest.php
@@ -0,0 +1,25 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use PHPUnit\Framework\TestCase;
+use function _\spread;
+
+class SpreadTest extends TestCase
+{
+ public function testSpread()
+ {
+ $say = spread(function ($who, $what) {
+ return $who.' says '.$what;
+ });
+
+ $this->assertSame('fred says hello', $say(['fred', 'hello']));
+ }
+}
diff --git a/tests/Function/UnaryTest.php b/tests/Function/UnaryTest.php
new file mode 100644
index 0000000..b68c439
--- /dev/null
+++ b/tests/Function/UnaryTest.php
@@ -0,0 +1,22 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use function _\map;
+use function _\unary;
+use PHPUnit\Framework\TestCase;
+
+class UnaryTest extends TestCase
+{
+ public function testUnary()
+ {
+ $this->assertSame([6, 8, 10], map(['6', '8', '10'], unary('intval')));
+ }
+}
diff --git a/tests/Function/WrapTest.php b/tests/Function/WrapTest.php
new file mode 100644
index 0000000..008485f
--- /dev/null
+++ b/tests/Function/WrapTest.php
@@ -0,0 +1,25 @@
+
+ * @copyright Copyright (c) 2017
+ */
+
+use function _\wrap;
+use PHPUnit\Framework\TestCase;
+
+class WrapTest extends TestCase
+{
+ public function testWrap()
+ {
+ $p = wrap('_\escape', function ($func, $text) {
+ return '' . $func($text) . '
'; + }); + + $this->assertSame('fred, barney, & pebbles
', $p('fred, barney, & pebbles')); + } +} diff --git a/tests/LodashTest.php b/tests/LodashTest.php new file mode 100644 index 0000000..fae6947 --- /dev/null +++ b/tests/LodashTest.php @@ -0,0 +1,25 @@ + 'barney', 'age' => 36], + ['user' => 'fred', 'age' => 40], + ['user' => 'pebbles', 'age' => 1], + ]; + + $youngest = __($users) + ->sortBy('age') + ->map(function ($o) { + return $o['user'] . ' is ' . $o['age']; + }) + ->head() + ->value(); + + $this->assertSame('pebbles is 1', $youngest); + } +} diff --git a/tests/Math/MaxByTest.php b/tests/Math/MaxByTest.php index 97fe5c6..77deba1 100644 --- a/tests/Math/MaxByTest.php +++ b/tests/Math/MaxByTest.php @@ -17,7 +17,9 @@ class MaxByTest extends TestCase public function testMax() { $objects = [['n' => 1], ['n' => 2]]; - $this->assertSame(['n' => 2], maxBy($objects, function ($o) { return $o['n']; })); + $this->assertSame(['n' => 2], maxBy($objects, function ($o) { + return $o['n']; + })); $this->assertSame(['n' => 2], maxBy($objects, 'n')); } } diff --git a/tests/Object/GetTest.php b/tests/Object/GetTest.php new file mode 100644 index 0000000..4fb02bb --- /dev/null +++ b/tests/Object/GetTest.php @@ -0,0 +1,49 @@ + + * @copyright Copyright (c) 2019 + */ + +use function _\get; +use PHPUnit\Framework\TestCase; + +class GetTest extends TestCase +{ + public function testGetArray() + { + $actualValue1 = "data"; + $sampleArray = ["key1" => ["key2" => ["key3" => $actualValue1, "key4" => ""]]]; + $defaultValue = "default"; + $this->assertSame($actualValue1, get($sampleArray, "key1.key2.key3", "default"), "Default To method 1 failed"); + $this->assertSame($defaultValue, get($sampleArray, "key2.key2.key3", $defaultValue), "Default To method 2 failed"); + $this->assertSame($actualValue1, get($sampleArray, ["key1","key2","key3"], $defaultValue), "Default To method 3 failed"); + $this->assertSame($defaultValue, get($sampleArray, "key1.key2.key3.key4", $defaultValue), "Default To method 4 failed"); + $this->assertSame($defaultValue, get($sampleArray, "key1.key2.key3.key4", $defaultValue), "Default To method 5 failed"); + $this->assertSame($defaultValue, get($sampleArray, ["key1","key2","key3","key4"], $defaultValue), "Default To method 6 failed"); + $this->assertSame("", get($sampleArray, "key1.key2.key4", $defaultValue), "Default To method 8 failed"); + + $this->assertSame($sampleArray["key1"]["key2"], _::get($sampleArray, "key1.key2", $defaultValue), "Default To method 9 failed"); + $this->assertSame($defaultValue, _::get($sampleArray, "key1.key3", $defaultValue), "Default To method 10 failed"); + } + + public function testDefaultToObject() + { + $actualValue1 = "data"; + $sampleArray = (object)["key1" => (object)["key2" => (object)["key3" => $actualValue1, "key4" => ""]]]; + $defaultValue = "default"; + $this->assertSame($actualValue1, get($sampleArray, "key1.key2.key3", $defaultValue), "Default To method object 1 failed"); + $this->assertSame($defaultValue, get($sampleArray, "key2.key2.key3", $defaultValue), "Default To method object 2 failed"); + $this->assertSame($actualValue1, get($sampleArray, ["key1","key2","key3"], $defaultValue), "Default To method object 3 failed"); + $this->assertSame($defaultValue, get($sampleArray, "key1.key2.key3.key4", $defaultValue), "Default To method object 4 failed"); + $this->assertSame($defaultValue, get($sampleArray, "key1.key2.key3.key4", $defaultValue), "Default To method object 5 failed"); + $this->assertSame($defaultValue, get($sampleArray, ["key1","key2","key3","key4"], $defaultValue), "Default To method object 6 failed"); + $this->assertSame("", get($sampleArray, "key1.key2.key4", $defaultValue), "Default To method object 8 failed"); + + $this->assertSame($sampleArray->key1->key2, _::get($sampleArray, "key1.key2", $defaultValue), "Default To method object 9 failed"); + $this->assertSame($defaultValue, _::get($sampleArray, "key1.key3", $defaultValue), "Default To method 10 failed"); + } +} diff --git a/tests/Object/PickByTest.php b/tests/Object/PickByTest.php new file mode 100644 index 0000000..5683f57 --- /dev/null +++ b/tests/Object/PickByTest.php @@ -0,0 +1,25 @@ + + * @copyright Copyright (c) 2017 + */ + +use PHPUnit\Framework\TestCase; +use function _\pickBy; + +class PickByTest extends TestCase +{ + public function testPick() + { + $object = (object) ['a' => 1, 'b' => '2', 'c' => 3]; + + $this->assertEquals((object) ['a' => 1, 'c' => 3], pickBy($object, function ($value) { + return \is_int($value); + })); + } +} diff --git a/tests/Object/PickTest.php b/tests/Object/PickTest.php new file mode 100644 index 0000000..3b1f9f4 --- /dev/null +++ b/tests/Object/PickTest.php @@ -0,0 +1,24 @@ + + * @copyright Copyright (c) 2017 + */ + +use PHPUnit\Framework\TestCase; +use function _\pick; + +class PickTest extends TestCase +{ + public function testPick() + { + $object = (object) ['a' => 1, 'b' => '2', 'c' => 3]; + $this->assertEquals((object) ['a' => 1, 'c' => 3], pick($object, ['a', 'c'])); + + $this->assertEquals((object) ['a' => 1], pick($object, 'a')); + } +} diff --git a/tests/Seq/ChainTest.php b/tests/Seq/ChainTest.php new file mode 100644 index 0000000..f647cff --- /dev/null +++ b/tests/Seq/ChainTest.php @@ -0,0 +1,35 @@ + + * @copyright Copyright (c) 2017 + */ + +use function _\chain; +use PHPUnit\Framework\TestCase; + +class ChainTest extends TestCase +{ + public function testChain() + { + $users = [ + ['user' => 'barney', 'age' => 36], + ['user' => 'fred', 'age' => 40], + ['user' => 'pebbles', 'age' => 1], + ]; + + $youngest = chain($users) + ->sortBy('age') + ->map(function ($o) { + return $o['user'] . ' is ' . $o['age']; + }) + ->head() + ->value(); + + $this->assertSame('pebbles is 1', $youngest); + } +} diff --git a/tests/Util/DefaultToTest.php b/tests/Util/DefaultToTest.php new file mode 100644 index 0000000..f428473 --- /dev/null +++ b/tests/Util/DefaultToTest.php @@ -0,0 +1,26 @@ + + * @copyright Copyright (c) 2019 + */ + +use function _\defaultTo; +use PHPUnit\Framework\TestCase; + +class DefaultToTest extends TestCase +{ + public function testDefaultTo() + { + $null = null; + $default = "defaultValue"; + $realValue = "string"; + $this->assertSame($default, defaultTo($null, $default), "DefaultTo 1 failed"); + $this->assertSame($default, defaultTo(NAN, $default), "DefaultTo 2 failed"); + $this->assertSame($realValue, defaultTo($realValue, $default), "DefaultTo 3 failed"); + $this->assertSame("", defaultTo("", $default), "DefaultTo 4 failed"); + } +}Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: