From dae2481369d0900ae939798282bc90dd66cbf225 Mon Sep 17 00:00:00 2001 From: zyd Date: Fri, 27 May 2022 22:26:34 +0900 Subject: [PATCH 1/4] add method converge, fix arity related issue --- README.md | 2 +- ramda/__init__.py | 1 + ramda/converge.py | 16 +++++++++++++ ramda/curryN.py | 3 +-- ramda/private/_curry1.py | 2 +- ramda/private/_curryN.py | 3 ++- ramda/private/_helper.py | 17 +++++++++++++ test/private/test__curry1.py | 3 +++ test/private/test__curry2.py | 3 +++ test/private/test__curry3.py | 3 +++ test/test_converge.py | 46 ++++++++++++++++++++++++++++++++++++ test/test_curryN.py | 20 ++++++++++++++-- 12 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 ramda/converge.py create mode 100644 test/test_converge.py diff --git a/README.md b/README.md index 5b8dd59..35a9656 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ isinstance(clone, Obj) # True - [ ] cond - [ ] construct - [ ] constructN -- [ ] converge +- [x] converge - [ ] count - [x] 0.1.2 countBy - [x] 0.1.2 curry diff --git a/ramda/__init__.py b/ramda/__init__.py index 8a0041c..b16a5e7 100644 --- a/ramda/__init__.py +++ b/ramda/__init__.py @@ -10,6 +10,7 @@ from .comparator import comparator from .compose import compose from .concat import concat +from .converge import converge from .countBy import countBy from .curry import curry from .curryN import curryN diff --git a/ramda/converge.py b/ramda/converge.py new file mode 100644 index 0000000..04dcab6 --- /dev/null +++ b/ramda/converge.py @@ -0,0 +1,16 @@ +from .curryN import curryN +from .Max import Max +from .private._curry2 import _curry2 +from .private._helper import funcArgsLength, getArgsToUse +from .private._map import _map +from .reduce import reduce + + +def inner_converge(after, fns): + def wrapper(*args): + return after(*_map(lambda fn: fn(*getArgsToUse(fn, args)), fns)) + arity = reduce(Max, 0, _map(funcArgsLength, fns)) + return curryN(arity, wrapper) + + +converge = _curry2(inner_converge) diff --git a/ramda/curryN.py b/ramda/curryN.py index 64a8d14..47bb23c 100644 --- a/ramda/curryN.py +++ b/ramda/curryN.py @@ -1,6 +1,5 @@ from .private._arity import _arity -from .private._curry1 import _curry1 from .private._curry2 import _curry2 from .private._curryN import _curryN -curryN = _curry2(lambda n, fn: _curry1(fn) if n == 1 else _arity(n, _curryN(n, [], fn))) +curryN = _curry2(lambda n, fn: _arity(n, _curryN(n, [], fn))) diff --git a/ramda/private/_curry1.py b/ramda/private/_curry1.py index ac93aba..4a3f7eb 100644 --- a/ramda/private/_curry1.py +++ b/ramda/private/_curry1.py @@ -8,5 +8,5 @@ def _curry1(fn): def f1(a=__, *_): if _isPlaceholder(a): return f1 - return fn(a, *_) + return fn(a) return f1 diff --git a/ramda/private/_curryN.py b/ramda/private/_curryN.py index d778dbb..edf10f4 100644 --- a/ramda/private/_curryN.py +++ b/ramda/private/_curryN.py @@ -1,4 +1,5 @@ from ._arity import _arity +from ._helper import getArgsToUse from ._isPlaceholder import _isPlaceholder @@ -20,6 +21,6 @@ def f1(*arguments): left -= 1 combinedIdx += 1 if left <= 0: - return fn(*combined) + return fn(*getArgsToUse(fn, combined)) return _arity(left, _curryN(n, combined, fn)) return f1 diff --git a/ramda/private/_helper.py b/ramda/private/_helper.py index 01ed7bd..93133a2 100644 --- a/ramda/private/_helper.py +++ b/ramda/private/_helper.py @@ -1,5 +1,8 @@ +from inspect import getfullargspec + from ._has import _has from ._isArrayLike import _isArrayLike +from ._isPlaceholder import _isPlaceholder def funcArgsLength(fn): @@ -10,6 +13,20 @@ def funcArgsLength(fn): return fn.__code__.co_argcount +def getArgsToUse(fn, args): + """ + Get args to use for fn + """ + if getfullargspec(fn).varargs: + # we can not determine the number of args if varargs exists + return args + argsToUse = [] + for i in range(funcArgsLength(fn)): + if not _isPlaceholder(args[i]): + argsToUse.append(args[i]) + return argsToUse + + def toNumber(a): """ Convert any input a to a number type diff --git a/test/private/test__curry1.py b/test/private/test__curry1.py index 8afe761..97b342e 100644 --- a/test/private/test__curry1.py +++ b/test/private/test__curry1.py @@ -22,6 +22,9 @@ def test_supports_placeholder(self): def test_has_1_arity(self): self.assertEqual(1, funcArgsLength(g)) + def test_works_even_more_args_provided(self): + self.assertEqual([1], g(1, 2, 3)) + if __name__ == '__main__': unittest.main() diff --git a/test/private/test__curry2.py b/test/private/test__curry2.py index 7793134..15501a8 100644 --- a/test/private/test__curry2.py +++ b/test/private/test__curry2.py @@ -33,6 +33,9 @@ def test_supports_placeholder(self): def test_has_2_arity(self): self.assertEqual(2, funcArgsLength(g)) + def test_works_even_more_args_provided(self): + self.assertEqual([1, 2], g(1, 2, 3)) + if __name__ == '__main__': unittest.main() diff --git a/test/private/test__curry3.py b/test/private/test__curry3.py index eb6f454..c776dd9 100644 --- a/test/private/test__curry3.py +++ b/test/private/test__curry3.py @@ -43,6 +43,9 @@ def test_supports_placeholder(self): def test_has_3_arity(self): self.assertEqual(3, funcArgsLength(g)) + def test_works_even_more_args_provided(self): + self.assertEqual([1, 2, 3], g(1, 2, 3, 4)) + if __name__ == '__main__': unittest.main() diff --git a/test/test_converge.py b/test/test_converge.py new file mode 100644 index 0000000..dcf63a9 --- /dev/null +++ b/test/test_converge.py @@ -0,0 +1,46 @@ + +import unittest + +import ramda as R +from ramda.private._helper import funcArgsLength + +""" +https://github.com/ramda/ramda/blob/master/test/converge.js +""" + +f1 = R.converge(R.multiply, [R.identity, R.identity]) +f2 = R.converge(R.multiply, [R.identity, lambda a, b: b]) +f3 = R.converge(R.multiply, [R.identity, lambda a, b, c: c]) + + +class TestConverge(unittest.TestCase): + def test_passes_the_results_of_applying_the_arguments_individually_to_two_separate_functions_into_a_single_one(self): + self.assertEqual(15, R.converge(R.multiply, [R.add(1), R.add(3)])(2)) + + def test_returns_a_function_with_the_length_of_the_longest_argument(self): + self.assertEqual(1, funcArgsLength(f1)) + self.assertEqual(2, funcArgsLength(f2)) + self.assertEqual(3, funcArgsLength(f3)) + + def test_returns_a_curried_function(self): + self.assertEqual(42, f2(6)(7)) + self.assertEqual(3, funcArgsLength(f3(R.__))) + + def test_works_with_empty_functions_list(self): + fn = R.converge(lambda *args: len(args), []) + self.assertEqual(0, funcArgsLength(fn)) + self.assertEqual(0, fn()) + + def test_works_with_functions_with_different_number_of_arguments(self): + fn = R.converge(R.multiply, [R.add, R.add(1)]) + self.assertEqual(6, fn(1)(2)) # curried + self.assertEqual(6, fn(1, 2)) + self.assertEqual(6, fn(1)(R.__)(2)) + self.assertEqual(9, fn(R.__, 1)(2)) + self.assertEqual(6, fn(R.__, R.__)(1, 2)) + self.assertEqual(6, fn(1, R.__)(2)) + self.assertEqual(6, fn(1, 2, 3)) # works even more arguments provided + + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_curryN.py b/test/test_curryN.py index 4235266..632de61 100644 --- a/test/test_curryN.py +++ b/test/test_curryN.py @@ -135,9 +135,9 @@ def test_returned_function_can_be_called_with_proper_arity(self): def f11(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11): return [x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11] self.assertEqual(0, funcArgsLength(R.curryN(0, f11))) - self.assertEqual(expected, R.curryN(0, f11)(*expected)) + self.assertEqual(expected, R.curryN(0, f11)(*expected)) # need to provide all args at once self.assertEqual(1, funcArgsLength(R.curryN(1, f11))) - self.assertEqual(expected, R.curryN(1, f11)(*expected)) + self.assertEqual(expected, R.curryN(1, f11)(*expected)) # need to provide all args at once self.assertEqual(2, funcArgsLength(R.curryN(2, f11))) self.assertEqual(expected, R.curryN(2, f11)(1)(*expected[1:])) self.assertEqual(3, funcArgsLength(R.curryN(3, f11))) @@ -157,6 +157,22 @@ def f11(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11): return [x1, x2, x3, x4, x self.assertEqual(10, funcArgsLength(R.curryN(10, f11))) self.assertEqual(expected, R.curryN(10, f11)(1)(2)(3)(4)(5)(6)(7)(8)(9)(*expected[9:])) + def test_works_even_more_args_provided(self): + expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + def f11(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11): return [x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11] + + self.assertEqual(expected, R.curryN(0, f11)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) + self.assertEqual(expected, R.curryN(1, f11)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) + self.assertEqual(expected, R.curryN(2, f11)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) + self.assertEqual(expected, R.curryN(3, f11)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) + self.assertEqual(expected, R.curryN(4, f11)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) + self.assertEqual(expected, R.curryN(5, f11)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) + self.assertEqual(expected, R.curryN(6, f11)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) + self.assertEqual(expected, R.curryN(7, f11)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) + self.assertEqual(expected, R.curryN(8, f11)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) + self.assertEqual(expected, R.curryN(9, f11)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) + self.assertEqual(expected, R.curryN(10, f11)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) + if __name__ == '__main__': unittest.main() From 67c3df60afe5db72756ff299cb7ee83d160974a0 Mon Sep 17 00:00:00 2001 From: zyd Date: Sun, 29 May 2022 05:40:50 +0900 Subject: [PATCH 2/4] refactor inspect related helper functions --- ramda/converge.py | 2 +- ramda/curry.py | 2 +- ramda/flip.py | 2 +- ramda/map.py | 2 +- ramda/once.py | 2 +- ramda/pipe.py | 2 +- ramda/private/_curryN.py | 2 +- ramda/private/_helper.py | 24 ------------------------ ramda/private/_inspect.py | 26 ++++++++++++++++++++++++++ test/private/test__curry1.py | 2 +- test/private/test__curry2.py | 2 +- test/private/test__curry3.py | 6 +++++- test/test_compose.py | 2 +- test/test_converge.py | 6 +++--- test/test_curry.py | 6 ++++++ test/test_curryN.py | 2 +- test/test_flip.py | 2 +- test/test_once.py | 3 ++- test/test_pipe.py | 2 +- test/test_useWith.py | 3 ++- 20 files changed, 57 insertions(+), 43 deletions(-) create mode 100644 ramda/private/_inspect.py diff --git a/ramda/converge.py b/ramda/converge.py index 04dcab6..12f4108 100644 --- a/ramda/converge.py +++ b/ramda/converge.py @@ -1,7 +1,7 @@ from .curryN import curryN from .Max import Max from .private._curry2 import _curry2 -from .private._helper import funcArgsLength, getArgsToUse +from .private._inspect import funcArgsLength, getArgsToUse from .private._map import _map from .reduce import reduce diff --git a/ramda/curry.py b/ramda/curry.py index 4e95892..ad216a2 100644 --- a/ramda/curry.py +++ b/ramda/curry.py @@ -1,6 +1,6 @@ from .curryN import curryN from .private._curry1 import _curry1 -from .private._helper import funcArgsLength +from .private._inspect import funcArgsLength curry = _curry1(lambda fn: curryN(funcArgsLength(fn), fn)) diff --git a/ramda/flip.py b/ramda/flip.py index dbc0eed..fe7315b 100644 --- a/ramda/flip.py +++ b/ramda/flip.py @@ -1,6 +1,6 @@ from .curryN import curryN from .private._curry1 import _curry1 -from .private._helper import funcArgsLength +from .private._inspect import funcArgsLength def inner_flip(fn): diff --git a/ramda/map.py b/ramda/map.py index 2385de9..9d12e34 100644 --- a/ramda/map.py +++ b/ramda/map.py @@ -5,7 +5,7 @@ from .private._curry2 import _curry2 from .private._dispatchable import _dispatchable from .private._has import _has -from .private._helper import funcArgsLength +from .private._inspect import funcArgsLength from .private._isFunction import _isFunction from .private._map import _map from .private._reduce import _reduce diff --git a/ramda/once.py b/ramda/once.py index 1cfa0b3..269181a 100644 --- a/ramda/once.py +++ b/ramda/once.py @@ -1,6 +1,6 @@ from .private._arity import _arity from .private._curry1 import _curry1 -from .private._helper import funcArgsLength +from .private._inspect import funcArgsLength def inner_once(fn): diff --git a/ramda/pipe.py b/ramda/pipe.py index 92d366e..80cb62b 100644 --- a/ramda/pipe.py +++ b/ramda/pipe.py @@ -1,5 +1,5 @@ from .private._arity import _arity -from .private._helper import funcArgsLength +from .private._inspect import funcArgsLength from .private._pipe import _pipe from .reduce import reduce from .tail import tail diff --git a/ramda/private/_curryN.py b/ramda/private/_curryN.py index edf10f4..5e7dea3 100644 --- a/ramda/private/_curryN.py +++ b/ramda/private/_curryN.py @@ -1,5 +1,5 @@ from ._arity import _arity -from ._helper import getArgsToUse +from ._inspect import getArgsToUse from ._isPlaceholder import _isPlaceholder diff --git a/ramda/private/_helper.py b/ramda/private/_helper.py index 93133a2..8427f37 100644 --- a/ramda/private/_helper.py +++ b/ramda/private/_helper.py @@ -1,30 +1,6 @@ -from inspect import getfullargspec from ._has import _has from ._isArrayLike import _isArrayLike -from ._isPlaceholder import _isPlaceholder - - -def funcArgsLength(fn): - """ - Get the number of args for function fn - Not count *args and **kwargs - """ - return fn.__code__.co_argcount - - -def getArgsToUse(fn, args): - """ - Get args to use for fn - """ - if getfullargspec(fn).varargs: - # we can not determine the number of args if varargs exists - return args - argsToUse = [] - for i in range(funcArgsLength(fn)): - if not _isPlaceholder(args[i]): - argsToUse.append(args[i]) - return argsToUse def toNumber(a): diff --git a/ramda/private/_inspect.py b/ramda/private/_inspect.py new file mode 100644 index 0000000..d31b4d9 --- /dev/null +++ b/ramda/private/_inspect.py @@ -0,0 +1,26 @@ + +from inspect import getfullargspec + +from ._isPlaceholder import _isPlaceholder + + +def funcArgsLength(fn): + """ + Get the number of args for function fn + Not count *args and **kwargs + """ + return fn.__code__.co_argcount + + +def getArgsToUse(fn, args): + """ + Get args to use for fn + """ + if getfullargspec(fn).varargs: + # we can not determine the number of args if varargs exists + return args + argsToUse = [] + for i in range(funcArgsLength(fn)): + if not _isPlaceholder(args[i]): + argsToUse.append(args[i]) + return argsToUse diff --git a/test/private/test__curry1.py b/test/private/test__curry1.py index 97b342e..ab66d6e 100644 --- a/test/private/test__curry1.py +++ b/test/private/test__curry1.py @@ -2,7 +2,7 @@ import ramda as R from ramda.private._curry1 import _curry1 -from ramda.private._helper import funcArgsLength +from ramda.private._inspect import funcArgsLength def f(a): return [a] diff --git a/test/private/test__curry2.py b/test/private/test__curry2.py index 15501a8..daf5d1a 100644 --- a/test/private/test__curry2.py +++ b/test/private/test__curry2.py @@ -2,7 +2,7 @@ import ramda as R from ramda.private._curry2 import _curry2 -from ramda.private._helper import funcArgsLength +from ramda.private._inspect import funcArgsLength """ https://github.com/ramda/ramda/blob/master/test/internal/_curry2.js diff --git a/test/private/test__curry3.py b/test/private/test__curry3.py index c776dd9..7819bc5 100644 --- a/test/private/test__curry3.py +++ b/test/private/test__curry3.py @@ -3,15 +3,19 @@ import ramda as R from ramda.private._curry3 import _curry3 -from ramda.private._helper import funcArgsLength +from ramda.private._inspect import funcArgsLength """ https://github.com/ramda/ramda/blob/master/test/internal/_curry3.js """ + def f(a, b, c): return [a, b, c] + + g = _curry3(f) + class Test_Curry3(unittest.TestCase): def test_supports_placeholder(self): _ = R.__ diff --git a/test/test_compose.py b/test/test_compose.py index 3683f9d..134c045 100644 --- a/test/test_compose.py +++ b/test/test_compose.py @@ -2,7 +2,7 @@ import unittest import ramda as R -from ramda.private._helper import funcArgsLength +from ramda.private._inspect import funcArgsLength """ https://github.com/ramda/ramda/blob/master/test/compose.js diff --git a/test/test_converge.py b/test/test_converge.py index dcf63a9..7217919 100644 --- a/test/test_converge.py +++ b/test/test_converge.py @@ -2,7 +2,7 @@ import unittest import ramda as R -from ramda.private._helper import funcArgsLength +from ramda.private._inspect import funcArgsLength """ https://github.com/ramda/ramda/blob/master/test/converge.js @@ -33,13 +33,13 @@ def test_works_with_empty_functions_list(self): def test_works_with_functions_with_different_number_of_arguments(self): fn = R.converge(R.multiply, [R.add, R.add(1)]) - self.assertEqual(6, fn(1)(2)) # curried + self.assertEqual(6, fn(1)(2)) # curried self.assertEqual(6, fn(1, 2)) self.assertEqual(6, fn(1)(R.__)(2)) self.assertEqual(9, fn(R.__, 1)(2)) self.assertEqual(6, fn(R.__, R.__)(1, 2)) self.assertEqual(6, fn(1, R.__)(2)) - self.assertEqual(6, fn(1, 2, 3)) # works even more arguments provided + self.assertEqual(6, fn(1, 2, 3)) # works even more arguments provided if __name__ == '__main__': diff --git a/test/test_curry.py b/test/test_curry.py index 9b9b544..126bf5d 100644 --- a/test/test_curry.py +++ b/test/test_curry.py @@ -113,6 +113,12 @@ def f(a, b, c, *args): self.assertEqual([1, 2, 3, 4], g(1)(2, 3, 4)) self.assertEqual([1, 2, 3, 4], g(1)(2)(3, 4)) + def test_works_even_more_args_provided(self): + def f(a, b): + return [a, b] + g = R.curry(f) + self.assertEqual([1, 2], g(1, 2, 3)) + if __name__ == '__main__': unittest.main() diff --git a/test/test_curryN.py b/test/test_curryN.py index 632de61..f24b21e 100644 --- a/test/test_curryN.py +++ b/test/test_curryN.py @@ -3,7 +3,7 @@ from random import randint import ramda as R -from ramda.private._helper import funcArgsLength +from ramda.private._inspect import funcArgsLength def source(a, b, c): diff --git a/test/test_flip.py b/test/test_flip.py index de71bb0..8e26cfc 100644 --- a/test/test_flip.py +++ b/test/test_flip.py @@ -2,7 +2,7 @@ import unittest import ramda as R -from ramda.private._helper import funcArgsLength +from ramda.private._inspect import funcArgsLength """ https://github.com/ramda/ramda/blob/master/test/flip.js diff --git a/test/test_once.py b/test/test_once.py index 2dc6f5a..7f37fcc 100644 --- a/test/test_once.py +++ b/test/test_once.py @@ -2,7 +2,7 @@ import unittest import ramda as R -from ramda.private._helper import funcArgsLength +from ramda.private._inspect import funcArgsLength """ https://github.com/ramda/ramda/blob/master/test/once.js @@ -12,6 +12,7 @@ class TestOnce(unittest.TestCase): def test_returns_a_function_that_calls_the_supplied_function_only_the_first_time_called(self): ctr = 0 + def wrapper(): nonlocal ctr ctr += 1 diff --git a/test/test_pipe.py b/test/test_pipe.py index faecaaa..03d1a23 100644 --- a/test/test_pipe.py +++ b/test/test_pipe.py @@ -2,7 +2,7 @@ import unittest import ramda as R -from ramda.private._helper import funcArgsLength +from ramda.private._inspect import funcArgsLength """ https://github.com/ramda/ramda/blob/master/test/pipe.js diff --git a/test/test_useWith.py b/test/test_useWith.py index 3c461dc..3d3f1bb 100644 --- a/test/test_useWith.py +++ b/test/test_useWith.py @@ -2,7 +2,7 @@ import unittest import ramda as R -from ramda.private._helper import funcArgsLength +from ramda.private._inspect import funcArgsLength from ramda.private._isFunction import _isFunction """ @@ -31,5 +31,6 @@ def test_passes_additional_arguments_to_the_main_function(self): def test_has_the_correct_arity(self): self.assertEqual(3, funcArgsLength(f)) + if __name__ == '__main__': unittest.main() From 9311913c6e1f36a25f2af84853f145f76d9966c7 Mon Sep 17 00:00:00 2001 From: zyd Date: Sun, 29 May 2022 06:09:47 +0900 Subject: [PATCH 3/4] add method juxt --- README.md | 2 +- ramda/__init__.py | 1 + ramda/juxt.py | 4 ++++ test/test_juxt.py | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 ramda/juxt.py create mode 100644 test/test_juxt.py diff --git a/README.md b/README.md index 35a9656..66b7250 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,7 @@ R.isEmpty(None) # False - [ ] isNil - [x] 0.1.2 join -- [ ] juxt +- [x] juxt - [x] 0.1.2 keys ```python diff --git a/ramda/__init__.py b/ramda/__init__.py index b16a5e7..4551b77 100644 --- a/ramda/__init__.py +++ b/ramda/__init__.py @@ -41,6 +41,7 @@ from .invoker import invoker from .isEmpty import isEmpty from .join import join +from .juxt import juxt from .keys import keys from .last import last from .lastIndexOf import lastIndexOf diff --git a/ramda/juxt.py b/ramda/juxt.py new file mode 100644 index 0000000..74a1759 --- /dev/null +++ b/ramda/juxt.py @@ -0,0 +1,4 @@ +from .converge import converge +from .private._curry1 import _curry1 + +juxt = _curry1(lambda fns: converge(lambda *args: list(args), fns)) diff --git a/test/test_juxt.py b/test/test_juxt.py new file mode 100644 index 0000000..63aef92 --- /dev/null +++ b/test/test_juxt.py @@ -0,0 +1,53 @@ + +import unittest + +import ramda as R + +""" +https://github.com/ramda/ramda/blob/master/test/juxt.js +""" + + +def hello(): + return "hello" + + +def bye(): + return "bye" + + +class TestJuxt(unittest.TestCase): + def test_works_with_no_functions_and_no_values(self): + self.assertEqual([], R.juxt([])()) + + def test_works_with_no_functions_and_some_values(self): + self.assertEqual([], R.juxt([])(2, 3)) + + def test_works_with_1_function_and_no_values(self): + self.assertEqual(['hello'], R.juxt([hello])()) + + def test_works_with_1_function_and_1_value(self): + self.assertEqual([5], R.juxt([R.add(3)])(2)) + + def test_works_with_1_function_and_some_value(self): + self.assertEqual([6], R.juxt([R.multiply])(2, 3)) + + def test_works_with_some_functions_and_no_value(self): + self.assertEqual(['hello', 'bye'], R.juxt([hello, bye])()) + + def test_works_with_some_functions_and_1_value(self): + self.assertEqual([4, 5], R.juxt([R.multiply(2), R.add(3)])(2)) + + def test_works_with_some_functions_and_some_value(self): + self.assertEqual([5, 6], R.juxt([R.add, R.multiply])(2, 3)) + + def test_retains_the_highest_arity(self): + # TODO: nAry + pass + + def test_returns_a_curried_function(self): + self.assertEqual([6, 5], R.juxt([R.multiply, R.add])(2)(3)) + + +if __name__ == '__main__': + unittest.main() From 47c852c59f8af481eb7d7863b755b389e212d3c3 Mon Sep 17 00:00:00 2001 From: zyd Date: Mon, 30 May 2022 08:58:13 +0900 Subject: [PATCH 4/4] add method partition --- README.md | 2 +- ramda/__init__.py | 1 + ramda/converge.py | 1 + ramda/filter.py | 2 + ramda/isEmpty.py | 1 + ramda/juxt.py | 1 + ramda/partition.py | 6 +++ ramda/private/_curry2.py | 6 ++- ramda/reject.py | 1 + test/test_partition.py | 81 ++++++++++++++++++++++++++++++++++++++++ 10 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 ramda/partition.py create mode 100644 test/test_partition.py diff --git a/README.md b/README.md index 66b7250..9fcbc48 100644 --- a/README.md +++ b/README.md @@ -373,7 +373,7 @@ R.omit(['v1', 'v3'], obj) # {'v2': 2} - [ ] partial - [ ] partialObject - [ ] partialRight -- [ ] partition +- [x] partition - [x] 0.1.2 path - [ ] pathEq - [ ] pathOr diff --git a/ramda/__init__.py b/ramda/__init__.py index 4551b77..128e862 100644 --- a/ramda/__init__.py +++ b/ramda/__init__.py @@ -59,6 +59,7 @@ from .omit import omit from .once import once from .Or import Or +from .partition import partition from .path import path from .paths import paths from .pick import pick diff --git a/ramda/converge.py b/ramda/converge.py index 12f4108..8f60396 100644 --- a/ramda/converge.py +++ b/ramda/converge.py @@ -14,3 +14,4 @@ def wrapper(*args): converge = _curry2(inner_converge) +converge.__name__ = 'converge' diff --git a/ramda/filter.py b/ramda/filter.py index bbfc039..71166d2 100644 --- a/ramda/filter.py +++ b/ramda/filter.py @@ -13,6 +13,7 @@ def inner_filter(pred, filterable): if _isArrayLike(filterable): return _filter(pred, filterable) + def inner_reduce(acc, key): """ There are 2 cases of filterable @@ -33,3 +34,4 @@ def inner_reduce(acc, key): # pylint: disable=redefined-builtin filter = _curry2(_dispatchable(['fantasy-land/filter', 'filter'], _xfilter, inner_filter)) +filter.__name__ = 'filter' diff --git a/ramda/isEmpty.py b/ramda/isEmpty.py index 74082b1..82b708c 100644 --- a/ramda/isEmpty.py +++ b/ramda/isEmpty.py @@ -8,3 +8,4 @@ def inner_isEmpty(x): isEmpty = _curry1(inner_isEmpty) +isEmpty.__name__ = 'isEmpty' diff --git a/ramda/juxt.py b/ramda/juxt.py index 74a1759..d909cde 100644 --- a/ramda/juxt.py +++ b/ramda/juxt.py @@ -2,3 +2,4 @@ from .private._curry1 import _curry1 juxt = _curry1(lambda fns: converge(lambda *args: list(args), fns)) +juxt.__name__ = 'juxt' diff --git a/ramda/partition.py b/ramda/partition.py new file mode 100644 index 0000000..fd58c6b --- /dev/null +++ b/ramda/partition.py @@ -0,0 +1,6 @@ +from .filter import filter +from .juxt import juxt +from .reject import reject + +partition = juxt([filter, reject]) +partition.__name__ = 'partition' diff --git a/ramda/private/_curry2.py b/ramda/private/_curry2.py index 3668286..2ba41c3 100644 --- a/ramda/private/_curry2.py +++ b/ramda/private/_curry2.py @@ -7,11 +7,13 @@ def _curry2(fn): # pylint: disable=dangerous-default-value # pylint: disable=keyword-arg-before-vararg def f2(a=__, b=__, *_): - def f_b(_b): return fn(a, _b) + def f_b(_b): + return fn(a, _b) if _isPlaceholder(a) and _isPlaceholder(b): return f2 if _isPlaceholder(a): - def f_a(_a): return fn(_a, b) + def f_a(_a): + return fn(_a, b) return _curry1(f_a) if _isPlaceholder(b): return _curry1(f_b) diff --git a/ramda/reject.py b/ramda/reject.py index bc48454..cf2f532 100644 --- a/ramda/reject.py +++ b/ramda/reject.py @@ -3,3 +3,4 @@ from .private._curry2 import _curry2 reject = _curry2(lambda pred, filterable: filter(_complement(pred), filterable)) +reject.__name__ = 'reject' diff --git a/test/test_partition.py b/test/test_partition.py new file mode 100644 index 0000000..21d5843 --- /dev/null +++ b/test/test_partition.py @@ -0,0 +1,81 @@ + +import unittest + +import ramda as R + +from .helpers.Maybe import Just + +""" +https://github.com/ramda/ramda/blob/master/test/partition.js +""" + + +def pred(x): return x % 2 + + +class TestPartition(unittest.TestCase): + def test_splits_a_list_into_two_lists_according_to_a_predicate(self): + self.assertEqual([[], []], R.partition(pred, [])) + self.assertEqual([[], [0, 2, 4, 6]], R.partition(pred, [0, 2, 4, 6])) + self.assertEqual([[1, 3, 5, 7], []], R.partition(pred, [1, 3, 5, 7])) + self.assertEqual([[1, 3], [0, 2]], R.partition(pred, [0, 1, 2, 3])) + + def test_works_with_dict(self): + self.assertEqual([{}, {}], R.partition(pred, {})) + self.assertEqual([{}, {'a': 0, 'b': 2, 'c': 4, 'd': 6}], R.partition(pred, {'a': 0, 'b': 2, 'c': 4, 'd': 6})) + self.assertEqual([{'a': 1, 'b': 3, 'c': 5, 'd': 7}, {}], R.partition(pred, {'a': 1, 'b': 3, 'c': 5, 'd': 7})) + self.assertEqual([{'b': 1, 'd': 3}, {'a': 0, 'c': 2}], R.partition(pred, {'a': 0, 'b': 1, 'c': 2, 'd': 3})) + + def test_works_with_object(self): + class Empty: + def __eq__(self, other): + return isinstance(other, Empty) + + def equals(self, other): + return isinstance(other, Empty) + + class Obj: + def __init__(self, a, b, c, d): + self.a = a + self.b = b + self.c = c + self.d = d + + def isEmpty(self): + return not hasattr(self, 'a') and not hasattr(self, 'b') and not hasattr(self, 'c') and not hasattr(self, 'd') + + def __eq__(self, another): + return self.a == another.a and self.b == another.b and self.c == another.c and self.d == another.d + + self.assertEqual([Empty(), Empty()], R.partition(pred, Empty())) + + res = R.partition(pred, Obj(0, 2, 4, 6)) + self.assertTrue(res[0].isEmpty()) + self.assertEqual(Obj(0, 2, 4, 6), res[1]) + + res = R.partition(pred, Obj(1, 3, 5, 7)) + self.assertTrue(res[1].isEmpty()) + self.assertEqual(Obj(1, 3, 5, 7), res[0]) + + res = R.partition(pred, Obj(0, 1, 2, 3)) + self.assertEqual(1, res[0].b) + self.assertEqual(3, res[0].d) + self.assertEqual(0, res[1].a) + self.assertEqual(2, res[1].c) + + def test_works_with_other_filterables(self): + just = Just([]) + res = R.partition(R.isEmpty, just) + self.assertEqual(just, res[0]) + self.assertTrue(res[1].isNothing) + + just = Just([1]) + res = R.partition(R.isEmpty, just) + self.assertTrue(res[0].isNothing) + self.assertEqual(just, res[1]) + + # TODO: complement + + +if __name__ == '__main__': + unittest.main()