1
0
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:
Iku-turso 2023-03-14 15:00:04 +02:00
parent 257d8a15cb
commit 62cd2957cc
10 changed files with 167 additions and 111 deletions

View 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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View 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;

View File

@ -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", () => {

View File

@ -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;
}
}
},
};
},
});

View File

@ -0,0 +1,8 @@
import { getInjectable } from "@ogre-tools/injectable";
const monsterInjectable = getInjectable({
id: "monster",
instantiate: () => ({ hitPoints: 3 }),
});
export default monsterInjectable;

View 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;