cline / option
There is no license information available for the latest version (1.1.0) of this package.
1.1.0
2025-10-03 04:59 UTC
Requires
- cline/result: ^1.0
Requires (Dev)
- cline/php-cs-fixer: dev-main
- ergebnis/composer-normalize: ^2.48
- orchestra/testbench: 10.x-dev
- pestphp/pest: ^4.1
- pestphp/pest-plugin-type-coverage: ^4.0
README
This directory contains a Rust-aligned Option
implementation with a small Result
interop. It provides expressive, null-safe code paths and ergonomic controller helpers for Laravel.
Highlights
- Null-safety with
Option::fromNullable($v)
andOption::fromValue($v, $noneValue)
- Laravel macros:
Builder|Relation|Collection::firstOption()
- Controller helpers:
unwrapOrAbort()
andunwrapOrAbortUnless()
- Full Rust naming for unwrapping and combinators
- Interop with a minimal
Result
(Ok
,Err
)
Core API
- Create:
fromNullable($v)
,fromValue($v, $noneValue)
,ensure($v|callable)
,fromReturn(callable, args, noneValue)
- Query:
isSome()
,isNone()
,contains($x)
,isSomeAnd(fn($v)=>bool)
,isNoneOr(fn($v)=>bool)
- Unwrap:
unwrap()
,expect($msg)
,unwrapOr($default)
,unwrapOrElse(fn()=>default)
,unwrapOrDefault()
- Map/Chain:
map(fn)
,mapOr($default, fn)
,mapOrElse(fn()=>default, fn)
,mapOrDefault(fn)
,andThen(fn=>Option)
- Combine:
and(Option)
,or(Option)
,orElse(fn=>Option)
(lazy),xor(Option)
,zip(Option)
,zipWith(Option, fn($a,$b)=>x)
,unzip()
,flatten()
- Match:
match(fn($v)=>x, fn()=>y)
- HTTP:
unwrapOrAbort(int $status=404, ?string $message=null)
,unwrapOrAbortUnless(bool|callable $cond, int $status=404, ?string $message=null)
- Result interop:
okOr($err)
,okOrElse(fn()=>err)
,transpose()
(Option<Result<T,E>> → Result<Option,E>)
Result API (interop)
- Types:
App\Support\Result\Ok
,App\Support\Result\Err
- Query:
isOk()
,isErr()
,ok(): Option<T>
,err(): Option<E>
,contains($x)
,containsErr($e)
- Map/Chain:
map(fn)
,mapErr(fn)
,andThen(fn=>Result)
,mapOr($default, fn)
,mapOrElse(fn($e)=>default, fn($v)=>x)
- Combine:
and(Result)
,or(Result)
,orElse(fn=>Result)
- Unwrap:
unwrap()
,unwrapErr()
,unwrapOr($default)
,unwrapOrElse(fn($e)=>x)
,expect($msg)
,expectErr($msg)
,intoOk()
,intoErr()
- Transpose:
transpose()
(Result<Option,E> → Option<Result,E>)
Laravel Integration
App\Providers\OptionServiceProvider
registersfirstOption()
macros:Illuminate\Database\Eloquent\Builder::firstOption()
Illuminate\Database\Eloquent\Relations\Relation::firstOption()
Illuminate\Support\Collection::firstOption(callable $p=null)
- Prefer
unwrapOrAbort()
/unwrapOrAbortUnless()
in controllers
Migration Notes
- Renamed to Rust terms:
getOrThrow
→unwrapOrThrow
getOrElse
→unwrapOr
getOrCall
→unwrapOrElse
- Prefer
Option::fromNullable(...)
overfromValue(..., null)
Examples
// Controller-style early return $user = User::query()->whereKey($id) ->firstOption() ->unwrapOrAbort(404); // Compose with combinators $name = Option::fromNullable($request->string('name')) ->map('trim') ->filter(fn ($s) => $s !== '') ->unwrapOr('Anonymous'); // Result interop $emailResult = Option::fromNullable($payload['email'] ?? null) ->map('strtolower') ->okOr('missing-email'); // Pattern match $label = $maybeUser->match( fn ($u) => $u->name, fn () => 'Guest', ); // Typed defaults via Defaultable use App\Support\Defaultable; final class Profile implements Defaultable { public function __construct(public string $name) { } public static function default(): self { return new self('Anonymous'); } } $profile = Option::fromNullable($maybeProfile) ->unwrapOrElse([Profile::class, 'default']);
- Utilities:
inspect(fn($v)=>void)
,cloned()