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 { getInjectable } from "@ogre-tools/injectable";
|
||||||
import type { Dependencies } from "./monster-beatdown";
|
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 =
|
const handleAttackOnMonsterInjectable = getInjectable({
|
||||||
({
|
id: "handle-attack-on-monster",
|
||||||
monster,
|
|
||||||
messageToPlayer,
|
instantiate: (di) => {
|
||||||
handleLandedHitOnMonster,
|
const messageToPlayer = di.inject(messageToPlayerInjectable);
|
||||||
castDie,
|
const castDie = di.inject(castDieInjectable);
|
||||||
}: {
|
const handleLandedHitOnMonster = di.inject(handleLandedHitOnMonsterInjectable);
|
||||||
monster: Monster;
|
const monster = di.inject(monsterInjectable);
|
||||||
messageToPlayer: Dependencies["messageToPlayer"];
|
|
||||||
handleLandedHitOnMonster: () => { monsterIsDead: boolean };
|
return async () => {
|
||||||
castDie: () => Promise<number>;
|
|
||||||
}) =>
|
|
||||||
async () => {
|
|
||||||
messageToPlayer("You attack the monster.");
|
messageToPlayer("You attack the monster.");
|
||||||
|
|
||||||
const dieResult = await castDie();
|
const dieResult = await castDie();
|
||||||
@ -32,3 +32,7 @@ export const handleAttackOnMonsterFor =
|
|||||||
|
|
||||||
return { gameIsOver: false };
|
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 =
|
const handleAttackingTheMonsterAgainInjectable = getInjectable({
|
||||||
({
|
id: "handle-attacking-the-monster-again",
|
||||||
messageToPlayer,
|
|
||||||
questionToPlayer,
|
|
||||||
}: {
|
|
||||||
messageToPlayer: Dependencies["messageToPlayer"];
|
|
||||||
questionToPlayer: Dependencies["questionToPlayer"];
|
|
||||||
}) =>
|
|
||||||
async () => {
|
|
||||||
const playerWantsToAttackAgain = await questionToPlayer("Do you want to attack again?");
|
|
||||||
|
|
||||||
if (playerWantsToAttackAgain) {
|
instantiate: (di) => {
|
||||||
return { gameIsOver: false };
|
const questionToPlayer = di.inject(questionToPlayerInjectable);
|
||||||
}
|
const messageToPlayer = di.inject(messageToPlayerInjectable);
|
||||||
|
|
||||||
messageToPlayer(
|
return async () => {
|
||||||
"You lose your nerve mid-beat-down, and try to run away. You get eaten by a sad, disappointed monster.",
|
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 { getInjectable } from "@ogre-tools/injectable";
|
||||||
import type { Dependencies } from "./monster-beatdown";
|
import messageToPlayerInjectable from "./message-to-player";
|
||||||
|
import questionToPlayerInjectable from "./question-to-player";
|
||||||
|
import monsterInjectable from "./monster";
|
||||||
|
|
||||||
export const handleInitialMonsterEncounterFor =
|
const handleInitialMonsterEncounterInjectable = getInjectable({
|
||||||
({
|
id: "handle-initial-monster-encounter",
|
||||||
monster,
|
|
||||||
messageToPlayer,
|
instantiate: (di) => {
|
||||||
questionToPlayer,
|
const messageToPlayer = di.inject(messageToPlayerInjectable);
|
||||||
}: {
|
const questionToPlayer = di.inject(questionToPlayerInjectable);
|
||||||
monster: Monster;
|
const monster = di.inject(monsterInjectable);
|
||||||
messageToPlayer: Dependencies["messageToPlayer"];
|
|
||||||
questionToPlayer: Dependencies["questionToPlayer"];
|
return async () => {
|
||||||
}) =>
|
|
||||||
async () => {
|
|
||||||
messageToPlayer(`You encounter a monster with ${monster.hitPoints} hit-points`);
|
messageToPlayer(`You encounter a monster with ${monster.hitPoints} hit-points`);
|
||||||
|
|
||||||
const playerWantsToAttack = await questionToPlayer("Attack the monster?");
|
const playerWantsToAttack = await questionToPlayer("Attack the monster?");
|
||||||
@ -27,3 +27,7 @@ export const handleInitialMonsterEncounterFor =
|
|||||||
|
|
||||||
return { gameIsOver: true };
|
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 = {
|
const handleLandedHitOnMonsterInjectable = getInjectable({
|
||||||
hitPoints: number;
|
id: "handle-landed-hit-on-monster",
|
||||||
};
|
|
||||||
|
|
||||||
export const handleLandedHitOnMonsterFor =
|
instantiate: (di) => {
|
||||||
({
|
const monster = di.inject(monsterInjectable);
|
||||||
monster,
|
const messageToPlayer = di.inject(messageToPlayerInjectable);
|
||||||
messageToPlayer,
|
|
||||||
}: {
|
return () => {
|
||||||
monster: Monster;
|
|
||||||
messageToPlayer: Dependencies["messageToPlayer"];
|
|
||||||
}) =>
|
|
||||||
() => {
|
|
||||||
monster.hitPoints--;
|
monster.hitPoints--;
|
||||||
|
|
||||||
if (monster.hitPoints) {
|
if (monster.hitPoints) {
|
||||||
@ -31,3 +28,7 @@ export const handleLandedHitOnMonsterFor =
|
|||||||
|
|
||||||
return { monsterIsDead: true };
|
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 asyncFn, { AsyncFnMock } from "@async-fn/jest";
|
||||||
import { getPromiseStatus } from "@k8slens/test-utils";
|
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", () => {
|
describe("monster-beatdown", () => {
|
||||||
let game: { start: () => Promise<void> };
|
let game: { start: () => Promise<void> };
|
||||||
@ -10,15 +19,29 @@ describe("monster-beatdown", () => {
|
|||||||
let gamePromise: Promise<void>;
|
let gamePromise: Promise<void>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
const di = createContainer("monster-beatdown");
|
||||||
|
|
||||||
|
di.register(
|
||||||
|
castDieInjectable,
|
||||||
|
gameInjectable,
|
||||||
|
handleAttackOnMonsterInjectable,
|
||||||
|
handleAttackingTheMonsterAgainInjectable,
|
||||||
|
handleInitialMonsterEncounterInjectable,
|
||||||
|
handleLandedHitOnMonsterInjectable,
|
||||||
|
messageToPlayerInjectable,
|
||||||
|
monsterInjectable,
|
||||||
|
questionToPlayerInjectable,
|
||||||
|
);
|
||||||
|
|
||||||
messageToPlayerMock = jest.fn();
|
messageToPlayerMock = jest.fn();
|
||||||
|
di.override(messageToPlayerInjectable, () => messageToPlayerMock);
|
||||||
|
di.override(questionToPlayerInjectable, () => questionToPlayerMock);
|
||||||
|
di.override(castDieInjectable, () => castDieMock);
|
||||||
|
|
||||||
questionToPlayerMock = asyncFn();
|
questionToPlayerMock = asyncFn();
|
||||||
castDieMock = asyncFn();
|
castDieMock = asyncFn();
|
||||||
|
|
||||||
game = createGame({
|
game = di.inject(gameInjectable);
|
||||||
messageToPlayer: messageToPlayerMock,
|
|
||||||
questionToPlayer: questionToPlayerMock,
|
|
||||||
castDie: castDieMock,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when game is not started", () => {
|
describe("when game is not started", () => {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { handleLandedHitOnMonsterFor, Monster } from "./handle-landed-hit-on-monster-for";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { handleInitialMonsterEncounterFor } from "./handle-initial-monster-encounter-for";
|
import handleInitialMonsterEncounterInjectable from "./handle-initial-monster-encounter-for";
|
||||||
import { handleAttackOnMonsterFor } from "./handle-attack-on-monster-for";
|
import handleAttackOnMonsterInjectable from "./handle-attack-on-monster-for";
|
||||||
import { handleAttackingTheMonsterAgainFor } from "./handle-attacking-the-monster-again-for";
|
import handleAttackingTheMonsterAgainInjectable from "./handle-attacking-the-monster-again-for";
|
||||||
|
|
||||||
export type Dependencies = {
|
export type Dependencies = {
|
||||||
messageToPlayer: (message: string) => void;
|
messageToPlayer: (message: string) => void;
|
||||||
@ -9,49 +9,33 @@ export type Dependencies = {
|
|||||||
castDie: () => Promise<number>;
|
castDie: () => Promise<number>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createGame = ({ messageToPlayer, questionToPlayer, castDie }: Dependencies) => {
|
export const gameInjectable = getInjectable({
|
||||||
const monster: Monster = { hitPoints: 3 };
|
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({
|
return {
|
||||||
monster,
|
start: async () => {
|
||||||
messageToPlayer,
|
const initialEncounterResult = await handleInitialMonsterEncounter();
|
||||||
handleLandedHitOnMonster,
|
if (initialEncounterResult.gameIsOver) {
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const attackAgainResult = await handleAttackingTheMonsterAgain();
|
while (true) {
|
||||||
if (attackAgainResult.gameIsOver) {
|
const attackResult = await handleAttackOnMonster();
|
||||||
return;
|
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