Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,38 @@ isinstance(clone, Obj) # True
- [x] 0.1.2 compose
- [ ] composeWith
- [x] 0.1.2 concat
- [ ] cond
- [x] cond

Please notice the number of given arguments should match functions.
Otherwise Python will complain about the mis-matching arguments.

For example:

```python
fn = R.cond([
[lambda a: a == 1, lambda a: f'a == {a}'],
[lambda a, b: a == b, lambda a, b: f'{a} == {b}']
])
fn(1) # a == 1
fn(2, 2) # 2 == 2

fn(2) # Throw error, because b is not provided for prediction, failed when (lambda a, b: a == b)(2), missing argument b
# to solve above issue, you should try your best to provide enough arguments

fn(1, 2) # Throw error, because (lambda(a: f'a == {a}'))(1, 2) has extra arguments 2
# To solve above issue, always use sencond function with enough arguments
# Try create cond like below.
fn = R.cond([
[lambda a: a == 1, lambda a, _: f'a == {a}'], # ignore b
[lambda a, b: a == b, lambda a, b: f'{a} == {b}']
])

fn = R.cond([
[lambda a: a == 1, lambda a, *args: f'a == {a}'], # ignore any arguments
[lambda a, b: a == b, lambda a, b: f'{a} == {b}']
])
```

- [x] 0.4.0 construct
- [x] 0.4.0 constructN
- [x] 0.1.4 converge
Expand Down
1 change: 1 addition & 0 deletions ramda/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .comparator import comparator
from .compose import compose
from .concat import concat
from .cond import cond
from .construct import construct
from .constructN import constructN
from .converge import converge
Expand Down
25 changes: 25 additions & 0 deletions ramda/cond.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from .map import map
from .Max import Max
from .private._arity import _arity
from .private._curry1 import _curry1
from .private._inspect import funcArgsLength, getArgsToUse
from .reduce import reduce


def inner_cond(pairs):
arity = reduce(
Max, 0, map(lambda pair: funcArgsLength(pair[0]), pairs)
)

def wrapper(*args):
idx = 0
while idx < len(pairs):
pred = pairs[idx][0]
argsToUse = getArgsToUse(pred, args)
if pred(*argsToUse):
return pairs[idx][1](*args)
idx += 1
return _arity(arity, wrapper)


cond = _curry1(inner_cond)
75 changes: 75 additions & 0 deletions test/test_cond.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@

import unittest

import ramda as R
from ramda.private._inspect import funcArgsLength

"""
https://github.com/ramda/ramda/blob/master/test/cond.js
"""


class TestCond(unittest.TestCase):
def test_returns_a_function(self):
self.assertTrue(callable(R.cond([])))

def test_returns_a_conditional_function(self):
fn = R.cond([
[R.equals(0), R.always('water freezes at 0°C')],
[R.equals(100), R.always('water boils at 0°C')],
[R.T, lambda temp: f'nothing special happens at {temp}°C']
])
fn = R.cond([
[R.equals('foo'), R.always(1)],
[R.equals('bar'), R.always(2)]
])
# self.assertEqual('water freezes at 0°C', fn(0))
# self.assertEqual('nothing special happens at 50°C', fn(50))
# self.assertEqual('water boils at 100°C', fn(100))

def test_returns_a_function_which_returns_None_if_none_of_the_predicates_matches(self):
fn = R.cond([
[R.equals('foo'), R.always(1)],
[R.equals('bar'), R.always(2)]
])
self.assertEqual(None, fn('quux'))

def test_predicates_are_tested_in_order(self):
fn = R.cond([
[R.T, R.always('foo')],
[R.T, R.always('bar')],
[R.T, R.always('baz')]
])
self.assertEqual('foo', fn())

def test_forwards_all_arguments_to_predicates_and_to_transformers(self):
fn = R.cond([
[lambda _, x: x == 42, lambda a, b, c: a + b + c]
])
self.assertEqual(46, fn(1, 42, 3))

def test_cond_with_different_number_of_arguments(self):
fn = R.cond([
[lambda a: a == 1, lambda a, *_: f'a == {a}'],
[lambda a, b: a == b, lambda a, b, *_: f'{a} == {b}'],
[lambda a, b, c: a == b + c, lambda a, b, c: f'{a} == {b} + {c}'],
])
self.assertEqual('a == 1', fn(1))
self.assertEqual('a == 1', fn(1, 2))
self.assertEqual('a == 1', fn(1, 2, 3))
self.assertEqual('2 == 2', fn(2, 2))
self.assertEqual('2 == 2', fn(2, 2, 3))
self.assertEqual('4 == 1 + 3', fn(4, 1, 3))
self.assertEqual(None, fn(4, 1, 4))

def test_retains_highest_predicate_arity(self):
fn = R.cond([
[R.nAry(2, R.T), R.T],
[R.nAry(3, R.T), R.T],
[R.nAry(1, R.T), R.T]
])
self.assertEqual(3, funcArgsLength(fn))


if __name__ == '__main__':
unittest.main()