Skip to content

Commit

Permalink
Merge pull request #48 from ace411/v2.x
Browse files Browse the repository at this point in the history
v2.4.0 changes
  • Loading branch information
ace411 authored Sep 3, 2024
2 parents 0dd5e5e + 19323a2 commit 840ee12
Show file tree
Hide file tree
Showing 46 changed files with 1,370 additions and 540 deletions.
4 changes: 4 additions & 0 deletions .php-cs-fixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
[
'@PSR12' => true,
'linebreak_after_opening_tag' => true,
'trailing_comma_in_multiline' => [
'after_heredoc' => false,
'elements' => [],
],
'binary_operator_spaces' => [
'operators' => [
'=>' => 'align',
Expand Down
10 changes: 10 additions & 0 deletions changes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# bingo-functional changes

## v2.4.0

- Added `jsonDecode` and `extract` functions
- Reworked internals of `partition`, `slugify`, and `partitionBy` functions
- Infused `startsWith`, `endsWith`, `contains`, and `truncate` functions with multi-byte string processing capabilities
- Added iteration modes to `filter` and `reject` functions
- Added [ext-eio](https://pecl.php.net/eio)-powered non-blocking file operations for IO monad
- Replaced pattern matching parser in `functional-php/pattern-matching` with custom parser
- Replaced cons matching function calls in `cmatch` with custom parser

## v2.3.0

- Added `keys`, `values`, and `size` functions
Expand Down
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@
}
],
"require": {
"php": "^7 || ^8",
"functional-php/pattern-matching": "^1"
"php": "^7 || ^8"
},
"require-dev": {
"ergebnis/composer-normalize": "^2",
Expand All @@ -79,6 +78,7 @@
},
"suggest": {
"ext-apcu": "In-memory key-value PHP userland store",
"ext-eio": "An interface to the libeio library",
"ext-mbstring": "PHP extension for accurately determining byte-length of strings",
"ext-readline": "An interface to the GNU readline library",
"chemem/bingo-functional-repl": "A simple REPL for the bingo-functional library"
Expand Down Expand Up @@ -111,7 +111,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
"dev-master": "2.x-dev"
}
},
"scripts": {
Expand Down
9 changes: 8 additions & 1 deletion src/Functional/Contains.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,12 @@
*/
function contains(string $haystack, string $needle): bool
{
return !equals(\strpos($haystack, $needle), false);
return !equals(
(
\extension_loaded('mbstring') ?
'\mb_stripos' :
'\stripos'
)($haystack, $needle),
false
);
}
24 changes: 16 additions & 8 deletions src/Functional/EndsWith.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,21 @@
*/
function endsWith(string $haystack, string $needle): bool
{
$strlen = \function_exists('mb_strlen') ?
\mb_strlen($needle, 'utf-8') :
\strlen($needle);
$lmbstr = \extension_loaded('mbstring');
$strlen = (
$lmbstr ?
'\mb_strlen' :
'\strlen'
)($needle);

if (equals($strlen, 0)) {
return false;
}

return equals(\substr($haystack, -$strlen), $needle);
return $strlen > 0 ?
equals(
(
$lmbstr ?
'\mb_substr' :
'\substr'
)($haystack, -$strlen),
$needle
) :
false;
}
17 changes: 13 additions & 4 deletions src/Functional/Filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,30 @@
* filter
* selects list values that conform to a boolean predicate
*
* filter :: (a -> Bool) -> [a] -> [a]
* filter :: (a -> Bool) -> [a] -> Int -> [a]
*
* @param callable $func
* @param array|object $list
* @param int $mode
* @return array|object
* @example
*
* filter(fn ($x) => $x % 2 === 0, range(4, 8))
* => [4, 6, 8]
*/
function filter(callable $func, $list)
function filter(callable $func, $list, int $mode = 0)
{
return fold(
function ($acc, $val, $idx) use ($func) {
if (!$func($val)) {
function ($acc, $val, $idx) use ($func, $mode) {
$filter = equals($mode, ARRAY_FILTER_USE_KEY) ?
$func($idx) :
(
equals($mode, ARRAY_FILTER_USE_BOTH) ?
$func($val, $idx) :
$func($val)
);

if (!$filter) {
if (\is_object($acc)) {
unset($acc->{$idx});
} elseif (\is_array($acc)) {
Expand Down
57 changes: 57 additions & 0 deletions src/Functional/JsonDecode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

/**
* jsonDecode function
*
* @package bingo-functional
* @author Lochemem Bruno Michael
* @license Apache-2.0
*/

declare(strict_types=1);

namespace Chemem\Bingo\Functional;

/**
* jsonDecode
*/
function jsonDecode(...$args)
{
$decoder = \extension_loaded('simdjson') ?
'\simdjson_decode' :
'\json_decode';
$initial = $decoder(...$args);
$options = tail($args);

return fold(
function ($acc, $value, $key) use ($decoder, $options) {
if (
(\is_string($value) && contains($value, '\\"')) ||
\is_iterable($value) ||
\is_object($value)
) {
if (\is_iterable($acc)) {
$acc[$key] = jsonDecode($value, ...$options);
} elseif (\is_object($acc)) {
$acc->{$key} = jsonDecode($value, ...$options);
}
} else {
if (\is_iterable($acc)) {
$acc[$key] = $decoder(
\sprintf('%s', $value),
...$options
) ?? $value;
} elseif (\is_object($acc)) {
$acc->{$key} = $decoder(
\sprintf('%s', $value),
...$options
) ?? $value;
}
}

return $acc;
},
$initial,
\is_iterable($initial) ? [] : new \stdClass()
);
}
15 changes: 4 additions & 11 deletions src/Functional/Partition.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,10 @@
*/
function partition(int $number, $list)
{
$list = _props($list);
$count = size($list);
$list = _props($list);

if ($number < 2 || $count < 2) {
return [$list];
}

$psize = \ceil($count / $number);

return extend(
[\array_slice($list, 0, $psize, true)],
partition($number - 1, dropLeft($list, $psize))
return partitionBy(
(int) \ceil(size($list) / $number),
$list
);
}
32 changes: 23 additions & 9 deletions src/Functional/PartitionBy.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,27 @@
*/
function partitionBy(int $partitionSize, $list)
{
$list = _props($list);

if (equals($partitionSize, 0)) {
return $list;
}

$number = (int) \ceil(size($list) / $partitionSize);

return partition($number, $list);
$list = _props($list);
$counter = 0;
$idx = 0;

return fold(
function (iterable $acc, $value, $key) use (
&$counter,
&$idx,
$partitionSize
) {
$idx++;

$acc[$counter][$key] = $value;

if ($idx > 0 && ($idx % $partitionSize === 0)) {
$counter++;
}

return $acc;
},
$list,
[]
);
}
4 changes: 3 additions & 1 deletion src/Functional/Pluck.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@
*/
function pluck($values, $search, $default = null)
{
$search = \sprintf('%s', $search);

return fold(
function ($acc, $val, $idx) use ($search) {
if ($search == $idx) {
if (equals($search, \sprintf('%s', $idx))) {
$acc = $val;
}

Expand Down
17 changes: 13 additions & 4 deletions src/Functional/Reject.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,30 @@
* reject
* selects list values that do not conform to a boolean predicate
*
* reject :: (a -> Bool) -> [a] -> [a]
* reject :: (a -> Bool) -> [a] -> Int -> [a]
*
* @param callable $func
* @param array|object $list
* @param int $mode
* @return array|object
* @example
*
* reject(fn ($x) => $x % 2 === 0, range(4, 8))
* => [5, 7]
*/
function reject(callable $func, $list)
function reject(callable $func, $list, int $mode = 0)
{
return fold(
function ($acc, $val, $idx) use ($func) {
if ($func($val)) {
function ($acc, $val, $idx) use ($func, $mode) {
$filter = equals($mode, ARRAY_FILTER_USE_KEY) ?
$func($idx) :
(
equals($mode, ARRAY_FILTER_USE_BOTH) ?
$func($val, $idx) :
$func($val)
);

if ($filter) {
if (\is_object($acc)) {
unset($acc->{$idx});
} elseif (\is_array($acc)) {
Expand Down
11 changes: 4 additions & 7 deletions src/Functional/Slugify.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,9 @@
*/
function slugify(string $string): string
{
$slugify = compose(
partial('explode', ' '),
function (array $words) {
return concat('-', ...$words);
}
return preg_replace(
'/(\s){1,}/ix',
'-',
$string
);

return $slugify($string);
}
28 changes: 20 additions & 8 deletions src/Functional/StartsWith.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,25 @@
*/
function startsWith(string $haystack, string $needle): bool
{
$strlen = \function_exists('mb_strlen') ?
\mb_strlen($needle, 'utf-8') :
\strlen($needle);
$lmbstr = \extension_loaded('mbstring');
$strlen = (
$lmbstr ?
'\mb_strlen' :
'\strlen'
)($needle);

if (equals($strlen, 0)) {
return false;
}

return equals(\substr($haystack, 0, $strlen), $needle);
return $strlen > 0 ?
equals(
(
$lmbstr ?
'\mb_substr' :
'\substr'
)(
$haystack,
0,
$strlen
),
$needle
) :
false;
}
29 changes: 21 additions & 8 deletions src/Functional/Truncate.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,28 @@
*/
function truncate(string $string, int $limit): string
{
$strlen = 0;
$strlen += !\function_exists('mb_strlen') ?
\strlen($string) :
\mb_strlen($string, 'utf-8');

$lmbstr = \extension_loaded('mbstring');
$truncate = compose(
partialRight('substr', $limit, 0),
partialRight(partial(concat, '..'), '.')
partialRight(
(
$lmbstr ?
'\mb_substr' :
'\substr'
),
$limit,
0
),
partial('\sprintf', '%s...')
);

return $limit > $strlen ? $string : $truncate($string);
return (
$limit >
(
$lmbstr ?
'\mb_strlen' :
'\strlen'
)($string)
) ?
$string :
$truncate($string);
}
1 change: 1 addition & 0 deletions src/Functional/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
require_once __DIR__ . '/Intersects.php';
require_once __DIR__ . '/Intersperse.php';
require_once __DIR__ . '/IsArrayOf.php';
require_once __DIR__ . '/JsonDecode.php';
require_once __DIR__ . '/K.php';
require_once __DIR__ . '/Keys.php';
require_once __DIR__ . '/Last.php';
Expand Down
Loading

0 comments on commit 840ee12

Please sign in to comment.