Skip to content
Closed
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ All Result types (both Ok and Err) implement these methods:
#### Value Extraction
- `unwrap(): mixed` - Returns the success value or throws UnwrapException (extends LogicException)
- `unwrapErr(): mixed` - Returns the error value or throws UnwrapException (extends LogicException)
- `expect(string $message): mixed` - Returns the success value or throws UnwrapException with the given message and a summary of the error value
- `expectErr(string $message): mixed` - Returns the error value or throws UnwrapException with the given message and a summary of the success value
- `unwrapOr(mixed $default): mixed` - Returns the success value or a default
- `unwrapOrElse(callable $fn): mixed` - Returns the success value or computes it from the error

Expand Down
15 changes: 15 additions & 0 deletions src/Err.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,21 @@ public function unwrapErr(): mixed
return $this->value;
}

#[Override]
public function expect(string $message): never
{
throw UnwrapException::withMessage($message, $this->value);
}

/**
* @return E
*/
#[Override]
public function expectErr(string $message): mixed
{
return $this->value;
}

/**
* @template U
* @param U $default
Expand Down
15 changes: 15 additions & 0 deletions src/Ok.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,21 @@ public function unwrapErr(): never
throw UnwrapException::unwrapErrOnOk($this->value);
}

/**
* @return T
*/
#[Override]
public function expect(string $message): mixed
{
return $this->value;
}

#[Override]
public function expectErr(string $message): never
{
throw UnwrapException::withMessage($message, $this->value);
}

/**
* @template U
* @param U $default
Expand Down
22 changes: 22 additions & 0 deletions src/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,28 @@ public function unwrap(): mixed;
*/
public function unwrapErr(): mixed;

/**
* 成功値を返します。失敗の場合は指定したメッセージで例外を投げます.
*
* @param string $message 失敗時の例外メッセージ(エラー値の要約が付加されます)
*
* @return ($this is Ok<mixed> ? T : never)
*
* @throws UnwrapException $this が Err の場合
*/
public function expect(string $message): mixed;

/**
* エラー値を返します。成功の場合は指定したメッセージで例外を投げます.
*
* @param string $message 成功時の例外メッセージ(成功値の要約が付加されます)
*
* @return ($this is Err<mixed> ? E : never)
*
* @throws UnwrapException $this が Ok の場合
*/
public function expectErr(string $message): mixed;

/**
* 成功値またはデフォルト値を返します.
*
Expand Down
8 changes: 8 additions & 0 deletions src/UnwrapException.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ public static function unwrapErrOnOk(mixed $value): self
return new self(\sprintf('called Result::unwrapErr() on an Ok value: %s', self::describe($value)));
}

/**
* expect() / expectErr() 用に、呼び出し側のメッセージと値の要約から例外を生成します.
*/
public static function withMessage(string $message, mixed $value): self
{
return new self(\sprintf('%s: %s', $message, self::describe($value)));
}

/**
* 例外メッセージ用に値の要約を生成します.
*
Expand Down
25 changes: 25 additions & 0 deletions tests/ErrTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,22 @@ public function unwrap_throws_exception(): void
$err->unwrap();
}

#[Test]
public function expect_throws_withGivenMessage(): void
{
$err = new Err('error');
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('config file should be readable');
$err->expect('config file should be readable');
}

#[Test]
public function expectErr_returns_error_value(): void
{
$err = new Err('error');
$this->assertSame('error', $err->expectErr('should have an error'));
}

#[Test]
public function unwrap_throwsUnwrapException_withErrorValueInMessage(): void
{
Expand Down Expand Up @@ -146,6 +162,15 @@ public function unwrap_withMultilineStringError_keepsMessageSingleLine(): void
}
}

#[Test]
public function expect_throwsUnwrapException_withErrorValueInMessage(): void
{
$err = new Err(new \RuntimeException('boom'));
$this->expectException(UnwrapException::class);
$this->expectExceptionMessage('config file should be readable: RuntimeException: boom');
$err->expect('config file should be readable');
}

#[Test]
public function unwrapErr_returns_error_value(): void
{
Expand Down
25 changes: 25 additions & 0 deletions tests/OkTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,22 @@ public function unwrapErr_throws_exception(): void
$ok->unwrapErr();
}

#[Test]
public function expect_returns_value(): void
{
$ok = new Ok(42);
$this->assertSame(42, $ok->expect('should have a value'));
}

#[Test]
public function expectErr_throws_withGivenMessage(): void
{
$ok = new Ok(42);
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('should have an error');
$ok->expectErr('should have an error');
}

#[Test]
public function unwrapErr_throwsUnwrapException_withValueInMessage(): void
{
Expand All @@ -114,6 +130,15 @@ public function __toString(): string
$ok->unwrapErr();
}

#[Test]
public function expectErr_throwsUnwrapException_withValueInMessage(): void
{
$ok = new Ok(42);
$this->expectException(UnwrapException::class);
$this->expectExceptionMessage('should have an error: 42');
$ok->expectErr('should have an error');
}

#[Test]
public function unwrapOr_returns_value(): void
{
Expand Down
11 changes: 11 additions & 0 deletions tests/Types/result.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,17 @@ function testUnwrapOnGenericReceiver(Result $result): void
assertType('RuntimeException', $result->unwrapErr());
}

/**
* expect / expectErr も unwrap / unwrapErr と同じ条件付き戻り値型が解決される.
*
* @param Result<int, RuntimeException> $result
*/
function testExpectOnGenericReceiver(Result $result): void
{
assertType('int', $result->expect('should have a value'));
assertType('RuntimeException', $result->expectErr('should have an error'));
}

/**
* 具象レシーバでの unwrapOr / unwrapOrElse: 実行時に起こり得ない側の型を混ぜない.
*
Expand Down
Loading