diff --git a/README.md b/README.md index 950273d..1a3263e 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ R.add(date(1,2,3), date(1,2,3)) # float('nan) - [ ] ascend - [ ] assoc - [ ] assocPath -- [ ] binary +- [x] binary - [ ] bind - [ ] both - [ ] call @@ -341,7 +341,7 @@ Python modulo on negative numbers has different behavior than JS. - [ ] move - [x] 0.1.2 multiply -- [ ] nAry +- [x] nAry - [ ] negate - [ ] none - [x] 0.1.2 not diff --git a/ramda/__init__.py b/ramda/__init__.py index 128e862..71aad9e 100644 --- a/ramda/__init__.py +++ b/ramda/__init__.py @@ -6,6 +6,7 @@ from .And import And from .any import any from .append import append +from .binary import binary from .clone import clone from .comparator import comparator from .compose import compose @@ -53,6 +54,7 @@ from .Min import Min from .modulo import modulo from .multiply import multiply +from .nAry import nAry from .Not import Not from .nth import nth from .objOf import objOf diff --git a/ramda/binary.py b/ramda/binary.py new file mode 100644 index 0000000..d5e0fae --- /dev/null +++ b/ramda/binary.py @@ -0,0 +1,4 @@ +from .nAry import nAry +from .private._curry1 import _curry1 + +binary = _curry1(lambda fn: nAry(2, fn)) diff --git a/ramda/nAry.py b/ramda/nAry.py new file mode 100644 index 0000000..1053a34 --- /dev/null +++ b/ramda/nAry.py @@ -0,0 +1,30 @@ +from .private._curry2 import _curry2 + + +def inner_nAry(n, fn): + if n == 0: + return lambda *args: fn() + if n == 1: + return lambda a0=None, *args: fn(a0) + if n == 2: + return lambda a0=None, a1=None, *args: fn(a0, a1) + if n == 3: + return lambda a0=None, a1=None, a2=None, *args: fn(a0, a1, a2) + if n == 4: + return lambda a0=None, a1=None, a2=None, a3=None, *args: fn(a0, a1, a2, a3) + if n == 5: + return lambda a0=None, a1=None, a2=None, a3=None, a4=None, *args: fn(a0, a1, a2, a3, a4) + if n == 6: + return lambda a0=None, a1=None, a2=None, a3=None, a4=None, a5=None, *args: fn(a0, a1, a2, a3, a4, a5) + if n == 7: + return lambda a0=None, a1=None, a2=None, a3=None, a4=None, a5=None, a6=None, *args: fn(a0, a1, a2, a3, a4, a5, a6) + if n == 8: + return lambda a0=None, a1=None, a2=None, a3=None, a4=None, a5=None, a6=None, a7=None, *args: fn(a0, a1, a2, a3, a4, a5, a6, a7) + if n == 9: + return lambda a0=None, a1=None, a2=None, a3=None, a4=None, a5=None, a6=None, a7=None, a8=None, *args: fn(a0, a1, a2, a3, a4, a5, a6, a7, a8) + if n == 10: + return lambda a0=None, a1=None, a2=None, a3=None, a4=None, a5=None, a6=None, a7=None, a8=None, a9=None, *args: fn(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) + raise ValueError('First argument to nAry must be a non-negative integer no greater than ten') + + +nAry = _curry2(inner_nAry) diff --git a/test/test_binary.py b/test/test_binary.py new file mode 100644 index 0000000..7f67cfa --- /dev/null +++ b/test/test_binary.py @@ -0,0 +1,20 @@ + +import unittest + +import ramda as R +from ramda.private._inspect import funcArgsLength + +""" +https://github.com/ramda/ramda/blob/master/test/binary.js +""" + + +class TestBinary(unittest.TestCase): + def test_turns_multiple_argument_function_into_binary_one(self): + fn = R.binary(lambda *args: list(args)) + self.assertEqual(2, funcArgsLength(fn)) + self.assertEqual([10, 20], fn(10, 20)) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_nAry.py b/test/test_nAry.py new file mode 100644 index 0000000..11538fd --- /dev/null +++ b/test/test_nAry.py @@ -0,0 +1,69 @@ + +import unittest + +import ramda as R +from ramda.private._inspect import funcArgsLength + +""" +https://github.com/ramda/ramda/blob/master/test/nAry.js +""" + + +def toArray(*args): + return list(args) + + +class TestNAry(unittest.TestCase): + def test_turns_multiple_argument_function_into_a_nullary_one(self): + fn = R.nAry(0, toArray) + self.assertEqual(0, funcArgsLength(fn)) + self.assertEqual([], fn(1, 2, 3)) + + def test_turns_multiple_argument_function_into_a_ternary_one(self): + fn = R.nAry(3, toArray) + self.assertEqual(3, funcArgsLength(fn)) + self.assertEqual([1, 2, 3], fn(1, 2, 3, 4)) + self.assertEqual([1, None, None], fn(1)) + + def test_creates_functions_of_arity_less_than_or_equal_to_ten(self): + fn = R.nAry(10, toArray) + self.assertEqual(10, funcArgsLength(fn)) + self.assertEqual(R.range(0, 10), fn(*R.range(0, 25))) + + nones = fn() + ns = R.repeat(None, 10) + self.assertEqual(nones, ns) + + def test_throws_if_n_is_greater_than_ten(self): + with self.assertRaises(ValueError): + R.nAry(11, toArray) + + def test_all_arity(self): + self.assertEqual(0, funcArgsLength(R.nAry(0, toArray))) + self.assertEqual(1, funcArgsLength(R.nAry(1, toArray))) + self.assertEqual(2, funcArgsLength(R.nAry(2, toArray))) + self.assertEqual(3, funcArgsLength(R.nAry(3, toArray))) + self.assertEqual(4, funcArgsLength(R.nAry(4, toArray))) + self.assertEqual(5, funcArgsLength(R.nAry(5, toArray))) + self.assertEqual(6, funcArgsLength(R.nAry(6, toArray))) + self.assertEqual(7, funcArgsLength(R.nAry(7, toArray))) + self.assertEqual(8, funcArgsLength(R.nAry(8, toArray))) + self.assertEqual(9, funcArgsLength(R.nAry(9, toArray))) + self.assertEqual(10, funcArgsLength(R.nAry(10, toArray))) + + input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + self.assertEqual([], R.nAry(0, toArray)(*input)) + self.assertEqual([1], R.nAry(1, toArray)(*input)) + self.assertEqual([1, 2], R.nAry(2, toArray)(*input)) + self.assertEqual([1, 2, 3], R.nAry(3, toArray)(*input)) + self.assertEqual([1, 2, 3, 4], R.nAry(4, toArray)(*input)) + self.assertEqual([1, 2, 3, 4, 5], R.nAry(5, toArray)(*input)) + self.assertEqual([1, 2, 3, 4, 5, 6], R.nAry(6, toArray)(*input)) + self.assertEqual([1, 2, 3, 4, 5, 6, 7], R.nAry(7, toArray)(*input)) + self.assertEqual([1, 2, 3, 4, 5, 6, 7, 8], R.nAry(8, toArray)(*input)) + self.assertEqual([1, 2, 3, 4, 5, 6, 7, 8, 9], R.nAry(9, toArray)(*input)) + self.assertEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], R.nAry(10, toArray)(*input)) + + +if __name__ == '__main__': + unittest.main()