Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature - Psalm annotations #93

Merged
merged 11 commits into from
Jul 25, 2023
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,25 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v3

- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
ini-values: error_reporting=-1, display_errors=On, log_errors_max_len=0
coverage: none
tools: none
tools: composer

# Install dependencies and handle caching in one go.
# @link https://github.com/marketplace/actions/install-composer-dependencies
- name: "Install Composer dependencies (PHP < 8.1)"
if: ${{ matrix.php < '8.1' }}
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"

- name: "Install Composer dependencies (PHP 8.1)"
if: ${{ matrix.php >= '8.1' }}
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
composer-options: --ignore-platform-reqs

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ $res = $rewindableMap(func\operator('*', 3), [1, 2, 3]);
$res = iter\callRewindable('iter\\map', func\operator('*', 3), [1, 2, 3]);
```

The above functions are only useful for your own generators though, for the
`iter` generators rewindable variants are directly provided with an
The above functions are only useful for your own iterators though; for the
`iter` iterators, rewindable variants are directly provided with an
`iter\rewindable` prefix:

$res = iter\rewindable\map(func\operator('*', 3), [1, 2, 3]);
Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
"php": ">=7.1"
},
"require-dev": {
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"vimeo/psalm": "^4.18 || ^5.13",
"phpstan/phpstan": "^1.4"
},
"autoload": {
"files": [
Expand Down
18 changes: 18 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<psalm
errorLevel="4"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedBaselineEntry="true"
findUnusedCode="false"
>
<projectFiles>
<directory name="src" />
<directory name="test" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a phpstan config as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike psalm, phpstan does not require an explicit config. A config can be added to be explicit about things if so desired.

97 changes: 94 additions & 3 deletions src/iter.func.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

namespace iter\func;

/**
* Returns a callable which extracts a given index from an array.
*
* Example:
*
* $array = [ 'foo' => 42 ];
*
* func\index('foo')($array);
* => 42
*
*
* @param array-key $index
*
* @return callable(array):mixed
*/
function index($index) {
return function($array) use ($index) {
return $array[$index];
Expand Down Expand Up @@ -31,9 +46,9 @@ function index($index) {
* $getIndexFooBarBaz($array)
* => 42
*
* @param mixed[] ...$indices Path of indices
* @param array-key ...$indices Path of indices
*
* @return callable
* @return callable(array):mixed
*/
function nested_index(...$indices) {
return function($array) use ($indices) {
Expand All @@ -45,18 +60,73 @@ function nested_index(...$indices) {
};
}

/**
* Returns a callable which returns a given property from an object.
*
* Example:
*
* $object = new \stdClass();
* $object->foo = 42;
*
* func\property('foo')($object);
* => 42
*
* @param string $propertyName
*
* @return callable(object):mixed
*/
function property($propertyName) {
return function($object) use ($propertyName) {
return $object->$propertyName;
};
}

/**
* Returns a callable which calls a method on an object, optionally with some
* provided arguments.
*
* Example:
*
* class Foo {
* public function bar($a, $b) {
* return $a + $b;
* }
* }
*
* $foo = new Foo();
*
* func\method('bar', [1, 2])($foo);
* => 3
*
* @param string $methodName
* @param mixed[] $args
*
* @return callable(object):mixed
*/
function method($methodName, $args = []) {
return function($object) use ($methodName, $args) {
return $object->$methodName(...$args);
};
}

/**
* Returns a callable which applies the specified operator to the argument.
*
* Examples:
*
* $addOne = func\operator('+', 1);
* $addOne(41);
* => 42
*
* $modulo2 = func\operator('%', 2);
* $modulo2(42);
* => 0
*
* @param string $operator
* @param mixed $arg The right-hand argument for the operator
*
* @return callable
*/
function operator($operator, $arg = null) {
$functions = [
'instanceof' => function($a, $b) { return $a instanceof $b; },
Expand Down Expand Up @@ -99,8 +169,29 @@ function operator($operator, $arg = null) {
}
}

/**
* Takes a callable which returns a boolean, and returns another function that
* returns the opposite for all values.
*
* Example:
* $isEven = function($x) {
* return $x % 2 === 0;
* };
*
* $isOdd = func\not($isEven);
*
* $isEven(42);
* => true
*
* $isOdd(42);
* => false
*
* @param callable(...mixed):bool $function
*
* @return callable(...mixed):bool
*/
function not($function) {
return function(...$args) use ($function) {
return !$function(...$args);
};
}
}
Loading