Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
* develop:
  specify next release
  update action version
  update actions version
  add Validation
  fix doc error
  • Loading branch information
Baptouuuu committed Nov 6, 2023
2 parents 9ba8332 + 94442fc commit 08558e5
Show file tree
Hide file tree
Showing 10 changed files with 991 additions and 8 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
name: 'BlackBox'
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
Expand All @@ -38,7 +38,7 @@ jobs:
name: 'Coverage'
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
Expand All @@ -54,7 +54,7 @@ jobs:
env:
ENABLE_COVERAGE: 'true'
BLACKBOX_SET_SIZE: 1
- uses: codecov/codecov-action@v1
- uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
psalm:
Expand All @@ -65,7 +65,7 @@ jobs:
name: 'Psalm'
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
Expand All @@ -83,7 +83,7 @@ jobs:
name: 'CS'
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 5.3.0 - 2023-11-06

### Added

- `Innmind\Immutable\Validation`

## 5.2.0 - 2023-11-05

### Added
Expand Down
4 changes: 2 additions & 2 deletions docs/EITHER.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function identify(ServerRequest $request): Either {
return Either::right($theUser);
}

Either::left(new Error('User not found'));
return Either::left(new Error('User not found'));
}

/**
Expand Down Expand Up @@ -83,7 +83,7 @@ This will apply the map transformation on the right value if there is one, other

```php
/** @var Either<Error, User> */
$either = identify($serverRequest)
$either = identify($serverRequest);
/** @var Either<Error, Impersonated> */
$impersonated = $either->map(fn(User $user): Impersonated => $user->impersonateAdmin());
```
Expand Down
3 changes: 2 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ composer require innmind/immutable

## Structures

This library provides the 7 following structures:
This library provides the 10 following structures:

- [`Sequence`](SEQUENCE.md)
- [`Set`](SET.md)
Expand All @@ -21,6 +21,7 @@ This library provides the 7 following structures:
- [`RegExp`](REGEXP.md)
- [`Maybe`](MAYBE.md)
- [`Either`](EITHER.md)
- [`Validation`](VALIDATION.md)
- [`State`](STATE.md)
- [`Fold`](FOLD.md)

Expand Down
176 changes: 176 additions & 0 deletions docs/VALIDATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# `Validation`

This structure is similar to [`Either`](EITHER.md) except that the right side is called success and left fail. The difference is that `Validation` allows to accumulate failures.

For the examples below we will use the given imaginary functions:

```php
use Innmind\Immutable\Validation;

/**
* @return Validation<Error, string>
*/
function isEmail(string $value): Validation {
if (\filter_var($value, \FILTER_VALIDATE_EMAIL)) {
return Validation::success($value);
}

return Validation::fail(new Error("$value is not an email"));
}

/**
* @return Validation<Error, string>
*/
function isLocal(string $value): Validation {
if (\str_ends_with($value, '.local')) {
return Validation::success($value);
}

return Validation::fail(new Error('Not a local email'));
}
```

> **Note**
> `Error` is imaginary class.
## `::fail()`

This builds a `Validation` instance with the given value in the fail side.

```php
$validation = Validation::fail($anyValue);
```

## `::success()`

This builds a `Validation` instance with the given value in the success side.

```php
$validation = Validation::success($anyValue);
```

## `->map()`

This will apply the map transformation on the success value if there is one, otherwise it's only a type change.

```php
/** @var Validation<Error, string> */
$validation = isEmail('[email protected]');
/** @var Either<Error, Email> */
$email = $validation->map(fn(string $email): Email => new Email($email));
```

## `->flatMap()`

This is similar to `->map()` but instead of returning the new success value you return a new `Validation` object.

```php
/** @var Validation<Error, string> */
$validation = isEmail('[email protected]');
/** @var Validation<Error, string> */
$localEmail = $either->flatMap(fn(string $email): Validation => isLocal($email));
```

## `->match()`

This is the only way to extract the wrapped value.

```php
/** @var Email */
$localEmail = isEmail($serverRequest)
->flatMap(fn(string $email): Validation => isLocal($email))
->map(static fn(string $email) => new Email($email))
->match(
fn(Email $email) => $email,
fn(Sequence $failures) => throw new \Exception(\implode(', ', $failure->toList())),
);
```

## `->otherwise()`

This is like `->flatMap()` but is called when the instance contains failures. The callable must return a new `Validation` object.

```php
/** @var Validation<Error, string> */
$email = isEmail('invalid value')
->otherwise(fn() => isEmail('[email protected]'));
```

## `->mapFailures()`

This is similar to the `->map()` function but will be applied on each failure.

```php
/** @var Either<Exception, string> */
$email = isEmail('[email protected]')
->mapFailures(fn(Error $error) => new \Exception($error->toString()));
```

## `->and()`

This method allows to aggregate the success values of 2 `Validation` objects or aggregates the failures if at least one of them is a failure.

```php
$foo = isEmail('[email protected]');
$bar = isEmail('[email protected]');
$baz = isEmail('invalid value');
$foobar = isEmail('another value');

$foo
->and(
$bar,
static fn($a, $b) => [$a, $b],
)
->match(
static fn($value) => $value,
static fn() => null,
); // returns ['[email protected]', '[email protected]']
$foo
->and(
$baz,
static fn($a, $b) => [$a, $b],
)
->match(
static fn() => null,
static fn($failures) => $failures->toList(),
); // returns [new Error('invalid value is not an email')]
$foobar
->and(
$baz,
static fn($a, $b) => [$a, $b],
)
->match(
static fn() => null,
static fn($failures) => $failures->toList(),
); // returns [new Error('another value is not an email'), new Error('invalid value is not an email')]
```

## `->maybe()`

This returns a [`Maybe`](MAYBE.md) containing the success value, in case of failures it returns a `Maybe` with nothing inside.

```php
Validation::success('something')->maybe()->match(
static fn($value) => $value,
static fn() => null,
); // returns 'something'
Validation::fail('something')->maybe()->match(
static fn($value) => $value,
static fn() => null,
); // returns null
```

## `->either()`

This returns an [`Either`](EITHER.md) containing the success value as the right side, in case of failures it returns an `Either` with failures as the left side.

```php
Validation::success('something')->either()->match(
static fn($value) => $value,
static fn() => null,
); // returns 'something'
Validation::fail('something')->either()->match(
static fn() => null,
static fn($value) => $value,
); // returns Sequence<string>
```
Loading

0 comments on commit 08558e5

Please sign in to comment.