From f3a7dd4a5aab3bfd2c4deb10b1baf5dd57d749b6 Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Fri, 8 Jun 2018 12:18:22 -0400 Subject: [PATCH] Status is now stored in Process, not returned --- src/AddIdeaProcess.ts | 22 ++++++------- src/DaVinciBot.ts | 72 +++++++++++++++++++------------------------ src/Idea.ts | 1 - src/Serialization.ts | 44 +++++++++++++------------- src/index.ts | 55 ++++++++++----------------------- 5 files changed, 81 insertions(+), 113 deletions(-) diff --git a/src/AddIdeaProcess.ts b/src/AddIdeaProcess.ts index 1efa2a5..da98378 100644 --- a/src/AddIdeaProcess.ts +++ b/src/AddIdeaProcess.ts @@ -3,23 +3,23 @@ import {BotProcess, BotStatus} from "./DaVinciBot"; export class AddIdeaProcess extends BotProcess { - description(): string { return 'Add ideas to the idea pool.'; } - - start(): BotStatus { - return BotStatus.HasOutput; + start(): void { + this.status = BotStatus.HasOutput; } - getOutput(): [string, BotStatus] { - return [`Enter as many ideas as you want, followed by ENTER. To stop entering ideas, type 'quit'`, BotStatus.NeedsInput]; + getOutput(): string { + this.status = BotStatus.NeedsInput; + return `Enter as many ideas as you want, followed by ENTER. To stop entering ideas, type 'quit'`; } - handleInput(input: string): BotStatus { + handleInput(input: string): void { if (input === 'quit') { - return BotStatus.Idle; + this.status = BotStatus.Idle; + } + else { + this.rootIdea.addChild(input); + this.status = BotStatus.NeedsInput; } - - this.rootIdea.addChild(input); - return BotStatus.NeedsInput; } finish(): void { diff --git a/src/DaVinciBot.ts b/src/DaVinciBot.ts index 288a723..c9a4d38 100644 --- a/src/DaVinciBot.ts +++ b/src/DaVinciBot.ts @@ -1,54 +1,47 @@ import { Idea } from "./Idea"; -// Manages core state and functionality of the program. +// Manages a call stack of BotProcesses export class DaVinciBot { - private _rootIdea: Idea = new Idea(); + private _processes: Array = []; - private _processes: { [name: string]: BotProcess } = {}; - private _currentProcess: string = ''; - - private _status: BotStatus = BotStatus.Idle; - - get currentProcess(): string { - return this._currentProcess; - } - - get processes(): { [name: string]: BotProcess } { - return this._processes; + get currentProcess(): BotProcess { + return this._processes[this._processes.length-1]; } get status(): BotStatus { - return this._status; - } + if (this._processes.length == 0) { + return BotStatus.Idle; + } - addProcess(name: string, process: BotProcess) { - this._processes[name] = process.init(this._rootIdea); + return this.currentProcess.status; } - startProcess(process: string) { - if (this._status !== BotStatus.Idle) { - throw new Error(`Tried to switch BotProcess without first finishing process ${this._currentProcess}`); - } - - this._currentProcess = process; - this._status = this._processes[process].start(); + startProcess(process: BotProcess) { + this._processes.push(process); + process.start(); } getOutput(): string { - let outputTuple = this._processes[this._currentProcess].getOutput(); - - this._status = outputTuple[1]; - return outputTuple[0]; + let output = this.currentProcess.getOutput(); + this.finishProcessIfIdle(); + return output; } handleInput(input: string) { - this._status = this._processes[this._currentProcess].handleInput(input); + this.currentProcess.handleInput(input); + this.finishProcessIfIdle(); } finishCurrentProcess() { - this._processes[this._currentProcess].finish(); - this._status = BotStatus.Idle; + this.currentProcess.finish(); + this._processes.pop(); + } + + finishProcessIfIdle() { + if (this.status === BotStatus.Idle) { + this.finishCurrentProcess(); + } } } @@ -62,18 +55,17 @@ export enum BotStatus // TODO make this its own file export class BotProcess { - // TODO there could be real problems if a bot is started with null root idea - rootIdea: Idea = Idea.None; - description(): string { return ''; } + bot: DaVinciBot; + rootIdea: Idea; + status: BotStatus = BotStatus.Idle; - init(rootIdea: Idea): any { + constructor(bot: DaVinciBot, rootIdea: Idea) { + this.bot = bot; this.rootIdea = rootIdea; - return this; } - start(): BotStatus { throw new Error(`Custom BotProcess must define a start method: ${typeof this}`); } - - getOutput(): [string, BotStatus] { return ['', BotStatus.Idle]; } - handleInput(input: string): BotStatus { return BotStatus.Idle; } + start(): void { } + getOutput(): string { return ''; } + handleInput(input: string): void { } finish(): void { } } diff --git a/src/Idea.ts b/src/Idea.ts index a91d0f3..a504874 100644 --- a/src/Idea.ts +++ b/src/Idea.ts @@ -14,7 +14,6 @@ export class Idea // need to be serialized because each deserialization will increment count // in the constructor before restoring the Idea's original id static TotalCount: number = 0; - static None: Idea = new Idea(); @JsonProperty("id", Number) id: number; diff --git a/src/Serialization.ts b/src/Serialization.ts index a5e2583..ee17c6d 100644 --- a/src/Serialization.ts +++ b/src/Serialization.ts @@ -6,36 +6,35 @@ import {BotProcess, BotStatus} from "./DaVinciBot"; export class LoadFileProcess extends BotProcess { - description(): string { return 'Load ideas from a file.'; } - - start(): BotStatus { - return BotStatus.NeedsInput; + start(): void { + this.status = BotStatus.NeedsInput; } - handleInput(input: string): BotStatus { + handleInput(input: string): void { if (fs.existsSync(input)) { - return new LoadProcess().init(this.rootIdea).handleInput(fs.readFileSync(input, 'utf8')); + this.bot.startProcess(new LoadProcess(this.bot, this.rootIdea)); + this.bot.handleInput(fs.readFileSync(input, 'utf8')); } else { // TODO sometimes it might be error behavior if there's no file to // load - return BotStatus.Idle; } + + this.status = BotStatus.Idle; } } export class SaveFileProcess extends BotProcess { - description(): string { return 'Save ideas to a file.'; } - - start(): BotStatus { - return BotStatus.NeedsInput; + start(): void { + this.status = BotStatus.NeedsInput; } - handleInput(input: string) { - let output = new SaveProcess().init(this.rootIdea).getOutput()[0]; - fs.writeFileSync(input, output); - return BotStatus.Idle; + handleInput(input: string): void { + this.bot.startProcess(new SaveProcess(this.bot, this.rootIdea)); + let output = this.bot.getOutput(); + fs.writeFileSync(input, output, 'utf8'); + this.status = BotStatus.Idle; } } @@ -43,13 +42,11 @@ export class LoadProcess extends BotProcess { static converter = new JsonConvert(); - description(): string { return 'Load ideas from a JSON string.'; } - - start(): BotStatus { - return BotStatus.NeedsInput; + start() { + this.status = BotStatus.NeedsInput; } - handleInput(input: string) { + handleInput(input: string): void { let jsonStart = input.indexOf('{'); let countInput = input.substr(0, jsonStart); let jsonInput = input.substr(jsonStart); @@ -61,7 +58,7 @@ export class LoadProcess extends BotProcess // Make sure TotalCount is properly set Idea.TotalCount = parseInt(countInput); - return BotStatus.Idle; + this.status = BotStatus.Idle; } finish(): void { @@ -78,7 +75,8 @@ export class SaveProcess extends BotProcess return BotStatus.HasOutput; } - getOutput(): [string, BotStatus] { - return [Idea.TotalCount + JSON.stringify(this.rootIdea), BotStatus.Idle]; + getOutput(): string { + this.status = BotStatus.Idle; + return Idea.TotalCount + JSON.stringify(this.rootIdea); } } diff --git a/src/index.ts b/src/index.ts index f4b9a7e..f109447 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ +import {Idea} from "./Idea"; import {DaVinciBot, BotStatus, BotProcess} from "./DaVinciBot"; import {AddIdeaProcess} from "./AddIdeaProcess"; import {LoadProcess, SaveProcess, LoadFileProcess, SaveFileProcess} from "./Serialization"; @@ -22,48 +23,26 @@ import * as path from "path"; /*console.log(jsonString);*/ /*console.log(deserializedIdea);*/ +let rootIdea = new Idea(); let bot: DaVinciBot = new DaVinciBot(); -bot.addProcess('AddIdeaProcess', new AddIdeaProcess()); -bot.addProcess('SaveProcess', new SaveProcess()); -bot.addProcess('LoadProcess', new LoadProcess()); -bot.addProcess('SaveFileProcess', new SaveFileProcess()); -bot.addProcess('LoadFileProcess', new LoadFileProcess()); -// Automatically save and load state -bot.startProcess('LoadFileProcess'); +// Automatically load state +bot.startProcess(new LoadFileProcess(bot, rootIdea)); bot.handleInput(path.join(os.homedir(), '.davinci.json')); -while (true) { - // TODO print all available processes - let availableProcesses = bot.processes; - for (let name in availableProcesses) { - let process = availableProcesses[name]; - console.log(`${name} - ${process.description()}`); +bot.startProcess(new AddIdeaProcess(bot, rootIdea)); + +while (bot.status !== BotStatus.Idle) { + switch (bot.status) { + case BotStatus.HasOutput: + console.log(bot.getOutput()); + break; + case BotStatus.NeedsInput: + let input = readlineSync.prompt(); + bot.handleInput(input); + break; } - - console.log(`Choose which process to run, or type 'quit'`); - let process = readlineSync.prompt(); - - if (process === 'quit') { - break; - } - - bot.startProcess(process); - - while (bot.status !== BotStatus.Idle) { - switch (bot.status) { - case BotStatus.HasOutput: - console.log(bot.getOutput()); - break; - case BotStatus.NeedsInput: - let input = readlineSync.prompt(); - bot.handleInput(input); - break; - } - } - - bot.finishCurrentProcess(); - bot.startProcess('SaveFileProcess'); - bot.handleInput(path.join(os.homedir(), '.davinci.json')); } +bot.startProcess(new SaveFileProcess(bot, rootIdea)); +bot.handleInput(path.join(os.homedir(), '.davinci.json'));