Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A Simple Match Class.
import Match from "./Match";
const simpleMatch = new Match(
[
["reverse", (input: string) => input.split("").reverse().join("")],
["scream", (input: string) => input.toUpperCase()],
],
(input: string) => `default output: ${input}`
);
const fizzBuzz = new Match(
[
[
(input: number) => input % 15 === 0,
(input: number) => `${input} - FizzBuzz!`,
],
[(input: number) => input % 5 === 0, (input: number) => `${input} - Buzz`],
[(input: number) => input % 3 === 0, (input: number) => `${input} - Fizz`],
],
(input: number) => input
);
describe("Match", () => {
describe("Simple match", () => {
it("creates a matcher", () => {
expect(simpleMatch.match("reverse")).toBe("esrever");
expect(simpleMatch.match("scream")).toBe("SCREAM");
expect(simpleMatch.match("foo")).toBe("default output: foo");
});
});
describe("FizzBuzz", () => {
it("does a fizzbuzz", () => {
const fizzLog = [];
for (let i = 0; i < 35; i++) {
fizzLog.push(fizzBuzz.match(i));
}
expect(fizzLog).toEqual([
"0 - FizzBuzz!",
1,
2,
"3 - Fizz",
4,
"5 - Buzz",
"6 - Fizz",
7,
8,
"9 - Fizz",
"10 - Buzz",
11,
"12 - Fizz",
13,
14,
"15 - FizzBuzz!",
16,
17,
"18 - Fizz",
19,
"20 - Buzz",
"21 - Fizz",
22,
23,
"24 - Fizz",
"25 - Buzz",
26,
"27 - Fizz",
28,
29,
"30 - FizzBuzz!",
31,
32,
"33 - Fizz",
34,
]);
});
});
describe("static methods", () => {
it("Match.fromMap", () => {
const m = new Map();
m.set("a", 1);
m.set("b", 2);
m.set("_", "none");
const mfm = Match.fromMap(m);
expect(mfm.match("a")).toBe(1);
expect(mfm.match("b")).toBe(2);
expect(mfm.match("c")).toBe("none");
});
it("Match.fromObject/Match.fromObj", () => {
const o = {
a: 1,
b: 2,
_: "none",
};
const mfo = Match.fromObject(o);
expect(mfo.match("a")).toBe(1);
expect(mfo.match("b")).toBe(2);
expect(mfo.match("c")).toBe("none");
});
});
});
type ConditionalFn = (input: any) => boolean;
type Condition = string | number | symbol | ConditionalFn;
type Statement = [Condition, any] | [any];
export default class Match {
constructor(
private matchPattern: Statement[],
private defaultMatch: any = undefined
) {}
private checkCondition = (condition: Condition, input: any): boolean => {
if (typeof condition === "function") {
return condition(input);
} else {
return condition === input;
}
};
public static fromMap = (map: Map<any, any>) => {
const dMatch = map.get("_");
const matchPatterns = Array.from(map.entries()).filter(
([k, _v]: [any, any]) => k !== "_"
);
return new Match(matchPatterns, dMatch);
};
public static fromObject = (obj: Record<string | number, any>) => {
const dMatch: any = obj["_"];
const matchPatterns = Array.from(Object.entries(obj)).filter(
([k, _v]: [any, any]) => k !== "_"
);
return new Match(matchPatterns, dMatch);
};
public static fromObj = Match.fromObject;
public match = (input: any) => {
for (let [condition, value] of this.matchPattern) {
if (this.checkCondition(condition, input)) {
return typeof value === "function" ? value(input) : value;
}
}
return typeof this.defaultMatch === "function"
? this.defaultMatch(input)
: this.defaultMatch;
};
}
@frbaroni

This comment has been minimized.

Copy link

@frbaroni frbaroni commented Jul 12, 2020

This is really cool!

Maybe by using some Generics ( https://www.typescriptlang.org/docs/handbook/generics.html ) you can get ridden out of some ANYs :)

@brianboyko

This comment has been minimized.

Copy link
Owner Author

@brianboyko brianboyko commented Jul 14, 2020

Thanks frbaroni! I'm currently working on it now. The only thing is - I think the term "any" is appropriate here, not using generics, as the input values can and should work with any input. This wouldn't be nearly as useful if all the inputs had to be of the same type within each instance of the class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.