Skip to content

Commit

Permalink
feat(logical): add and then operator
Browse files Browse the repository at this point in the history
  • Loading branch information
TomokiMiyauci committed Jul 4, 2023
1 parent 25f62ab commit c414c4c
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 13 deletions.
25 changes: 24 additions & 1 deletion operators/logical.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// This module is browser compatible.

import { isNone, isSome } from "./query.ts";
import { None, type Option } from "../spec.ts";
import { None, type Option, Some } from "../spec.ts";

/** Returns the {@link option} if it contains a value, otherwise returns {@link obtb}.
*
Expand Down Expand Up @@ -47,6 +47,29 @@ export function and<T>(option: Option<unknown>, optb: Option<T>): Option<T> {
return optb;
}

/** Returns {@link None} if the {@link option} is {@link None}, otherwise calls {@link fn} with the wrapped value and returns the result.
*
* @example
* ```ts
* import { None, Some } from "https://deno.land/x/optio/spec.ts";
* import { andThen } from "https://deno.land/x/optio/mod.ts";
* import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
*
* declare const square: (value: number) => number;
*
* assertEquals(andThen(Some.of(3), square), Some.of(9));
* assertEquals(andThen(None, square), None);
* ```
*/
export function andThen<T, U>(
option: Option<T>,
fn: (value: T) => U,
): Option<U> {
if (isNone(option)) return option;

return Some.of(fn(option.get));
}

/** Returns `Some` if exactly one of {@link option}, {@link optb} is `Some`, otherwise returns `None`.
*
* @example
Expand Down
38 changes: 26 additions & 12 deletions operators/logical_test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
// Copyright © 2023 Tomoki Miyauchi. All rights reserved. MIT license.
// This module is browser compatible.

import { and, or, xor } from "./logical.ts";
import { and, andThen, or, xor } from "./logical.ts";
import { None, Some } from "../spec.ts";
import { assert, describe, it } from "../_dev_deps.ts";
import {
assert,
assertEquals,
assertSpyCallArgs,
assertSpyCalls,
describe,
it,
spy,
} from "../_dev_deps.ts";

describe("or", () => {
it("should return option if it is Some", () => {
Expand Down Expand Up @@ -32,21 +39,28 @@ describe("and", () => {
});

describe("xor", () => {
it("should return Some if Some, None", () => {
it("should return Some if one of option or optb is Some, otherwise None", () => {
const option = Some.of(0);
assert(xor(option, None) === option);
});

it("should return Some if None, Some", () => {
const optb = Some.of(0);

assert(xor(option, None) === option);
assert(xor(None, optb) === optb);
assert(xor(Some.of(0), Some.of(1)) === None);
assert(xor(None, None) === None);
});
});

it("should return None if Some, Some", () => {
assert(xor(Some.of(0), Some.of(1)) === None);
describe("andThen", () => {
it("should return Some and call fn if option is Some", () => {
const fn = spy((v: number) => v ** 3);
assertEquals(andThen(Some.of(2), fn), Some.of(8));
assertSpyCalls(fn, 1);
assertSpyCallArgs(fn, 0, [2]);
});

it("should return None if None, None", () => {
assert(xor(None, None) === None);
it("should return None if option is None", () => {
const fn = spy((v: number) => v ** 3);
assertEquals(andThen(None, fn), None);
assertSpyCalls(fn, 0);
});
});

0 comments on commit c414c4c

Please sign in to comment.