Compare commits
3 Commits
v1.0.0-bet
...
v1.0.0-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
| 6779b2c554 | |||
| fad428a4e4 | |||
| 57af645d87 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
.idea
|
.idea
|
||||||
vendor
|
vendor
|
||||||
|
*.tests.txt
|
||||||
|
|||||||
29
README.md
29
README.md
@@ -7,24 +7,31 @@ This project contains PHP utility classes whose functionality is inspired by the
|
|||||||
This early-stage library currently provides two classes, both of which are designed to wrap values and indicate the state of the action that produced them. `Option<T>` represents a variable that may or may not have a value. `Result<TOK, TError>` represents the result of an action; the "ok" and "error" states both provide a value.
|
This early-stage library currently provides two classes, both of which are designed to wrap values and indicate the state of the action that produced them. `Option<T>` represents a variable that may or may not have a value. `Result<TOK, TError>` represents the result of an action; the "ok" and "error" states both provide a value.
|
||||||
|
|
||||||
| | `Option<T>`<br>Replaces `null` checks | `Result<TOK, TError>`<br>Replaces exception-based error handling |
|
| | `Option<T>`<br>Replaces `null` checks | `Result<TOK, TError>`<br>Replaces exception-based error handling |
|
||||||
|----------------------------------------------------|--------------------------------------------------------------------------------|------------------------------------------------------------------|
|
|---------------------------------------------------|-------------------------------------------------------|-----------------------------------------------------------------------------|
|
||||||
| **Creating** | `::Some(T)` for Some<br>`::None()` for None<br>`::of($value)` _None if `null`_ | `::OK(TOK)` for OK<br>`::Error(TError)` for Error |
|
| **Creating** | `::Some(T)` for Some | `::OK(TOK)` for OK |
|
||||||
| **Querying** | `->isSome()`<br>`->isNone()` | `->isOK()`<br>`->isError()` |
|
| | `::None()` for None | `::Error(TError)` for Error |
|
||||||
| **Reading**<br>_throws if called on missing value_ | `->get()` | `->getOK()`<br>`->getError()` |
|
| | `::of($value)` _None if `null`_ | |
|
||||||
| **Transforming**<br>_still `Option` or `Result`_ | `->map(callable(T): U)` | `->map(callable(TOK): U)`<br>`->mapError(callable(TError): U)` |
|
| **Querying** | `->isSome(): bool` | `->isOK(): bool` |
|
||||||
| **Iterating** | `->iter(callable(T): void)` | `->iter(callable(TOK): void)` |
|
| | `->isNone(): bool` | `->isError(): bool` |
|
||||||
| **Inspecting**<br>_returns the original instance_ | `->tap(callable(Option<T>): void)` | `->tap(callable(Result<TOK, TError>): void)` |
|
| | `->contains(T, $strict = true): bool` | `->contains(TOK, $strict = true): bool` |
|
||||||
|
| | `->exists(callable(T): bool): bool` | `->exists(callable(TOK): bool): bool` |
|
||||||
|
| **Reading**<br> | `->get(): T` | `->getOK(): TOK` |
|
||||||
|
| _all throw if called on missing value_ | | `->getError(): TError` |
|
||||||
|
| **Transforming**<br> | `->map(callable(T): TMapped): Option<TMapped>` | `->map(callable(TOK): TMapped): Result<TMapped, TError>` |
|
||||||
|
| _all still `Option` or `Result`_ | | `->mapError(callable(TError): TMapped): Result<TOK, TMapped>` |
|
||||||
|
| **Iterating** | `->iter(callable(T): void): void` | `->iter(callable(TOK): void): void` |
|
||||||
|
| **Inspecting**<br>_returns the original instance_ | `->tap(callable(Option<T>): void): Option<T>` | `->tap(callable(Result<TOK, TError>): void): Result<TOK, TError>` |
|
||||||
|
| **Continued Processing** | `->bind(callable(T): Option<TBound>): Option<TBound>` | `->bind(callable(TOK): Result<TBoundOK, TError>): Result<TBoundOK, TError>` |
|
||||||
|
| **Changing Types** | `->toArray(): T[]` | `->toArray(): TOK[]` |
|
||||||
|
| | | `->toOption(): Option<TOK>` |
|
||||||
|
|
||||||
In addition to this, `Option<T>` provides:
|
In addition to this, `Option<T>` provides:
|
||||||
- `->getOrDefault(T)` will return the Some value if it exists or the given default if the option is None.
|
- `->getOrDefault(T)` will return the Some value if it exists or the given default if the option is None.
|
||||||
- `->getOrCall(callable(): mixed)` will call the given function if the option is None. That function may return a value, or may be `void` or `never`.
|
- `->getOrCall(callable(): mixed)` will call the given function if the option is None. That function may return a value, or may be `void` or `never`.
|
||||||
|
- `->getOrThrow(callable(): Exception)` will return the Some value if it exists, or throw the exception returned by the function if the option is None.
|
||||||
- `->filter(callable(T): bool)` will compare a Some value against the callable, and if it returns `true`, will remain Some; if it returns `false`, the value will become None.
|
- `->filter(callable(T): bool)` will compare a Some value against the callable, and if it returns `true`, will remain Some; if it returns `false`, the value will become None.
|
||||||
- `->is(T, $strict = true)` will return `true` if the option is Some and the value matches. Strict equality (the default) uses `===` for the comparison; if strict is set to `false`, the comparison will use `==` instead.
|
|
||||||
- `->unwrap()` will return `null` for None options and the value for Some options.
|
- `->unwrap()` will return `null` for None options and the value for Some options.
|
||||||
|
|
||||||
`Result<TOK, TError>` also provides:
|
|
||||||
- `toOption()` will transform an OK result to a Some option, and an Error result to a None option.
|
|
||||||
|
|
||||||
Finally, we would be remiss to not acknowledge some really cool prior art in this area - the [PhpOption](https://github.com/schmittjoh/php-option) project. `Option::of` recognizes their options and converts them properly, and `Option<T>` instances have a `->toPhpOption()` method that will convert these back into PhpOption's `Some<T>` and `None` instances. There is also a [ResultType](https://github.com/GrahamCampbell/Result-Type) project from the same team, though this project's result does not (yet) have any conversion methods for it.
|
Finally, we would be remiss to not acknowledge some really cool prior art in this area - the [PhpOption](https://github.com/schmittjoh/php-option) project. `Option::of` recognizes their options and converts them properly, and `Option<T>` instances have a `->toPhpOption()` method that will convert these back into PhpOption's `Some<T>` and `None` instances. There is also a [ResultType](https://github.com/GrahamCampbell/Result-Type) project from the same team, though this project's result does not (yet) have any conversion methods for it.
|
||||||
|
|
||||||
## The Inspiration
|
## The Inspiration
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
"rss": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp.rss"
|
"rss": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp.rss"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2"
|
"php": "8.2 - 8.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^11",
|
"phpunit/phpunit": "^11",
|
||||||
|
|||||||
114
composer.lock
generated
114
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "9c9d70d95d369f37fa95a10637a56a58",
|
"content-hash": "e08185f1629cdda5af3af5405a707797",
|
||||||
"packages": [],
|
"packages": [],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
@@ -69,16 +69,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nikic/php-parser",
|
"name": "nikic/php-parser",
|
||||||
"version": "v5.1.0",
|
"version": "v5.3.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||||
"reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1"
|
"reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1",
|
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3abf7425cd284141dc5d8d14a9ee444de3345d1a",
|
||||||
"reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1",
|
"reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -121,9 +121,9 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0"
|
"source": "https://github.com/nikic/PHP-Parser/tree/v5.3.0"
|
||||||
},
|
},
|
||||||
"time": "2024-07-01T20:03:41+00:00"
|
"time": "2024-09-29T13:56:26+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phar-io/manifest",
|
"name": "phar-io/manifest",
|
||||||
@@ -320,32 +320,32 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
"version": "11.0.5",
|
"version": "11.0.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||||
"reference": "19b6365ab8b59a64438c0c3f4241feeb480c9861"
|
"reference": "ebdffc9e09585dafa71b9bffcdb0a229d4704c45"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/19b6365ab8b59a64438c0c3f4241feeb480c9861",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ebdffc9e09585dafa71b9bffcdb0a229d4704c45",
|
||||||
"reference": "19b6365ab8b59a64438c0c3f4241feeb480c9861",
|
"reference": "ebdffc9e09585dafa71b9bffcdb0a229d4704c45",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-libxml": "*",
|
"ext-libxml": "*",
|
||||||
"ext-xmlwriter": "*",
|
"ext-xmlwriter": "*",
|
||||||
"nikic/php-parser": "^5.0",
|
"nikic/php-parser": "^5.1.0",
|
||||||
"php": ">=8.2",
|
"php": ">=8.2",
|
||||||
"phpunit/php-file-iterator": "^5.0",
|
"phpunit/php-file-iterator": "^5.0.1",
|
||||||
"phpunit/php-text-template": "^4.0",
|
"phpunit/php-text-template": "^4.0.1",
|
||||||
"sebastian/code-unit-reverse-lookup": "^4.0",
|
"sebastian/code-unit-reverse-lookup": "^4.0.1",
|
||||||
"sebastian/complexity": "^4.0",
|
"sebastian/complexity": "^4.0.1",
|
||||||
"sebastian/environment": "^7.0",
|
"sebastian/environment": "^7.2.0",
|
||||||
"sebastian/lines-of-code": "^3.0",
|
"sebastian/lines-of-code": "^3.0.1",
|
||||||
"sebastian/version": "^5.0",
|
"sebastian/version": "^5.0.1",
|
||||||
"theseer/tokenizer": "^1.2.0"
|
"theseer/tokenizer": "^1.2.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^11.0"
|
"phpunit/phpunit": "^11.0"
|
||||||
@@ -357,7 +357,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-main": "11.0-dev"
|
"dev-main": "11.0.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -386,7 +386,7 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.5"
|
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.6"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -394,20 +394,20 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-07-03T05:05:37+00:00"
|
"time": "2024-08-22T04:37:56+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-file-iterator",
|
"name": "phpunit/php-file-iterator",
|
||||||
"version": "5.0.1",
|
"version": "5.1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||||
"reference": "6ed896bf50bbbfe4d504a33ed5886278c78e4a26"
|
"reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6ed896bf50bbbfe4d504a33ed5886278c78e4a26",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6",
|
||||||
"reference": "6ed896bf50bbbfe4d504a33ed5886278c78e4a26",
|
"reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -447,7 +447,7 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
|
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
|
"security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.0.1"
|
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -455,7 +455,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-07-03T05:06:37+00:00"
|
"time": "2024-08-27T05:02:59+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-invoker",
|
"name": "phpunit/php-invoker",
|
||||||
@@ -643,16 +643,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
"version": "11.2.8",
|
"version": "11.3.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||||
"reference": "a7a29e8d3113806f18f99d670f580a30e8ffff39"
|
"reference": "d62c45a19c665bb872c2a47023a0baf41a98bb2b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a7a29e8d3113806f18f99d670f580a30e8ffff39",
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d62c45a19c665bb872c2a47023a0baf41a98bb2b",
|
||||||
"reference": "a7a29e8d3113806f18f99d670f580a30e8ffff39",
|
"reference": "d62c45a19c665bb872c2a47023a0baf41a98bb2b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -666,20 +666,20 @@
|
|||||||
"phar-io/manifest": "^2.0.4",
|
"phar-io/manifest": "^2.0.4",
|
||||||
"phar-io/version": "^3.2.1",
|
"phar-io/version": "^3.2.1",
|
||||||
"php": ">=8.2",
|
"php": ">=8.2",
|
||||||
"phpunit/php-code-coverage": "^11.0.5",
|
"phpunit/php-code-coverage": "^11.0.6",
|
||||||
"phpunit/php-file-iterator": "^5.0.1",
|
"phpunit/php-file-iterator": "^5.1.0",
|
||||||
"phpunit/php-invoker": "^5.0.1",
|
"phpunit/php-invoker": "^5.0.1",
|
||||||
"phpunit/php-text-template": "^4.0.1",
|
"phpunit/php-text-template": "^4.0.1",
|
||||||
"phpunit/php-timer": "^7.0.1",
|
"phpunit/php-timer": "^7.0.1",
|
||||||
"sebastian/cli-parser": "^3.0.2",
|
"sebastian/cli-parser": "^3.0.2",
|
||||||
"sebastian/code-unit": "^3.0.1",
|
"sebastian/code-unit": "^3.0.1",
|
||||||
"sebastian/comparator": "^6.0.1",
|
"sebastian/comparator": "^6.1.0",
|
||||||
"sebastian/diff": "^6.0.2",
|
"sebastian/diff": "^6.0.2",
|
||||||
"sebastian/environment": "^7.2.0",
|
"sebastian/environment": "^7.2.0",
|
||||||
"sebastian/exporter": "^6.1.3",
|
"sebastian/exporter": "^6.1.3",
|
||||||
"sebastian/global-state": "^7.0.2",
|
"sebastian/global-state": "^7.0.2",
|
||||||
"sebastian/object-enumerator": "^6.0.1",
|
"sebastian/object-enumerator": "^6.0.1",
|
||||||
"sebastian/type": "^5.0.1",
|
"sebastian/type": "^5.1.0",
|
||||||
"sebastian/version": "^5.0.1"
|
"sebastian/version": "^5.0.1"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
@@ -691,7 +691,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-main": "11.2-dev"
|
"dev-main": "11.3-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -723,7 +723,7 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.2.8"
|
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.3.6"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -739,7 +739,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-07-18T14:56:37+00:00"
|
"time": "2024-09-19T10:54:28+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/cli-parser",
|
"name": "sebastian/cli-parser",
|
||||||
@@ -913,16 +913,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/comparator",
|
"name": "sebastian/comparator",
|
||||||
"version": "6.0.1",
|
"version": "6.1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||||
"reference": "131942b86d3587291067a94f295498ab6ac79c20"
|
"reference": "fa37b9e2ca618cb051d71b60120952ee8ca8b03d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/131942b86d3587291067a94f295498ab6ac79c20",
|
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa37b9e2ca618cb051d71b60120952ee8ca8b03d",
|
||||||
"reference": "131942b86d3587291067a94f295498ab6ac79c20",
|
"reference": "fa37b9e2ca618cb051d71b60120952ee8ca8b03d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -933,12 +933,12 @@
|
|||||||
"sebastian/exporter": "^6.0"
|
"sebastian/exporter": "^6.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^11.0"
|
"phpunit/phpunit": "^11.3"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-main": "6.0-dev"
|
"dev-main": "6.1-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -978,7 +978,7 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/comparator/issues",
|
"issues": "https://github.com/sebastianbergmann/comparator/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
|
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/comparator/tree/6.0.1"
|
"source": "https://github.com/sebastianbergmann/comparator/tree/6.1.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -986,7 +986,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-07-03T04:48:07+00:00"
|
"time": "2024-09-11T15:42:56+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/complexity",
|
"name": "sebastian/complexity",
|
||||||
@@ -1555,28 +1555,28 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/type",
|
"name": "sebastian/type",
|
||||||
"version": "5.0.1",
|
"version": "5.1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/type.git",
|
"url": "https://github.com/sebastianbergmann/type.git",
|
||||||
"reference": "fb6a6566f9589e86661291d13eba708cce5eb4aa"
|
"reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb6a6566f9589e86661291d13eba708cce5eb4aa",
|
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/461b9c5da241511a2a0e8f240814fb23ce5c0aac",
|
||||||
"reference": "fb6a6566f9589e86661291d13eba708cce5eb4aa",
|
"reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=8.2"
|
"php": ">=8.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^11.0"
|
"phpunit/phpunit": "^11.3"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-main": "5.0-dev"
|
"dev-main": "5.1-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -1600,7 +1600,7 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/type/issues",
|
"issues": "https://github.com/sebastianbergmann/type/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/type/security/policy",
|
"security": "https://github.com/sebastianbergmann/type/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/type/tree/5.0.1"
|
"source": "https://github.com/sebastianbergmann/type/tree/5.1.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -1608,7 +1608,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-07-03T05:11:49+00:00"
|
"time": "2024-09-17T13:12:04+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/version",
|
"name": "sebastian/version",
|
||||||
@@ -1721,7 +1721,7 @@
|
|||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": "^8"
|
"php": "8.2 - 8.3"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": [],
|
||||||
"plugin-api-version": "2.6.0"
|
"plugin-api-version": "2.6.0"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||||||
namespace BitBadger\InspiredByFSharp;
|
namespace BitBadger\InspiredByFSharp;
|
||||||
|
|
||||||
use Error;
|
use Error;
|
||||||
|
use Exception;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,21 +85,73 @@ readonly class Option
|
|||||||
/**
|
/**
|
||||||
* Get the value, or return the value of a callable function
|
* Get the value, or return the value of a callable function
|
||||||
*
|
*
|
||||||
* @template U The return type of the callable provided
|
* @template TCalled The return type of the callable provided
|
||||||
* @param callable(): U $f The callable function to use for `None` options
|
* @param callable(): TCalled $f The callable function to use for `None` options
|
||||||
* @return T|mixed The value if `Some`, the result of the callable if `None`
|
* @return T|TCalled The value if `Some`, the result of the callable if `None`
|
||||||
*/
|
*/
|
||||||
public function getOrCall(callable $f): mixed
|
public function getOrCall(callable $f): mixed
|
||||||
{
|
{
|
||||||
return $this->value ?? $f();
|
return $this->value ?? $f();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value, or throw the
|
||||||
|
* @param callable(): Exception $exFunc A function to construct the exception to throw
|
||||||
|
* @return T The value of the option if `Some`
|
||||||
|
* @throws Exception If the option is `None`
|
||||||
|
*/
|
||||||
|
public function getOrThrow(callable $exFunc): mixed
|
||||||
|
{
|
||||||
|
return $this->value ?? throw $exFunc();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a function to this option (railway processing)
|
||||||
|
*
|
||||||
|
* If this option is Some, the function will be called with the option's value. If this option is None, it will be
|
||||||
|
* immediately returned.
|
||||||
|
*
|
||||||
|
* @template TBound The type returned by Some in the bound function
|
||||||
|
* @param callable(T): Option<TBound> $f The function that will receive the Some value; can return a different type
|
||||||
|
* @return Option<TBound> The updated option if the starting value was Some, None otherwise
|
||||||
|
*/
|
||||||
|
public function bind(callable $f): Option
|
||||||
|
{
|
||||||
|
return $this->isNone() ? $this : $f($this->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the option contain the given value?
|
||||||
|
*
|
||||||
|
* @param T $value The value to be checked
|
||||||
|
* @param bool $strict True for strict equality (`===`), false for loose equality (`==`); optional, default is true
|
||||||
|
* @return bool True if the value matches, false if not; `None` always returns false
|
||||||
|
*/
|
||||||
|
public function contains(mixed $value, bool $strict = true): bool
|
||||||
|
{
|
||||||
|
return match (true) {
|
||||||
|
$this->isNone() => false,
|
||||||
|
default => $strict ? $this->value === $value : $this->value == $value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the value of the option match the given predicate function?
|
||||||
|
*
|
||||||
|
* @param callable(T): bool $f The function to determine whether the value matches
|
||||||
|
* @return bool True if the `Some` value matches the function, false otherwise
|
||||||
|
*/
|
||||||
|
public function exists(callable $f): bool
|
||||||
|
{
|
||||||
|
return $this->isSome() ? $f($this->value) : false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map this optional value to another value
|
* Map this optional value to another value
|
||||||
*
|
*
|
||||||
* @template U The type of the mapping function
|
* @template TMapped The type of the mapping function
|
||||||
* @param callable(T): U $f The mapping function
|
* @param callable(T): TMapped $f The mapping function
|
||||||
* @return Option<U> A `Some` instance with the transformed value if `Some`, `None` otherwise
|
* @return Option<TMapped> A `Some` instance with the transformed value if `Some`, `None` otherwise
|
||||||
*/
|
*/
|
||||||
public function map(callable $f): self
|
public function map(callable $f): self
|
||||||
{
|
{
|
||||||
@@ -125,25 +178,7 @@ readonly class Option
|
|||||||
*/
|
*/
|
||||||
public function filter(callable $f): self
|
public function filter(callable $f): self
|
||||||
{
|
{
|
||||||
return match (true) {
|
return $this->isNone() || $this->exists($f) ? $this : self::None();
|
||||||
$this->isNone() => $this,
|
|
||||||
default => $f($this->value) ? $this : self::None(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does the option have the given value?
|
|
||||||
*
|
|
||||||
* @param T $value The value to be checked
|
|
||||||
* @param bool $strict True for strict equality (`===`), false for loose equality (`==`)
|
|
||||||
* @return bool True if the value matches, false if not; `None` always returns false
|
|
||||||
*/
|
|
||||||
public function is(mixed $value, bool $strict = true): bool
|
|
||||||
{
|
|
||||||
return match (true) {
|
|
||||||
$this->isNone() => false,
|
|
||||||
default => $strict ? $this->value === $value : $this->value == $value,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,6 +203,16 @@ readonly class Option
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert this option into a 0 or 1 item array
|
||||||
|
*
|
||||||
|
* @return T[] An empty array for `None`, a 1-item array for `Some`
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return $this->isSome() ? [$this->value] : [];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert this to a PhpOption option
|
* Convert this to a PhpOption option
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -87,12 +87,54 @@ readonly class Result
|
|||||||
return $this->errorValue->isSome();
|
return $this->errorValue->isSome();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a function to this result (railway processing)
|
||||||
|
*
|
||||||
|
* If this result is OK, the function will be called with the OK value of the result. If this result is Error, it
|
||||||
|
* will be immediately returned. This allows for a sequence of functions to proceed on the happy path (OK all the
|
||||||
|
* way), or be shunted off to the exit ramp once an error occurs.
|
||||||
|
*
|
||||||
|
* @template TBoundOK The type returned by OK in the bound function
|
||||||
|
* @param callable(TOK): Result<TBoundOK, TError> $f The function that will receive the OK value; can return a different type
|
||||||
|
* @return Result<TBoundOK, TError> The updated result if the function was successful, an error otherwise
|
||||||
|
*/
|
||||||
|
public function bind(callable $f): Result
|
||||||
|
{
|
||||||
|
return $this->isError() ? $this : $f($this->getOK());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this result's "OK" value match the given value?
|
||||||
|
*
|
||||||
|
* @param TOK $value The value to be matched
|
||||||
|
* @param bool $strict True for strict equality (`===`), false for loose equality (`==`); optional, default is true
|
||||||
|
* @return bool True if the "OK" value matches the one provided, false otherwise
|
||||||
|
*/
|
||||||
|
public function contains(mixed $value, bool $strict = true): bool
|
||||||
|
{
|
||||||
|
return match (true) {
|
||||||
|
$this->isError() => false,
|
||||||
|
default => $this->okValue->contains($value, $strict),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the "OK" value of this result match the given predicate function?
|
||||||
|
*
|
||||||
|
* @param callable(TOK): bool $f The function to determine whether the value matches
|
||||||
|
* @return bool True if the OK value matches the function, false otherwise
|
||||||
|
*/
|
||||||
|
public function exists(callable $f): bool
|
||||||
|
{
|
||||||
|
return $this->isOK() ? $f($this->okValue->get()) : false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map an `OK` result to another, leaving an `Error` result unmodified
|
* Map an `OK` result to another, leaving an `Error` result unmodified
|
||||||
*
|
*
|
||||||
* @template U The type of the mapping function
|
* @template TMapped The type of the mapping function
|
||||||
* @param callable(TOK): U $f The mapping function
|
* @param callable(TOK): TMapped $f The mapping function
|
||||||
* @return Result<U, TError> A transformed `OK` instance or the original `Error` instance
|
* @return Result<TMapped, TError> A transformed `OK` instance or the original `Error` instance
|
||||||
*/
|
*/
|
||||||
public function map(callable $f): self
|
public function map(callable $f): self
|
||||||
{
|
{
|
||||||
@@ -102,9 +144,9 @@ readonly class Result
|
|||||||
/**
|
/**
|
||||||
* Map an `Error` result to another, leaving an `OK` result unmodified
|
* Map an `Error` result to another, leaving an `OK` result unmodified
|
||||||
*
|
*
|
||||||
* @template U The type of the mapping function
|
* @template TMapped The type of the mapping function
|
||||||
* @param callable(TError): U $f The mapping function
|
* @param callable(TError): TMapped $f The mapping function
|
||||||
* @return Result<TOK, U> A transformed `Error` instance or the original `OK` instance
|
* @return Result<TOK, TMapped> A transformed `Error` instance or the original `OK` instance
|
||||||
*/
|
*/
|
||||||
public function mapError(callable $f): self
|
public function mapError(callable $f): self
|
||||||
{
|
{
|
||||||
@@ -123,6 +165,16 @@ readonly class Result
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert this result into a 0 or 1 item array
|
||||||
|
*
|
||||||
|
* @return TOK[] An empty array for `Error`, a 1-item array for `OK`
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return $this->okValue->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform a `Result`'s `OK` value to an `Option`
|
* Transform a `Result`'s `OK` value to an `Option`
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Test;
|
namespace Test;
|
||||||
|
|
||||||
|
use BadMethodCallException;
|
||||||
use BitBadger\InspiredByFSharp\Option;
|
use BitBadger\InspiredByFSharp\Option;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use PhpOption\{None, Some};
|
use PhpOption\{None, Some};
|
||||||
@@ -85,6 +86,92 @@ class OptionTest extends TestCase
|
|||||||
$this->assertEquals('passed', $value, 'The value should have been obtained from the option');
|
$this->assertEquals('passed', $value, 'The value should have been obtained from the option');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[TestDox('GetOrThrow succeeds with Some')]
|
||||||
|
public function testGetOrThrowSucceedsWithSome(): void
|
||||||
|
{
|
||||||
|
$value = Option::Some('no throw')->getOrThrow(fn() => new BadMethodCallException('oops'));
|
||||||
|
$this->assertEquals('no throw', $value, 'The "Some" value should have been returned');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('GetOrThrow succeeds with None')]
|
||||||
|
public function testGetOrThrowSucceedsWithNone(): void
|
||||||
|
{
|
||||||
|
$this->expectException(BadMethodCallException::class);
|
||||||
|
Option::None()->getOrThrow(fn() => new BadMethodCallException('oops'));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Bind succeeds with None')]
|
||||||
|
public function testBindSucceedsWithNone(): void
|
||||||
|
{
|
||||||
|
$original = Option::None();
|
||||||
|
$bound = $original->bind(fn($it) => Option::Some('value'));
|
||||||
|
$this->assertTrue($bound->isNone(), 'The option should have been None');
|
||||||
|
$this->assertSame($original, $bound, 'The same None instance should have been returned');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Bind succeeds with Some and Some')]
|
||||||
|
public function testBindSucceedsWithSomeAndSome(): void
|
||||||
|
{
|
||||||
|
$bound = Option::Some('hello')->bind(fn($it) => Option::Some('goodbye'));
|
||||||
|
$this->assertTrue($bound->isSome(), 'The option should have been Some');
|
||||||
|
$this->assertEquals('goodbye', $bound->get(), 'The bound function was not called');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Bind succeeds with Some and None')]
|
||||||
|
public function testBindSucceedsWithSomeAndNone(): void
|
||||||
|
{
|
||||||
|
$bound = Option::Some('greetings')->bind(fn($it) => Option::None());
|
||||||
|
$this->assertTrue($bound->isNone(), 'The option should have been None');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Contains succeeds with None')]
|
||||||
|
public function testContainsSucceedsWithNone(): void
|
||||||
|
{
|
||||||
|
$this->assertFalse(Option::None()->contains(null), '"None" should always return false');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Contains succeeds with Some when strictly equal')]
|
||||||
|
public function testContainsSucceedsWithSomeWhenStrictlyEqual(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue(Option::Some(3)->contains(3), '"Some" with strict equality should be true');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Contains succeeds with Some when strictly unequal')]
|
||||||
|
public function testContainsSucceedsWithSomeWhenStrictlyUnequal(): void
|
||||||
|
{
|
||||||
|
$this->assertFalse(Option::Some('3')->contains(3), '"Some" with strict equality should be false');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Contains succeeds with Some when loosely equal')]
|
||||||
|
public function testContainsSucceedsWithSomeWhenLooselyEqual(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue(Option::Some('3')->contains(3, strict: false), '"Some" with loose equality should be true');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Contains succeeds with Some when loosely unequal')]
|
||||||
|
public function testContainsSucceedsWithSomeWhenLooselyUnequal(): void
|
||||||
|
{
|
||||||
|
$this->assertFalse(Option::Some('3')->contains(4, strict: false), '"Some" with loose equality should be false');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Exists succeeds with Some when matching')]
|
||||||
|
public function testExistsSucceedsWithSomeWhenMatching(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue(Option::Some(14)->exists(fn($it) => $it < 100), 'Exists should have returned true');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Exists succeeds with Some when not matching')]
|
||||||
|
public function testExistsSucceedsWithSomeWhenNotMatching(): void
|
||||||
|
{
|
||||||
|
$this->assertFalse(Option::Some(14)->exists(fn($it) => $it > 100), 'Exists should have returned false');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Exists succeeds with None')]
|
||||||
|
public function testExistsSucceedsWithNone(): void
|
||||||
|
{
|
||||||
|
$this->assertFalse(Option::None()->exists(fn($it) => true), 'Exists should have returned false');
|
||||||
|
}
|
||||||
|
|
||||||
#[TestDox('Map succeeds with None')]
|
#[TestDox('Map succeeds with None')]
|
||||||
public function testMapSucceedsWithNone(): void
|
public function testMapSucceedsWithNone(): void
|
||||||
{
|
{
|
||||||
@@ -164,36 +251,6 @@ class OptionTest extends TestCase
|
|||||||
$this->assertTrue($filtered->isNone(), 'The filtered option should have been "None"');
|
$this->assertTrue($filtered->isNone(), 'The filtered option should have been "None"');
|
||||||
}
|
}
|
||||||
|
|
||||||
#[TestDox('Is succeeds with None')]
|
|
||||||
public function testIsSucceedsWithNone(): void
|
|
||||||
{
|
|
||||||
$this->assertFalse(Option::None()->is(null), '"None" should always return false');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('Is succeeds with Some when strictly equal')]
|
|
||||||
public function testIsSucceedsWithSomeWhenStrictlyEqual(): void
|
|
||||||
{
|
|
||||||
$this->assertTrue(Option::Some(3)->is(3), '"Some" with strict equality should be true');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('Is succeeds with Some when strictly unequal')]
|
|
||||||
public function testIsSucceedsWithSomeWhenStrictlyUnequal(): void
|
|
||||||
{
|
|
||||||
$this->assertFalse(Option::Some('3')->is(3), '"Some" with strict equality should be false');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('Is succeeds with Some when loosely equal')]
|
|
||||||
public function testIsSucceedsWithSomeWhenLooselyEqual(): void
|
|
||||||
{
|
|
||||||
$this->assertTrue(Option::Some('3')->is(3, strict: false), '"Some" with loose equality should be true');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('Is succeeds with Some when loosely unequal')]
|
|
||||||
public function testIsSucceedsWithSomeWhenLooselyUnequal(): void
|
|
||||||
{
|
|
||||||
$this->assertFalse(Option::Some('3')->is(4, strict: false), '"Some" with loose equality should be false');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('Unwrap succeeds with None')]
|
#[TestDox('Unwrap succeeds with None')]
|
||||||
public function testUnwrapSucceedsWithNone(): void
|
public function testUnwrapSucceedsWithNone(): void
|
||||||
{
|
{
|
||||||
@@ -228,6 +285,22 @@ class OptionTest extends TestCase
|
|||||||
$this->assertSame($original, $tapped, 'The same option should have been returned');
|
$this->assertSame($original, $tapped, 'The same option should have been returned');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[TestDox('ToArray succeeds with Some')]
|
||||||
|
public function testToArraySucceedsWithSome(): void
|
||||||
|
{
|
||||||
|
$arr = Option::Some('15')->toArray();
|
||||||
|
$this->assertNotNull($arr, 'The array should not have been null');
|
||||||
|
$this->assertEquals(['15'], $arr, 'The array was not created correctly');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('ToArray succeeds with None')]
|
||||||
|
public function testToArraySucceedsWithNone(): void
|
||||||
|
{
|
||||||
|
$arr = Option::None()->toArray();
|
||||||
|
$this->assertNotNull($arr, 'The array should not have been null');
|
||||||
|
$this->assertEmpty($arr, 'The array should have been empty');
|
||||||
|
}
|
||||||
|
|
||||||
#[TestDox('ToPhpOption succeeds for Some')]
|
#[TestDox('ToPhpOption succeeds for Some')]
|
||||||
public function testToPhpOptionSucceedsForSome(): void
|
public function testToPhpOptionSucceedsForSome(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -74,6 +74,80 @@ class ResultTest extends TestCase
|
|||||||
$this->assertFalse($result->isError(), 'The check for "Error" should have returned false');
|
$this->assertFalse($result->isError(), 'The check for "Error" should have returned false');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[TestDox('Bind succeeds for OK with OK')]
|
||||||
|
public function testBindSucceedsForOKWithOK(): void
|
||||||
|
{
|
||||||
|
$result = Result::OK('one')->bind(fn($it) => Result::OK("$it two"));
|
||||||
|
$this->assertTrue($result->isOK(), 'The result should have been OK');
|
||||||
|
$this->assertEquals('one two', $result->getOK(), 'The bound function was not called');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Bind succeeds for OK with Error')]
|
||||||
|
public function testBindSucceedsForOKWithError(): void
|
||||||
|
{
|
||||||
|
$result = Result::OK('three')->bind(fn($it) => Result::Error('back to two'));
|
||||||
|
$this->assertTrue($result->isError(), 'The result should have been Error');
|
||||||
|
$this->assertEquals('back to two', $result->getError(), 'The bound function was not called');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Bind succeeds for Error')]
|
||||||
|
public function testBindSucceedsForError(): void
|
||||||
|
{
|
||||||
|
$original = Result::Error('oops');
|
||||||
|
$result = $original->bind(fn($it) => Result::OK('never mind - it worked!'));
|
||||||
|
$this->assertTrue($result->isError(), 'The result should have been Error');
|
||||||
|
$this->assertSame($original, $result, 'The same Error result should have been returned');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[TestDox('Contains succeeds for Error result')]
|
||||||
|
public function testContainsSucceedsForErrorResult(): void
|
||||||
|
{
|
||||||
|
$this->assertFalse(Result::Error('ouch')->contains('ouch'), '"Error" should always return false');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Contains succeeds for OK result when strictly equal')]
|
||||||
|
public function testContainsSucceedsForOKResultWhenStrictlyEqual(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue(Result::OK(18)->contains(18), '"OK" with strict equality should be true');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Contains succeeds for OK result when strictly unequal')]
|
||||||
|
public function testContainsSucceedsForOKResultWhenStrictlyUnequal(): void
|
||||||
|
{
|
||||||
|
$this->assertFalse(Result::OK(18)->contains('18'), '"OK" with strict equality should be false');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Contains succeeds for OK result when loosely equal')]
|
||||||
|
public function testContainsSucceedsForOKResultWhenLooselyEqual(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue(Result::OK(18)->contains('18', strict: false), '"OK" with loose equality should be true');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Contains succeeds for OK result when loosely unequal')]
|
||||||
|
public function testContainsSucceedsForOKResultWhenLooselyUnequal(): void
|
||||||
|
{
|
||||||
|
$this->assertFalse(Result::OK(18)->contains(17, strict: false), '"OK" with loose equality should be false');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Exists succeeds for OK result when matching')]
|
||||||
|
public function testExistsSucceedsForOKResultWhenMatching(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue(Result::OK(14)->exists(fn($it) => $it < 100), 'Exists should have returned true');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Exists succeeds for OK result when not matching')]
|
||||||
|
public function testExistsSucceedsForOKResultWhenNotMatching(): void
|
||||||
|
{
|
||||||
|
$this->assertFalse(Result::OK(14)->exists(fn($it) => $it > 100), 'Exists should have returned false');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Exists succeeds for Error result')]
|
||||||
|
public function testExistsSucceedsForErrorResult(): void
|
||||||
|
{
|
||||||
|
$this->assertFalse(Result::Error(true)->exists(fn($it) => true), 'Exists should have returned false');
|
||||||
|
}
|
||||||
|
|
||||||
#[TestDox('Map succeeds for OK result')]
|
#[TestDox('Map succeeds for OK result')]
|
||||||
public function testMapSucceedsForOKResult(): void
|
public function testMapSucceedsForOKResult(): void
|
||||||
{
|
{
|
||||||
@@ -152,6 +226,22 @@ class ResultTest extends TestCase
|
|||||||
$this->assertNull($target->called, 'The function should not have been called');
|
$this->assertNull($target->called, 'The function should not have been called');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[TestDox('ToArray succeeds for OK result')]
|
||||||
|
public function testToArraySucceedsForOKResult(): void
|
||||||
|
{
|
||||||
|
$arr = Result::OK('yay')->toArray();
|
||||||
|
$this->assertNotNull($arr, 'The array should not have been null');
|
||||||
|
$this->assertEquals(['yay'], $arr, 'The array was not created correctly');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('ToArray succeeds for Error result')]
|
||||||
|
public function testToArraySucceedsForErrorResult(): void
|
||||||
|
{
|
||||||
|
$arr = Result::Error('oh no')->toArray();
|
||||||
|
$this->assertNotNull($arr, 'The array should not have been null');
|
||||||
|
$this->assertEmpty($arr, 'The array should have been empty');
|
||||||
|
}
|
||||||
|
|
||||||
#[TestDox('ToOption succeeds for OK result')]
|
#[TestDox('ToOption succeeds for OK result')]
|
||||||
public function testToOptionSucceedsForOKResult()
|
public function testToOptionSucceedsForOKResult()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user