diff --git a/README.md b/README.md index d292fc5..dc1714f 100644 --- a/README.md +++ b/README.md @@ -100,13 +100,14 @@ The target can be any expression. It will be passed as the first argument to the #### Built-In Functions -| Function | Description | Example | -|------------|-------------------------------------------------------------|--------------------------------------------------| -| `count` | Returns the number of elements in a list | `foo:list.count:int()` | -| `contains` | Returns whether a list contains a value | `foo:list.contains:bool("bar")` | -| `some` | Returns whether any element matches a [predicate](#lambdas) | `foo:list.some:bool(\|item\| item:int > 5)` | -| `substr` | Returns a substring of a string | `foo:string.substr:string(0, 5)` | -| `take` | Returns the first n elements of a list | `foo:list.take:list(5)` | +| Function | Description | Example | +|------------|------------------------------------------------------------------------|--------------------------------------------------| +| `count` | Returns the number of elements in a list | `foo:list.count:int()` | +| `contains` | Returns whether a list contains a value | `foo:list.contains:bool("bar")` | +| `map` | Returns a new list with the results of applying a [function](#lambdas) | `foo:list.map:list(\|i\| i:int - 2)` | +| `some` | Returns whether any element matches a [predicate](#lambdas) | `foo:list.some:bool(\|item\| item:int > 5)` | +| `substr` | Returns a substring of a string | `foo:string.substr:string(0, 5)` | +| `take` | Returns the first n elements of a list | `foo:list.take:list(5)` | #### Custom Functions diff --git a/src/Scope.php b/src/Scope.php index 188ccbc..f90f420 100644 --- a/src/Scope.php +++ b/src/Scope.php @@ -43,6 +43,7 @@ public function __construct(private readonly array $vars = [], array $funcs = [] 'contains' => self::contains(...), 'count' => self::count(...), 'filter' => self::filter(...), + 'map' => self::map(...), 'some' => self::some(...), 'substr' => substr(...), 'take' => self::take(...), @@ -69,6 +70,19 @@ public function __construct(private readonly array $vars = [], array $funcs = [] } } + /** + * @template K of array-key + * @template From + * @template To + * @param array $items + * @param callable(From): To $f + * @return array + */ + private static function map(array $items, callable $f): array + { + return array_map($f, $items); + } + /** * @template T * @param array $haystack diff --git a/tests/unit/ExpressionTest.php b/tests/unit/ExpressionTest.php index d3bb790..1dc4afa 100644 --- a/tests/unit/ExpressionTest.php +++ b/tests/unit/ExpressionTest.php @@ -135,6 +135,12 @@ public static function evaluateCases(): iterable ['items:list.take:list(3)', new Scope(['items' => []]), []], ['items:list.take:list(0)', new Scope(['items' => ['a', 'b', 'c', 'd', 'e']]), []], ['-myval:int', new Scope(['myval' => 42]), -42], + [ + 'names:list.map:list(|name| name:string === "bar")', + new Scope(['names' => ['foo', 'bar', 'baz']]), + [false, true, false], + ], + ['ints:list.map:list(|i| i:int -2)', new Scope(['ints' => []]), []], ]; foreach ($cases as [$expr, $scope, $expected]) { $expectedStr = (string)Expr::literal($expected);