Skip to content

Commit

Permalink
Feature/bind (#66)
Browse files Browse the repository at this point in the history
* feat(bind): add implementation

* feat(bind): improve doc example

* fix: some errors with testing modules
  • Loading branch information
acostapazo authored Sep 14, 2023
1 parent d7c7dd0 commit d702314
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 12 deletions.
45 changes: 45 additions & 0 deletions docs/usage/result.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
| [`unwrap_or_else(on_failure_handler)`](#unwrap_or_else) | Returns the encapsulated value if this instance is a success or execute the `on_failure_handler` when it is failure. |
| [`unwrap_and(on_success_handler)`](#unwrap_and) | Returns the encapsulated value if this instance is a success and execute the `on_success_handler` when it is success. |
| [`handle(on_success_handler,on_failure_handler)`](#handle) | Returns itself and execute the `on_success_handler` when the instance is a success and the `on_failure_handler` when it is failure. |
| [`bind(func)`](#bind) | Returns itself binding success value with input func |
| [`transform()`](#transform) | Transform the result with a transformer function. You can give the transformer callable or use the set_transformer function to pre-set the callable to be used. |


Expand Down Expand Up @@ -320,6 +321,50 @@ Returns itself and execute the on_success_handler when the instance is a success
run(result)
```

### bind

Returns itself binding success value with input func

!!! question

What's the difference with handle?

It's quite similar but simpler. Bind only be applied to success value and don't accept external arguments
This function is very convenient for chaining actions on a result.


```python
from typing import Any

from meiga import Success

user = {"name": "rosalia de castro", "age": 186}

result = Success(user)


def upper_name(value: Any) -> Any:
value.update({"name": value["name"].upper()})
return value

def update_age(value: Any) -> Any:
value.update({"age": value["age"] + 1})
return value

def add_location(value: Any) -> Any:
value.update({"location": "GALIZA"})
return value


result = (
result
.bind(upper_name)
.bind(update_age)
.bind(add_location)
)
```


### `transform`

Transform the result with a transformer function. You can give the transformer callable or use the `set_transformer`
Expand Down
13 changes: 13 additions & 0 deletions meiga/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,19 @@ def handle(

return self

def bind(self, func: Callable[..., None]) -> Result[TS, TF]:
"""
Returns itself binding success value with input func
"""
value = self.unwrap()
if value is None:
return self

new_value = func(value)
self.set_value(new_value)

return self

def map(self, mapper: Callable[[TS | TF], Any]) -> None:
"""
Modifies encapsulate value applying a mapper function.
Expand Down
Empty file added tests/unit/doc/__init__.py
Empty file.
2 changes: 1 addition & 1 deletion tests/unit/doc/test_example_with_meiga.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from tests.unit.doc.example_with_meiga import NoSuchKey, TypeMismatch, string_from_key
from .example_with_meiga import NoSuchKey, TypeMismatch, string_from_key


@pytest.mark.unit
Expand Down
6 changes: 1 addition & 5 deletions tests/unit/doc/test_example_without_meiga.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import pytest

from tests.unit.doc.example_without_meiga import (
NoSuchKey,
TypeMismatch,
string_from_key,
)
from .example_without_meiga import NoSuchKey, TypeMismatch, string_from_key


@pytest.mark.unit
Expand Down
41 changes: 41 additions & 0 deletions tests/unit/test_result_bind.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import pytest

from meiga import Failure, Success


@pytest.mark.unit
def test_should_bind_a_success_result_encapsulated_value():
result = Success("hi")

def func(value: str):
return value.capitalize()

result.bind(func)

assert result.value == "Hi"


@pytest.mark.unit
def test_should_bind_several_times_success_result():
result = Success(0)

def func(value: int):
return value + 1

result.bind(func).bind(func).bind(func).bind(func).bind(func).bind(func).bind(
func
).bind(func).bind(func).bind(func)

assert result.value == 10


@pytest.mark.unit
def test_should_bind_and_keep_same_object_when_failure():
result = Failure("failure_value")

def func(value: str):
return value.capitalize()

result.bind(func)

assert result.value == "failure_value"
12 changes: 6 additions & 6 deletions tests/unit/test_result_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,25 @@


@pytest.mark.unit
def test_should_transform_a_success_result_encapsulated_value():
def transform(value):
def test_should_map_a_success_result_encapsulated_value():
def mapper(value):
return f"{value} Meiga"

result = Success("Hi")
result.map(transform)
result.map(mapper)

assert result.value == "Hi Meiga"


@pytest.mark.unit
def test_should_transform_a_failure_result_encapsulated_value():
def transform(domain_error):
def test_should_map_a_failure_result_encapsulated_value():
def mapper(domain_error):
if isinstance(domain_error, Error):
return "Error"
else:
return domain_error

result = Failure(Error())
result.map(transform)
result.map(mapper)

assert result.value == "Error"

0 comments on commit d702314

Please sign in to comment.