Skip to content

Commit

Permalink
function expanding in nullables
Browse files Browse the repository at this point in the history
  • Loading branch information
keotl committed Mar 14, 2019
1 parent 373ef85 commit 7e38855
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 7 deletions.
25 changes: 21 additions & 4 deletions jivago/lang/nullable.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import inspect
from typing import Generic, TypeVar, Optional, Callable, Union

T = TypeVar('T')
Expand Down Expand Up @@ -58,39 +59,55 @@ def orElseFetch(self, supplier: Callable[[], T]) -> T:
return self._item
return supplier()

def ifPresent(self, consumer: Callable[[T], None]) -> None:
def ifPresent(self, consumer: Union[Callable[[T], None], Callable[..., None]]) -> "Nullable[T]":
"""Invoke function if value is present; otherwise does nothing.
Args:
consumer (Callable) : Function to be invoked with a non-nil parameter.
"""
if self.isPresent():
consumer(self._item)
if self.__should_expand(consumer):
consumer(*self._item)
else:
consumer(self._item)
return self

def filter(self, predicate: Callable[[T], bool]) -> "Nullable[T]":
def filter(self, predicate: Union[Callable[[T], bool], Callable[..., bool]]) -> "Nullable[T]":
"""Filters item given a criterion.
Args:
predicate (Callable) : Invoked with a non-nil parameter. Should return a boolean.
"""
if self.isPresent():
if self.__should_expand(predicate):
return self if predicate(*self._item) else Nullable.empty()
return self if predicate(self._item) else Nullable.empty()
return Nullable.empty()

def map(self, callable: Callable[[T], S]) -> "Nullable[S]":
def map(self, callable: Union[Callable[[T], S], Callable[..., S]]) -> "Nullable[S]":
"""Maps the item when present.
Args:
callable (Callable) : Invoked with a non-nil parameter.
"""
if self.isPresent():
if self.__should_expand(callable):
return Nullable(callable(*self._item))
return Nullable(callable(self._item))
return Nullable.empty()

def __bool__(self) -> bool:
return self.isPresent()

def __should_expand(self, fun: Callable) -> bool:
if inspect.isbuiltin(fun):
return False
if inspect.isclass(fun):
return len(inspect.signature(fun.__init__).parameters) > 2
sig = inspect.signature(fun)
return len(sig.parameters) > 1

@staticmethod
def empty() -> "Nullable":
return _empty
Expand Down
15 changes: 12 additions & 3 deletions test/lang/test_nullable.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,19 @@ def test_whenEvaluatingToBoolean_thenReturnIfItemIsPresent(self):
self.assertFalse(self.null)

def test_whenUsingIfPresent_thenInvokeOnlyWhenItemIsPresent(self):
callback = MagicMock()
mock = MagicMock()
callback = lambda x: mock()

self.null.ifPresent(callback)
self.assertFalse(callback.called)
self.assertFalse(mock.called)

self.non_null.ifPresent(callback)
self.assertTrue(callback.called)
self.assertTrue(mock.called)

def test_givenACallableWhichTakesMoreThanOneParameter_whenMappingOrFiltering_thenExpandTupleToMultipleParameters(
self):
tupleNullable = Nullable((1, 2))

sum = tupleNullable.map(lambda x, y: x + y)

self.assertEqual(3, sum.get())

0 comments on commit 7e38855

Please sign in to comment.