Rust-style Option and Result Classes for PHP

feat(Option, Result): add mapOr() method with tests

Ciaran 80d2d807 d118a253

+105 -21
+31 -19
README.md
··· 61 62 - Add useful methods 63 - Option 64 - - [x] `Some()` 65 - [x] `None()` 66 - [x] `isSome()` 67 - - [x] `isNone()` 68 - [x] `unwrap()` 69 - [x] `unwrapOr()` 70 - - [x] `map()` 71 - - [ ] `mapOr()` 72 - - [ ] `filter(callback $predicate)` 73 - - [ ] `expect(string $message)` 74 - - [ ] `and(mixed $value)` 75 - - [ ] `andThen(callback $fn)` - Returns result of `fn(contained value)` if some, or returns none 76 - Result 77 - - [x] `Ok()` 78 - [x] `Err()` 79 - [x] `isOk()` 80 - - [x] `isErr()` 81 - - [x] `getOk()` 82 - - [x] `getErr()` 83 - [x] `unwrap()` 84 - [x] `unwrapErr()` 85 - [x] `unwrapOr(mixed $default)` 86 - - [x] `map()` 87 - - [x] `mapErr()` 88 - - [ ] `mapOr()` - Returns contained value or computes from closure 89 - - [ ] `expect(string $message)` 90 - - [ ] `expectErr(string $message)` 91 - - [ ] `andThen(callback $fn)` 92 - - [ ] `tryCatch(callback $tryFn, callback $onMapErr)` - Returns Ok if operation is successful or calls onMapErr with the Err if it throws 93 94 ## Contributing 95
··· 61 62 - Add useful methods 63 - Option 64 + - [ ] `and()` 65 + - [ ] `andThen()` 66 + - [ ] `expect()` 67 + - [ ] `filter()` 68 + - [ ] `inspect()` 69 + - [ ] `reduce()` 70 + - [ ] `replace()` 71 + - [ ] `take()` 72 + - [ ] `takeIf()` 73 - [x] `None()` 74 + - [x] `Some()` 75 + - [x] `isNone()` 76 - [x] `isSome()` 77 + - [x] `map()` 78 + - [x] `mapOr()` 79 - [x] `unwrap()` 80 - [x] `unwrapOr()` 81 - Result 82 + - [ ] `and()` 83 + - [ ] `andThen()` 84 + - [ ] `expect()` 85 + - [ ] `expectErr()` 86 + - [ ] `inspect()` 87 + - [ ] `inspectErr()` 88 + - [ ] `or()` 89 + - [ ] `tryCatch()` 90 - [x] `Err()` 91 + - [x] `Ok()` 92 + - [x] `getErr()` 93 + - [x] `getOk()` 94 + - [x] `isErr()` 95 - [x] `isOk()` 96 + - [x] `map()` 97 + - [x] `mapErr()` 98 + - [x] `mapOr()` 99 - [x] `unwrap()` 100 - [x] `unwrapErr()` 101 - [x] `unwrapOr(mixed $default)` 102 + - Refactor 103 + - Use match where possible 104 + - Use `$this` calls where possible 105 106 ## Contributing 107
+17
docs/classes/Ciarancoza/OptionResult/Option.md
··· 140 | `$fn` | **callable** | Function to transform the value | 141 142 ***
··· 140 | `$fn` | **callable** | Function to transform the value | 141 142 *** 143 + 144 + ### mapOr 145 + 146 + Calls `fn` on a contained value if `some`, or returns $or if `none` 147 + 148 + ```php 149 + public mapOr(mixed $or, callable $fn): \Ciarancoza\OptionResult\V|\Ciarancoza\OptionResult\U 150 + ``` 151 + 152 + **Parameters:** 153 + 154 + | Parameter | Type | Description | 155 + |-----------|--------------|---------------------------------| 156 + | `$or` | **mixed** | | 157 + | `$fn` | **callable** | Function to transform the value | 158 + 159 + ***
+17
docs/classes/Ciarancoza/OptionResult/Result.md
··· 198 199 *** 200 201 ### mapErr 202 203 If `err`, transform the error value with `$fn`
··· 198 199 *** 200 201 + ### mapOr 202 + 203 + Calls `fn` on a contained value if `ok`, or returns $or if `err` 204 + 205 + ```php 206 + public mapOr(mixed $or, callable $fn): \Ciarancoza\OptionResult\V|\Ciarancoza\OptionResult\U 207 + ``` 208 + 209 + **Parameters:** 210 + 211 + | Parameter | Type | Description | 212 + |-----------|--------------|---------------------------------| 213 + | `$or` | **mixed** | | 214 + | `$fn` | **callable** | Function to transform the value | 215 + 216 + *** 217 + 218 ### mapErr 219 220 If `err`, transform the error value with `$fn`
+17
src/Option.php
··· 104 105 return Option::Some($fn($this->value)); 106 } 107 }
··· 104 105 return Option::Some($fn($this->value)); 106 } 107 + 108 + /** 109 + * Calls `fn` on a contained value if `some`, or returns $or if `none` 110 + * 111 + * @template V $or 112 + * @template U 113 + * 114 + * @param callable(T): U $fn Function to transform the value 115 + * @return V|U 116 + */ 117 + public function mapOr(mixed $or, callable $fn): mixed 118 + { 119 + return match (true) { 120 + $this->isSome() => $fn($this->unwrap()), 121 + $this->isNone() => is_callable($or) ? $or() : $or, 122 + }; 123 + } 124 }
+17
src/Result.php
··· 161 } 162 163 /** 164 * If `err`, transform the error value with `$fn` 165 * 166 * @template U
··· 161 } 162 163 /** 164 + * Calls `fn` on a contained value if `ok`, or returns $or if `err` 165 + * 166 + * @template V $or 167 + * @template U 168 + * 169 + * @param callable(T): U $fn Function to transform the value 170 + * @return V|U 171 + */ 172 + public function mapOr(mixed $or, callable $fn): mixed 173 + { 174 + return match (true) { 175 + $this->isOk() => $fn($this->unwrap()), 176 + $this->isErr() => is_callable($or) ? $or() : $or, 177 + }; 178 + } 179 + 180 + /** 181 * If `err`, transform the error value with `$fn` 182 * 183 * @template U
+3 -1
tests/OptionTest.php
··· 60 61 public function test_map_or(): void 62 { 63 - $this->markTestIncomplete('TODO'); 64 $this->assertSame(3, Option::Some('foo')->mapOr(42, fn ($v) => strlen($v))); 65 $this->assertSame(42, Option::None()->mapOr(42, fn ($v) => strlen($v))); 66 } 67 68 public function test_map_or_else(): void
··· 60 61 public function test_map_or(): void 62 { 63 $this->assertSame(3, Option::Some('foo')->mapOr(42, fn ($v) => strlen($v))); 64 $this->assertSame(42, Option::None()->mapOr(42, fn ($v) => strlen($v))); 65 + 66 + $this->assertSame(3, Option::Some('foo')->mapOr(fn () => 42, fn ($v) => strlen($v))); 67 + $this->assertSame(42, Option::None()->mapOr(fn () => 42, fn ($v) => strlen($v))); 68 } 69 70 public function test_map_or_else(): void
+3 -1
tests/ResultTest.php
··· 91 92 public function test_map_or(): void 93 { 94 - $this->markTestIncomplete('TODO'); 95 $this->assertSame(3, Result::Ok('foo')->mapOr(42, fn ($v) => strlen($v))); 96 $this->assertSame(42, Result::Err('bar')->mapOr(42, fn ($v) => strlen($v))); 97 } 98 99 public function test_map_or_else(): void
··· 91 92 public function test_map_or(): void 93 { 94 $this->assertSame(3, Result::Ok('foo')->mapOr(42, fn ($v) => strlen($v))); 95 $this->assertSame(42, Result::Err('bar')->mapOr(42, fn ($v) => strlen($v))); 96 + 97 + $this->assertSame(3, Result::Ok('foo')->mapOr(fn () => 42, fn ($v) => strlen($v))); 98 + $this->assertSame(42, Result::Err('bar')->mapOr(fn () => 42, fn ($v) => strlen($v))); 99 } 100 101 public function test_map_or_else(): void