Skip to content

Commit 6698f30

Browse files
committed
Add create_assoc function
1 parent 8099470 commit 6698f30

File tree

4 files changed

+203
-1
lines changed

4 files changed

+203
-1
lines changed

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"require-dev": {
2121
"phpunit/phpunit": "~6",
2222
"squizlabs/php_codesniffer": "~3.0",
23-
"friendsofphp/php-cs-fixer": "^2.14"
23+
"friendsofphp/php-cs-fixer": "^2.14",
24+
"apantle/hashmapper": "^1.3"
2425
},
2526
"autoload": {
2627
"psr-4": {"Functional\\": "src/Functional"},
@@ -35,6 +36,7 @@
3536
"src/Functional/Concat.php",
3637
"src/Functional/Contains.php",
3738
"src/Functional/Converge.php",
39+
"src/Functional/CreateAssoc.php",
3840
"src/Functional/Curry.php",
3941
"src/Functional/CurryN.php",
4042
"src/Functional/Difference.php",

src/Functional/CreateAssoc.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
/**
3+
* Copyright (C) 2019 by Jesus Franco Martinez <tezcatl@fedoraproject.org>
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
namespace Functional;
24+
25+
/**
26+
* Return a function that applies a set of functions to build an
27+
* associative array from a single input (scalar, object or sequence)
28+
*
29+
* @param array $specs associative array of keys and functions that map to the target
30+
* @param object|null $tameme
31+
* @return callable
32+
*/
33+
function create_assoc(array $specs, $tameme = null): callable
34+
{
35+
return function ($input, $optional = null) use ($specs, $tameme) {
36+
$mecapal = [];
37+
38+
foreach ($specs as $target => $mapper) {
39+
$mecapal[$target] = is_unary($mapper)
40+
? \call_user_func($mapper, $input)
41+
: \call_user_func($mapper, $input, $optional, $tameme)
42+
;
43+
}
44+
45+
return $mecapal;
46+
};
47+
}
48+
49+
/**
50+
* determine if the callable passed expect only one argument
51+
* @param callable $callable
52+
* @return bool
53+
* @throws \ReflectionException
54+
*/
55+
function is_unary($callable)
56+
{
57+
if (!\is_callable($callable)) {
58+
return false;
59+
}
60+
$reflector = new \ReflectionFunction($callable);
61+
return \boolval($reflector->getNumberOfParameters() === 1);
62+
}

src/Functional/Functional.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ final class Functional
5454
*/
5555
const converge = '\Functional\converge';
5656

57+
/**
58+
* @see \Functional\create_assoc
59+
*/
60+
const create_assoc = '\Functional\create_assoc';
61+
5762
/**
5863
* @see \Functional\curry
5964
*/
@@ -169,6 +174,11 @@ final class Functional
169174
*/
170175
const identical = '\Functional\identical';
171176

177+
/**
178+
* @see \Functional\is_unary
179+
*/
180+
const is_unary = '\Functional\is_unary';
181+
172182
/**
173183
* @see \Functional\if_else
174184
*/
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?php
2+
/**
3+
* Copyright (C) 2019 by Jesus Franco Martinez <tezcatl@fedoraproject.org>
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
namespace Functional\Tests;
24+
25+
use Functional\Functional;
26+
27+
use function Functional\create_assoc;
28+
use function Apantle\HashMapper\hashMapper;
29+
30+
class CreateAssocTest extends AbstractTestCase
31+
{
32+
public function testBasicCreateAssoc()
33+
{
34+
$input = new \DateTimeImmutable();
35+
36+
$expected = [
37+
'targetA' => $input,
38+
'targetB' => $input
39+
];
40+
41+
$actual = create_assoc([
42+
'targetA' => Functional::id,
43+
'targetB' => Functional::id,
44+
])($input);
45+
46+
$this->assertEquals($expected, $actual);
47+
$this->assertEquals($input->format('U'), $actual['targetA']->format('U'));
48+
$this->assertEquals($input->format('U'), $actual['targetB']->format('U'));
49+
}
50+
51+
public function testExpectsTameme()
52+
{
53+
$input = [ 1, 2, 3 ];
54+
55+
$expected = [
56+
'targetA' => [ 4 => 1, 5 => 2, 6 => 3 ],
57+
'targetB' => [ 5 => 2 ]
58+
];
59+
60+
$tameme = new class extends \ArrayObject {};
61+
62+
$actual = create_assoc([
63+
'targetA' => function ($member, $input = null, $tameme) {
64+
$build = \array_reduce($member, function ($accum, $num) {
65+
$accum[$num + 3] = $num;
66+
return $accum;
67+
}, []);
68+
69+
$tameme['prev'] = $build;
70+
return $build;
71+
},
72+
'targetB' => function ($member, $input, $tameme) {
73+
$prev = $tameme['prev'];
74+
$build = [];
75+
foreach($prev as $key => $val) {
76+
if($key % 2 !== 0) {
77+
$build[$key] = $val;
78+
}
79+
}
80+
return $build;
81+
}
82+
], $tameme)($input);
83+
84+
$this->assertEquals($expected, $actual);
85+
}
86+
87+
public function testReceivesOptionalArgument()
88+
{
89+
$input = [
90+
'vendor' => 'tzkmx',
91+
'utility' => 'unfold'
92+
];
93+
94+
$expected = [
95+
'vendorName' => 'tzkmx',
96+
'vendorLen' => 5,
97+
'serialized' => 'a:2:{s:6:"vendor";s:5:"tzkmx";s:7:"utility";s:6:"unfold";}',
98+
'utility' => 'unfold',
99+
'utilLen' => 6,
100+
'package' => [ 'tzkmx/unfold' => $input ]
101+
];
102+
103+
$tameme = new class extends \ArrayObject {};
104+
105+
$actual = hashMapper([
106+
'vendor' => [ '...', create_assoc([
107+
'vendorName' => 'strval',
108+
'vendorLen' => 'strlen',
109+
'serialized' => function ($member, $hash, $tameme) {
110+
$tameme['name'] = $member;
111+
return \serialize($hash);
112+
}
113+
], $tameme)
114+
],
115+
'utility' => [ '...', create_assoc([
116+
'utility' => 'strval',
117+
'utilLen' => 'strlen',
118+
'package' => function ($member, $hash, $tameme) {
119+
$name = $tameme['name'];
120+
return [ "$name/$member" => $hash ];
121+
}
122+
], $tameme)
123+
]
124+
])($input);
125+
126+
$this->assertEquals($expected, $actual);
127+
}
128+
}

0 commit comments

Comments
 (0)