mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Refactor to using injectable for dependency injection
Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>
This commit is contained in:
parent
257d8a15cb
commit
62cd2957cc
9
packages/kata-for-gabriel/src/cast-die.ts
Normal file
9
packages/kata-for-gabriel/src/cast-die.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
|
||||
const castDieInjectable = getInjectable({
|
||||
id: "cast-die",
|
||||
instantiate: () => () => Promise.resolve(0),
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default castDieInjectable;
|
||||
@ -1,19 +1,19 @@
|
||||
import type { Monster } from "./handle-landed-hit-on-monster-for";
|
||||
import type { Dependencies } from "./monster-beatdown";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import messageToPlayerInjectable from "./message-to-player";
|
||||
import castDieInjectable from "./cast-die";
|
||||
import monsterInjectable from "./monster";
|
||||
import handleLandedHitOnMonsterInjectable from "./handle-landed-hit-on-monster-for";
|
||||
|
||||
export const handleAttackOnMonsterFor =
|
||||
({
|
||||
monster,
|
||||
messageToPlayer,
|
||||
handleLandedHitOnMonster,
|
||||
castDie,
|
||||
}: {
|
||||
monster: Monster;
|
||||
messageToPlayer: Dependencies["messageToPlayer"];
|
||||
handleLandedHitOnMonster: () => { monsterIsDead: boolean };
|
||||
castDie: () => Promise<number>;
|
||||
}) =>
|
||||
async () => {
|
||||
const handleAttackOnMonsterInjectable = getInjectable({
|
||||
id: "handle-attack-on-monster",
|
||||
|
||||
instantiate: (di) => {
|
||||
const messageToPlayer = di.inject(messageToPlayerInjectable);
|
||||
const castDie = di.inject(castDieInjectable);
|
||||
const handleLandedHitOnMonster = di.inject(handleLandedHitOnMonsterInjectable);
|
||||
const monster = di.inject(monsterInjectable);
|
||||
|
||||
return async () => {
|
||||
messageToPlayer("You attack the monster.");
|
||||
|
||||
const dieResult = await castDie();
|
||||
@ -32,3 +32,7 @@ export const handleAttackOnMonsterFor =
|
||||
|
||||
return { gameIsOver: false };
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default handleAttackOnMonsterInjectable;
|
||||
|
||||
@ -1,25 +1,30 @@
|
||||
import type { Dependencies } from "./monster-beatdown";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import questionToPlayerInjectable from "./question-to-player";
|
||||
import messageToPlayerInjectable from "./message-to-player";
|
||||
|
||||
export const handleAttackingTheMonsterAgainFor =
|
||||
({
|
||||
messageToPlayer,
|
||||
questionToPlayer,
|
||||
}: {
|
||||
messageToPlayer: Dependencies["messageToPlayer"];
|
||||
questionToPlayer: Dependencies["questionToPlayer"];
|
||||
}) =>
|
||||
async () => {
|
||||
const playerWantsToAttackAgain = await questionToPlayer("Do you want to attack again?");
|
||||
const handleAttackingTheMonsterAgainInjectable = getInjectable({
|
||||
id: "handle-attacking-the-monster-again",
|
||||
|
||||
if (playerWantsToAttackAgain) {
|
||||
return { gameIsOver: false };
|
||||
}
|
||||
instantiate: (di) => {
|
||||
const questionToPlayer = di.inject(questionToPlayerInjectable);
|
||||
const messageToPlayer = di.inject(messageToPlayerInjectable);
|
||||
|
||||
messageToPlayer(
|
||||
"You lose your nerve mid-beat-down, and try to run away. You get eaten by a sad, disappointed monster.",
|
||||
);
|
||||
return async () => {
|
||||
const playerWantsToAttackAgain = await questionToPlayer("Do you want to attack again?");
|
||||
|
||||
messageToPlayer("You lose. Game over!");
|
||||
if (playerWantsToAttackAgain) {
|
||||
return { gameIsOver: false };
|
||||
}
|
||||
|
||||
return { gameIsOver: true };
|
||||
};
|
||||
messageToPlayer(
|
||||
"You lose your nerve mid-beat-down, and try to run away. You get eaten by a sad, disappointed monster.",
|
||||
);
|
||||
|
||||
messageToPlayer("You lose. Game over!");
|
||||
|
||||
return { gameIsOver: true };
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default handleAttackingTheMonsterAgainInjectable;
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import type { Monster } from "./handle-landed-hit-on-monster-for";
|
||||
import type { Dependencies } from "./monster-beatdown";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import messageToPlayerInjectable from "./message-to-player";
|
||||
import questionToPlayerInjectable from "./question-to-player";
|
||||
import monsterInjectable from "./monster";
|
||||
|
||||
export const handleInitialMonsterEncounterFor =
|
||||
({
|
||||
monster,
|
||||
messageToPlayer,
|
||||
questionToPlayer,
|
||||
}: {
|
||||
monster: Monster;
|
||||
messageToPlayer: Dependencies["messageToPlayer"];
|
||||
questionToPlayer: Dependencies["questionToPlayer"];
|
||||
}) =>
|
||||
async () => {
|
||||
const handleInitialMonsterEncounterInjectable = getInjectable({
|
||||
id: "handle-initial-monster-encounter",
|
||||
|
||||
instantiate: (di) => {
|
||||
const messageToPlayer = di.inject(messageToPlayerInjectable);
|
||||
const questionToPlayer = di.inject(questionToPlayerInjectable);
|
||||
const monster = di.inject(monsterInjectable);
|
||||
|
||||
return async () => {
|
||||
messageToPlayer(`You encounter a monster with ${monster.hitPoints} hit-points`);
|
||||
|
||||
const playerWantsToAttack = await questionToPlayer("Attack the monster?");
|
||||
@ -27,3 +27,7 @@ export const handleInitialMonsterEncounterFor =
|
||||
|
||||
return { gameIsOver: true };
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default handleInitialMonsterEncounterInjectable;
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
import type { Dependencies } from "./monster-beatdown";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import monsterInjectable from "./monster";
|
||||
import messageToPlayerInjectable from "./message-to-player";
|
||||
|
||||
export type Monster = {
|
||||
hitPoints: number;
|
||||
};
|
||||
const handleLandedHitOnMonsterInjectable = getInjectable({
|
||||
id: "handle-landed-hit-on-monster",
|
||||
|
||||
export const handleLandedHitOnMonsterFor =
|
||||
({
|
||||
monster,
|
||||
messageToPlayer,
|
||||
}: {
|
||||
monster: Monster;
|
||||
messageToPlayer: Dependencies["messageToPlayer"];
|
||||
}) =>
|
||||
() => {
|
||||
instantiate: (di) => {
|
||||
const monster = di.inject(monsterInjectable);
|
||||
const messageToPlayer = di.inject(messageToPlayerInjectable);
|
||||
|
||||
return () => {
|
||||
monster.hitPoints--;
|
||||
|
||||
if (monster.hitPoints) {
|
||||
@ -31,3 +28,7 @@ export const handleLandedHitOnMonsterFor =
|
||||
|
||||
return { monsterIsDead: true };
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default handleLandedHitOnMonsterInjectable;
|
||||
|
||||
9
packages/kata-for-gabriel/src/message-to-player.ts
Normal file
9
packages/kata-for-gabriel/src/message-to-player.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
|
||||
const messageToPlayerInjectable = getInjectable({
|
||||
id: "message-to-player",
|
||||
instantiate: () => (message: string) => {},
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default messageToPlayerInjectable;
|
||||
@ -1,6 +1,15 @@
|
||||
import { createGame, Dependencies } from "./monster-beatdown";
|
||||
import { Dependencies, gameInjectable } from "./monster-beatdown";
|
||||
import asyncFn, { AsyncFnMock } from "@async-fn/jest";
|
||||
import { getPromiseStatus } from "@k8slens/test-utils";
|
||||
import { createContainer } from "@ogre-tools/injectable";
|
||||
import messageToPlayerInjectable from "./message-to-player";
|
||||
import castDieInjectable from "./cast-die";
|
||||
import questionToPlayerInjectable from "./question-to-player";
|
||||
import handleInitialMonsterEncounterInjectable from "./handle-initial-monster-encounter-for";
|
||||
import monsterInjectable from "./monster";
|
||||
import handleAttackOnMonsterInjectable from "./handle-attack-on-monster-for";
|
||||
import handleLandedHitOnMonsterInjectable from "./handle-landed-hit-on-monster-for";
|
||||
import handleAttackingTheMonsterAgainInjectable from "./handle-attacking-the-monster-again-for";
|
||||
|
||||
describe("monster-beatdown", () => {
|
||||
let game: { start: () => Promise<void> };
|
||||
@ -10,15 +19,29 @@ describe("monster-beatdown", () => {
|
||||
let gamePromise: Promise<void>;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = createContainer("monster-beatdown");
|
||||
|
||||
di.register(
|
||||
castDieInjectable,
|
||||
gameInjectable,
|
||||
handleAttackOnMonsterInjectable,
|
||||
handleAttackingTheMonsterAgainInjectable,
|
||||
handleInitialMonsterEncounterInjectable,
|
||||
handleLandedHitOnMonsterInjectable,
|
||||
messageToPlayerInjectable,
|
||||
monsterInjectable,
|
||||
questionToPlayerInjectable,
|
||||
);
|
||||
|
||||
messageToPlayerMock = jest.fn();
|
||||
di.override(messageToPlayerInjectable, () => messageToPlayerMock);
|
||||
di.override(questionToPlayerInjectable, () => questionToPlayerMock);
|
||||
di.override(castDieInjectable, () => castDieMock);
|
||||
|
||||
questionToPlayerMock = asyncFn();
|
||||
castDieMock = asyncFn();
|
||||
|
||||
game = createGame({
|
||||
messageToPlayer: messageToPlayerMock,
|
||||
questionToPlayer: questionToPlayerMock,
|
||||
castDie: castDieMock,
|
||||
});
|
||||
game = di.inject(gameInjectable);
|
||||
});
|
||||
|
||||
describe("when game is not started", () => {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { handleLandedHitOnMonsterFor, Monster } from "./handle-landed-hit-on-monster-for";
|
||||
import { handleInitialMonsterEncounterFor } from "./handle-initial-monster-encounter-for";
|
||||
import { handleAttackOnMonsterFor } from "./handle-attack-on-monster-for";
|
||||
import { handleAttackingTheMonsterAgainFor } from "./handle-attacking-the-monster-again-for";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import handleInitialMonsterEncounterInjectable from "./handle-initial-monster-encounter-for";
|
||||
import handleAttackOnMonsterInjectable from "./handle-attack-on-monster-for";
|
||||
import handleAttackingTheMonsterAgainInjectable from "./handle-attacking-the-monster-again-for";
|
||||
|
||||
export type Dependencies = {
|
||||
messageToPlayer: (message: string) => void;
|
||||
@ -9,49 +9,33 @@ export type Dependencies = {
|
||||
castDie: () => Promise<number>;
|
||||
};
|
||||
|
||||
const createGame = ({ messageToPlayer, questionToPlayer, castDie }: Dependencies) => {
|
||||
const monster: Monster = { hitPoints: 3 };
|
||||
export const gameInjectable = getInjectable({
|
||||
id: "game",
|
||||
|
||||
const handleLandedHitOnMonster = handleLandedHitOnMonsterFor({ messageToPlayer, monster });
|
||||
instantiate: (di) => {
|
||||
const handleInitialMonsterEncounter = di.inject(handleInitialMonsterEncounterInjectable);
|
||||
const handleAttackOnMonster = di.inject(handleAttackOnMonsterInjectable);
|
||||
const handleAttackingTheMonsterAgain = di.inject(handleAttackingTheMonsterAgainInjectable);
|
||||
|
||||
const handleAttackOnMonster = handleAttackOnMonsterFor({
|
||||
monster,
|
||||
messageToPlayer,
|
||||
handleLandedHitOnMonster,
|
||||
castDie,
|
||||
});
|
||||
|
||||
const handleAttackingTheMonsterAgain = handleAttackingTheMonsterAgainFor({
|
||||
messageToPlayer,
|
||||
questionToPlayer,
|
||||
});
|
||||
|
||||
const handleInitialMonsterEncounter = handleInitialMonsterEncounterFor({
|
||||
messageToPlayer,
|
||||
questionToPlayer,
|
||||
monster,
|
||||
});
|
||||
|
||||
return {
|
||||
start: async () => {
|
||||
const initialEncounterResult = await handleInitialMonsterEncounter();
|
||||
if (initialEncounterResult.gameIsOver) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const attackResult = await handleAttackOnMonster();
|
||||
if (attackResult.gameIsOver) {
|
||||
return {
|
||||
start: async () => {
|
||||
const initialEncounterResult = await handleInitialMonsterEncounter();
|
||||
if (initialEncounterResult.gameIsOver) {
|
||||
return;
|
||||
}
|
||||
|
||||
const attackAgainResult = await handleAttackingTheMonsterAgain();
|
||||
if (attackAgainResult.gameIsOver) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
while (true) {
|
||||
const attackResult = await handleAttackOnMonster();
|
||||
if (attackResult.gameIsOver) {
|
||||
return;
|
||||
}
|
||||
|
||||
export { createGame };
|
||||
const attackAgainResult = await handleAttackingTheMonsterAgain();
|
||||
if (attackAgainResult.gameIsOver) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
8
packages/kata-for-gabriel/src/monster.ts
Normal file
8
packages/kata-for-gabriel/src/monster.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
|
||||
const monsterInjectable = getInjectable({
|
||||
id: "monster",
|
||||
instantiate: () => ({ hitPoints: 3 }),
|
||||
});
|
||||
|
||||
export default monsterInjectable;
|
||||
9
packages/kata-for-gabriel/src/question-to-player.ts
Normal file
9
packages/kata-for-gabriel/src/question-to-player.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
|
||||
const questionToPlayerInjectable = getInjectable({
|
||||
id: "question-to-player",
|
||||
instantiate: () => (question: string) => Promise.resolve(true),
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default questionToPlayerInjectable;
|
||||
Loading…
Reference in New Issue
Block a user