Skip to content

Commit

Permalink
Higher order functions for comparison (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
lstrojny committed May 13, 2016
1 parent 7d21518 commit afacc8e
Show file tree
Hide file tree
Showing 16 changed files with 336 additions and 8 deletions.
3 changes: 3 additions & 0 deletions composer.json
Expand Up @@ -26,6 +26,8 @@
"src/Functional/Average.php",
"src/Functional/Capture.php",
"src/Functional/ConstFunction.php",
"src/Functional/CompareOn.php",
"src/Functional/CompareObjectHashOn.php",
"src/Functional/Compose.php",
"src/Functional/Contains.php",
"src/Functional/Difference.php",
Expand All @@ -48,6 +50,7 @@
"src/Functional/InvokeFirst.php",
"src/Functional/InvokeIf.php",
"src/Functional/InvokeLast.php",
"src/Functional/Invoker.php",
"src/Functional/Last.php",
"src/Functional/LastIndexOf.php",
"src/Functional/Map.php",
Expand Down
3 changes: 2 additions & 1 deletion docs/00-index.md
Expand Up @@ -5,7 +5,8 @@
- [Chapter 4: function functions](04-function-functions.md)
- [Chapter 5: mathematical functions](05-mathematical-functions.md)
- [Chapter 6: transformation functions](06-transformation-functions.md)
- [Chapter 7: miscellaneous](07-miscellaneous.md)
- [Chapter 7: comparator](07-comparator.md)
- [Chapter 8: miscellaneous](08-miscellaneous.md)

# Functional PHP

Expand Down
3 changes: 2 additions & 1 deletion docs/01-list-comprehension.md
Expand Up @@ -5,7 +5,8 @@
- [Chapter 4: function functions](04-function-functions.md)
- [Chapter 5: mathematical functions](05-mathematical-functions.md)
- [Chapter 6: transformation functions](06-transformation-functions.md)
- [Chapter 7: miscellaneous](07-miscellaneous.md)
- [Chapter 7: comparator](07-comparator.md)
- [Chapter 8: miscellaneous](08-miscellaneous.md)

# Function overview

Expand Down
3 changes: 2 additions & 1 deletion docs/02-partial-application.md
Expand Up @@ -5,7 +5,8 @@
- [Chapter 4: function functions](04-function-functions.md)
- [Chapter 5: mathematical functions](05-mathematical-functions.md)
- [Chapter 6: transformation functions](06-transformation-functions.md)
- [Chapter 7: miscellaneous](07-miscellaneous.md)
- [Chapter 7: comparator](07-comparator.md)
- [Chapter 8: miscellaneous](08-miscellaneous.md)

# Partial application

Expand Down
8 changes: 7 additions & 1 deletion docs/03-access-functions.md
Expand Up @@ -5,7 +5,8 @@
- [Chapter 4: function functions](04-function-functions.md)
- [Chapter 5: mathematical functions](05-mathematical-functions.md)
- [Chapter 6: transformation functions](06-transformation-functions.md)
- [Chapter 7: miscellaneous](07-miscellaneous.md)
- [Chapter 7: comparator](07-comparator.md)
- [Chapter 8: miscellaneous](08-miscellaneous.md)

# Access functions

Expand Down Expand Up @@ -55,6 +56,11 @@ Invokes method `$methodName` on the first object in the `$collection` and return
Invokes method `$methodName` on the last object in the `$collection` and returns the results of the call


## invoker()

``callable Functional\invoker(string $method[, array $methodArguments])``
Returns a function that invokes method `$method` with arguments `$methodArguments` on the object

## pluck()
Fetch a single property from a collection of objects or arrays.

Expand Down
3 changes: 2 additions & 1 deletion docs/04-function-functions.md
Expand Up @@ -5,7 +5,8 @@
- Chapter 4: function functions
- [Chapter 5: mathematical functions](05-mathematical-functions.md)
- [Chapter 6: transformation functions](06-transformation-functions.md)
- [Chapter 7: miscellaneous](07-miscellaneous.md)
- [Chapter 7: comparator](07-comparator.md)
- [Chapter 8: miscellaneous](08-miscellaneous.md)

# Function functions

Expand Down
3 changes: 2 additions & 1 deletion docs/05-mathematical-functions.md
Expand Up @@ -5,7 +5,8 @@
- [Chapter 4: function functions](04-function-functions.md)
- Chapter 5: mathematical functions
- [Chapter 6: transformation functions](06-transformation-functions.md)
- [Chapter 7: miscellaneous](07-miscellaneous.md)
- [Chapter 7: comparator](07-comparator.md)
- [Chapter 8: miscellaneous](08-miscellaneous.md)

# Mathematical functions

Expand Down
3 changes: 2 additions & 1 deletion docs/06-transformation-functions.md
Expand Up @@ -5,7 +5,8 @@
- [Chapter 4: function functions](04-function-functions.md)
- [Chapter 5: mathematical functions](05-mathematical-functions.md)
- Chapter 6: transformation functions
- [Chapter 7: miscellaneous](07-miscellaneous.md)
- [Chapter 7: comparator](07-comparator.md)
- [Chapter 8: miscellaneous](08-miscellaneous.md)

# Transformation functions

Expand Down
24 changes: 24 additions & 0 deletions docs/07-comparator.md
@@ -0,0 +1,24 @@
- [Overview](00-index.md)
- [Chapter 1: list comprehension](01-list-comprehension.md)
- [Chapter 2: partial application](02-partial-application.md)
- [Chapter 3: access functions](03-access-functions.md)
- [Chapter 4: function functions](04-function-functions.md)
- [Chapter 5: mathematical functions](05-mathematical-functions.md)
- [Chapter 6: transformation functions](06-transformation-functions.md)
- Chapter 7: comparator
- [Chapter 8: miscellaneous](08-miscellaneous.md)

# Higher order comparison functions

## compare_on & compare_object_hash_on

``callable compare_on(callable $comparison; callable $keyFunction = Functional\const_function)``
Returns a compare function that can be used with e.g. `usort()`, `array_udiff`, `array_uintersect` and so on. Takes a
comparison function as the first argument, pick e.g. `strcmp`, `strnatcmp` or `strnatcasecmp`. Second argument can be a
key function that is applied to both parameters passed to the compare function.

``callable compare_object_hash_on(callable $comparison = 'strnatcasecmp', callable $keyFunction = 'Functional\const_function')``
Returns a compare function function that expects `$left` and `$right` to be an object and compares them using the value
of `spl_object_hash`. First argument is the comparison function, pick e.g. `strcmp`, `strnatcmp` or `strnatcasecmp`.
Takes a key function as an optional argument that is invoked on both parameters passed to the compare function. It is
just a shortcut to `compare_on` as it composes the given key function with `spl_object_hash()` as a key function.
3 changes: 2 additions & 1 deletion docs/07-miscellaneous.md → docs/08-miscellaneous.md
Expand Up @@ -5,7 +5,8 @@
- [Chapter 4: function functions](04-function-functions.md)
- [Chapter 5: mathematical functions](05-mathematical-functions.md)
- [Chapter 6: transformation functions](06-transformation-functions.md)
- Chapter 7: miscellaneous
- [Chapter 7: comparator](07-comparator.md)
- Chapter 8: miscellaneous

# Miscellaneous

Expand Down
40 changes: 40 additions & 0 deletions src/Functional/CompareObjectHashOn.php
@@ -0,0 +1,40 @@
<?php
/**
* Copyright (C) 2011-2015 by Lars Strojny <lstrojny@php.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Functional;

use function Functional\compose;

/**
* Returns a comparison function that can be used with e.g. `usort()`
*
* @param callable $comparison A function that compares the two values. Pick e.g. strcmp() or strnatcasecmp()
* @param callable $keyFunction A function that takes an argument and returns the value that should be compared
* @return callable
*/
function compare_object_hash_on(callable $comparison, callable $keyFunction = null)
{
$keyFunction = $keyFunction ? compose($keyFunction, 'spl_object_hash') : 'spl_object_hash';

return compare_on($comparison, $keyFunction);
}

43 changes: 43 additions & 0 deletions src/Functional/CompareOn.php
@@ -0,0 +1,43 @@
<?php
/**
* Copyright (C) 2011-2015 by Lars Strojny <lstrojny@php.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Functional;
/**
* Returns a comparison function that can be used with e.g. `usort()`
*
* @param callable $comparison A function that compares the two values. Pick e.g. strcmp() or strnatcasecmp()
* @param callable $reducer A function that takes an argument and returns the value that should be compared
* @return callable
*/
function compare_on(callable $comparison, callable $reducer = null)
{
if ($reducer === null) {
return static function ($left, $right) use ($comparison) {
return $comparison($left, $right);
};
}

return static function ($left, $right) use ($reducer, $comparison) {
return $comparison($reducer($left), $reducer($right));
};
}

42 changes: 42 additions & 0 deletions src/Functional/Invoker.php
@@ -0,0 +1,42 @@
<?php
/**
* Copyright (C) 2011 by Lars Strojny <lstrojny@php.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Functional;

use Traversable;
use Functional\Exceptions\InvalidArgumentException;

/**
* Returns a function that invokes method `$method` with arguments `$methodArguments` on the object
*
* @param string $methodName
* @param array $arguments
* @return callable
*/
function invoker($methodName, array $arguments = [])
{
InvalidArgumentException::assertMethodName($methodName, __FUNCTION__, 1);

return static function ($object) use ($methodName, $arguments) {
return $object->{$methodName}(...$arguments);
};
}
45 changes: 45 additions & 0 deletions tests/Functional/CompareObjectHashOnTest.php
@@ -0,0 +1,45 @@
<?php
/**
* Copyright (C) 2011-2015 by Lars Strojny <lstrojny@php.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Functional\Tests;

use function Functional\compare_object_hash_on;
use function Functional\const_function;
use stdClass;

class CompareObjectHashOnTest extends AbstractTestCase
{
public function testCompareValues()
{
$compare = compare_object_hash_on('strcmp');

$this->assertSame(0, $compare($this, $this));
$this->assertNotSame(0, $compare($this, new stdClass()));
}

public function testCompareWithReducer()
{
$compare = compare_object_hash_on('strcmp', const_function(new stdClass()));

$this->assertSame(0, $compare($this, new stdClass()));
}
}
45 changes: 45 additions & 0 deletions tests/Functional/CompareOnTest.php
@@ -0,0 +1,45 @@
<?php
/**
* Copyright (C) 2011-2015 by Lars Strojny <lstrojny@php.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Functional\Tests;

use function Functional\compare_on;
use function Functional\const_function;

class CompareOnTest extends AbstractTestCase
{
public function testCompareValues()
{
$comparator = compare_on('strcmp');

$this->assertSame(-1, $comparator(1, 2));
$this->assertSame(0, $comparator(2, 2));
$this->assertSame(1, $comparator(20, 10));
}

public function testCompareWithReducer()
{
$comparator = compare_on('strcmp', const_function(1));

$this->assertSame(0, $comparator(0, 1));
}
}

0 comments on commit afacc8e

Please sign in to comment.