The aim of this guide is to help readers understand how the system and components of RecipEditor is designed, implemented and tested. This developer guide also serves to help developers to understand the architecture of RecipEditor and some design considerations. Click to view the latest release of RecipEditor.
main or RecipEditor (in some part of the DG) is the main running program, acting as the intermediary between
the Ui and the Parser
ui: handles interactions with users, including printing messages and reading of inputsstorage: manages the storage of the list of recipes by reading and writing data to the File Directorycommand: command executor to instruct what task to performparser: interprets the user input into different commandsrecipe: Contains classes that keep track of Recipes being used when the program is running (or Model)exception: exceptions thrown by the program.
Parser parsed correct command from the user inputCommand will affect change in the Recipe Model
Command will trigger Storage to save the Recipe Model to the File DirectoryThe UI component is responsible for all user interfaces of the application.
Class: Ui.java,
Ui takes CommandResult as a parameter to show the output message after a command is completed.Class: GuiWorkFlow.java, Editor.java
The GUI component consists of 2 main classes: Editor and GuiWorkFlow
Editor extends Jframe and implements ActionListener: This is the class that brings up the GUI (using JavaFx UI
framework)GUIWorkFlow is the class that call Editor: This class have various methods that handle the transition between CLI
and GUIThe recipe module encapsulates the array, recipe and ingredient objects.
API: Ingredient.java
Stores the name, amount and unit of recipes. Smallest class in the module.
API: Recipe.java
Recipe calls Ingredient to add, edit or delete ingredients. It contains methods to parse a recipe,
convert a recipe into printable or saveable format and perform operations on ingredient and step ArrayList objects
which are instantiated whenever a Recipe object is created.
API: RecipeList.java
RecipeList calls Recipe to add, edit or delete recipes. It consists of two ArrayList objects (recipes to store
recipes and recipeTitles to store titles). It contains methods to count the number of existing recipes,
search for recipes based on the given parameter and save edited recipe into Storage.
RecipeList.recipes: store the recipeRecipeList.recipeTitles: store the recipe titles
AllRecipes.txtRecipeList.recipes and RecipeList.recipeTitles
The storage component allows data to be read from and saved to a storage file.
Class: Storage.java
Storage calls Recipe when saving data from RecipeList to an external storage file.Storage calls RecipeList when loading recipe data from external storage file to.Storage calls ParserFileException when there is an error in parsing recipe file content.Storage uses a method in RecipeFileParser to parse the content in the recipe file content.
Storage uses a method in TitleFileParser to parse AllRecipes.txt.
AllRecipes.txt: contains the recipe title of all the recipesTemplate.txt: template file for adding recipeTemporaryFile.txt: for the GUI Workflow
Class: Parser.java
Command. It parses user’s input into commands through
respective parsing functions.parseCommand will takes in the user input for parsing, and call respective parsing functions
after identifying the type of Command. Then a Command will be returned as the result of parsing.Class: TitleFileParser.java
AllRecipes.txt file into recipe titles to store in RecipeList.recipeTitlesClass: RecipeFileParser.java
Recipe
The command component has classes that extend Command, identified from user input for the software to carry out
certain tasks.
A CommandResult is returned from execute() method call of each Command.
The CommandResult consists of a single error message in String.
Each subclass of Command has their own attributes and CommandResult
from Execute method, allowing them to perform respective tasks.
All types ofCommandand their functionalities are explained below:
AddCommand: Add a valid Recipe to RecipeList, otherwise shows error message
for invalid Recipe
DeleteCommand: Remove an existing Recipe at a valid index from RecipeList,
otherwise show error message on index out of bound
ExitCommand: Deliver a CommandResult to terminate software run.
InvalidCommand: Deliver a CommandResult of invalid command
ListCommand: Print all formatted Recipe in RecipeList to screen
ViewCommand: View an existing Recipe at a valid index from RecipeList,
otherwise show error message on index out of bound
Exception for program specific exceptions
ExcessFlagsException.javaInvalidFlagException.javaMissingFlagException.javaParseException.javaParseFileException.javaRecipeNotFoundException.java
When the program starts, it will
./RecipeData/App: to store Template.txt and TemporaryFile.txt./RecipeData/Recipes: to store recipe filesAllRecipes.txt file to keep track of the recipe titlesTemplate.txt file for Add CommandTempate.txt line by line by TitleFileParser./RecipeData/Recipes./RecipeData/Recipes
RecipeFileParser class.
Check Parse Text to RecipeRecipeList.recipesRecipeList.recipeTitles
Before exiting, the program will
AllRecipes.txtThis is to prevent manual tampering of the data that might affect the data in the next run
Parser and checked for the command word by parseCommand(input).If command word is /add, parseAddCommand() will be called by Parser. If the input is a valid AddCommand,
an instance of AddCommand to instruct entering GuiWorkFlow will be returned.
If templateFileMissingException occurs,Parser will call generateFile() in Storage to create
the template file. An InvalidCommandcontaining this exception will be returned.
If command word is /edit, parseEditCommand() will be called by Parser. If the command input is a
valid EditCommand
to edit in Gui, an instance of EditCommand to instruct entering GuiWorkFlow will be returned.
If the command is invalid, one of the Exception among IndexOutOfBoundException, NumberFormatException
or FileNotFoundException occurs. An InvalidCommand containing the respective Exception message will
be returned.
If the command input is a valid EditCommand to edit in CLI, an instance of EditCommand to interpret user
input into changes made to recipe is returned.
If the command is invalid, one of the Exception among IndexOutOfBoundException, NumberFormatException
or FileNotFoundException occurs. An InvalidCommand containing the respective Exception message will
be returned.
/list, an instance of ListCommand will be returned to Parser./exit, an instance of ExitCommand will be returned to Parser.If the command word is /view, Parser will call parseViewCommand() from itself. If the command views
recipe by index, a ViewCommand that instructs showing recipe at the given index will be returned
to Parser.
If the command views recipe by title, a ViewCommand that instructs showing recipe of the given
title will be returned to Parser.
If one of the Exception among MissingFlagException, InvalidFlagException, IndexOutOfBoundException
and NumberFormatException or AssertionError occurs, an instance of InvalidCommand containing
information on the respective Exception or Error will be returned to Parser.
If the command word is /delete, Parser will call parseDeleteCommand() from itself. If the command deletes
recipe by index, a DeleteCommand that instructs deleting recipe at the given index will be returned
to Parser.
If the command deletes recipe by title, a DeleteCommand that instructs deleting recipe of the given
title will be returned to Parser.
If one of the Exception among MissingFlagException, InvalidFlagException, IndexOutOfBoundException
and NumberFormatException or AssertionError occurs, an instance of InvalidCommand containing
information on the respective Exception or Error will be returned to Parser.
If the command word is /find, Parser will call parseFindCommand() from itself. If the input is a valid
FindCommand, an instance containing the respective flag and other input information will be returned to
Parser.
If the input is shorter than the expected length of a FindCommand input, an instance of InvalidCommand containing
information on the correct format for FindCommand input will be returned to Parser.
If the command word is /help, Parser will call parseHelpCommand() from itself. If the input is a valid
HelpCommand, an instance containing input information will be returned to Parser.
If the input is not of the same length as the expected length of a HelpCommand input, an instance
of InvalidCommand
containing information on the correct format for HelpCommand input will be returned to Parser.
InvalidCommand will be returned to Parser.
Parser parsed the AddCommand, an instance of GuiWorkFlow will be createdGuiWorkFlow is elaborated in GUI WorkflowParser will call getValid() and getRecipe() from the GuiWorkFlow
AllRecipes.txt fileCommandResult instance is returned with a successful message
GUI is only triggered by Add and Edit command
Template.txt fileFrom the path, GuiWorkFlow class can detect whether it is Mode.ADD or Mode.EDIT
Mode.ADD throws an exception when the recipe title already exist in the RecipeList.recipesMode.EDIT overwrite the recipe title that already exist RecipeList.recipesEditor and a loop for subsequent entry to Editor if the user choose to fix the
content of the recipeWhen exiting the Editor, the user can choose to SAVE or EXIT
saveToTemp = True and save the content in the Editor to TemporaryFile.txtsaveToTemp = FalsesaveToTemp = False, program flow will exit the loopsaveToTemp = False, program flow will exit the loopTemporaryFile.txt file. Check Parse Text to RecipeisValid = TrueEditor and the workflow is similar as point 4. aboveisValid = FalseRecipeFileParser Class with little interaction with other classes. Hence there
will be no diagram.lineType:TITLE, DESCRIPTION, INGREDIENT, STEP, NORMALstage: TITLE_START, TITLE, TITLE_END, DESCRIPTION, INGREDIENT, STEP, NORMALstageCounter = {0,0,0,0}: count the occurrence of {TITLE, DESCRIPTION, INGREDIENT, STEP}ingredientIndex: keep track of the increment of INGREDIENT indexstepIndex: keep track of the correct increment of STEP index#) and assign the lineType for that line
lineType is a heading, assign stage appropriately, and increment stageCounterlineType is NORMALNORMAL type is dependent on the stage
stage
TITLE:
DESCRIPTION:
INGREDIENT:
INDEX. INGREDIENT_NAME / AMOUNT / UNIT
ingredientIndexSTEP
INDEX. STEP_DESCRIPTION
stepIndexstage, Headings are parseable in different order (but highly discouraged)/edit indexTemplate.txt, the recipe file with the title name corresponding to the index will be loadedEditCommand is instantiated with the corresponding flags parsed from the arguments provided by the userEditModeCommand using different constructors
(Add, Delete, Swap, Change)Recipe, which will be saved to Storage through the
RecipeList class
The edit component consists of three parts:
EditCommand and GUIWorkFlow, switches between different flagsEditModeCommand (Add, Swap, Change, Delete, Invalid)EditCommand
/edit is called, instantiates the flag parser, switches the flow between GUI and
CLI, saves the edited recipe to StorageThe FlagParser contains several functions to extract flags from the user input in the FlagType format. It is used to
instantiate the necessary EditModeCommand.
GuiWorkFlow bypasses this parsing step since there is nothing to be parsed (given that only the index is provided).
EditCommand in CLI mode. It takes in the old recipe and, once executed,
returns a new recipe which will be saved to Storage.
The user first call the edit command from the Main class which will then be passed to the Parser class. It decides whether the GUI or CLI should be called through the number of arguments passed by the user.
FindCommand is given the title or ingredient to
searchtitle
RecipeList.findRecipeTitlesFromRecipeTitle(title)CommandResult containing the string format of the found recipe arraylist is returnedingredient
RecipeList.findRecipeTitlesFromIngredientName(ingredient)CommandResult containing the string format of the found recipe arraylist is returnedtitle or ingredient is invalid
CommandResult containing failure is returned from execute().
After parsing in Parsing of Commands,ViewCommad is given the index or title of recipe
to view.
index is within the range of RecipeList:
recipe file is found by calling RecipeList.getRecipe(index).recipe information is formatted by calling recipe.getRecipeAttributesFormatted().CommandReseult containing message of formatted recipe of given index is returned from execute().index is out of the range of RecipeList:
IndexOutofBoundException is thrown when RecipeList.getRecipe(index).Ui will show message on the total number of recipes in list.CommandResult containing failure in viewing the specified recipe returned from execute().
DeleteCommad is given the index or title
of recipe to delete.recipe of given title exist in the RecipeList:
recipe file is deleted by calling Storage.deleteRecipeFile(title).recipe is updated to remove the title of the deleted recipe by calling
Storage.rewriteRecipeListToFile(title).CommandReseult containing message of successful delete of recipe of given title is returned
from execute().recipe of given title does not exis in the RecipeList:
Exception is thrown when calling Storage.deleteRecipeFile().Ui will show message on the total number of recipes in list.CommandResult containing failure in deleting the specified recipe returned from execute().HelpCommand, ListCommand, ExitCommand are simple and self-explanatory in the code. Hence no elaboration will be
madeAvid cook who wants to organize their recipe list for ease of reference and search. The user is also a fast typer who can quickly type out all the part of the recipe
Helps people who cook often to keep track of the many recipes that they have so that they don’t have to go about memorising all the recipe details. RecipEditor helps to manage all these recipes where users can add, edit and delete recipes of their choice. Furthermore, they can find relevant recipes quickly using RecipEditor. For example, if the user wants to make a dish with tomato, he/she can use RecipEditor to find recipes that uses tomato as ingredient quickly.
| Version | As a … | I want to … | So that I can … |
|---|---|---|---|
| v1.0 | new user | see usage instructions | refer to them when I forget how to use the application |
| v1.0 | user | add new recipes | store recipes that I need without having to remember everything |
| v1.0 | user | delete existing recipes | remove recipes that I no longer use so that the list will not be cluttered |
| v1.0 | user | show all recipes in my list | see the overview of what recipes I have added beforehand |
| v1.0 | user | exit the application | close the entire application |
| v2.0 | user | edit a previously saved recipe | update the recipe without having go through the trouble to delete and add the updated version of the recipe |
| v2.0 | user | find recipe by recipe name or ingredient name | locate a recipe without having to go through the entire list |
| v2.0 | user | show detailed recipe that I specified | view detailed recipe (name, description, ingredients and steps) of the one that I am interested |
| v2.0 | new user | view the list of available commands | use the appropriate command according to my needs |
Main or RecipEditor: refers to the main class that the program startsTemplate.txt: Template file generated for adding recipeTemporaryFile.txt: Temporary file generated for the GUI WorkflowAllRecipes.txt: File that contains recipe titles./RecipeData/App: Directory path to store files that are not related to recipe./RecipeData/Recipes: Directory path to store recipe filesManualTestData.rar
from Release. There are
Recipes folderAllRecipes.txt fileRecipeData folder, overwriting existing files/add command and edit directly on the templateDo you want to FIX the recipe? (Y/N), type yIncorrect number of HEADINGS! Please follow the template!/add
This Recipe Title already existed!TITLE should be a single line and less than 255 charactersaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTITLE is too long! TITLE should be less than 255 characters!/view command to check the description contentINGREDIENT format is incorrect! and further instructionsINGREDIENT index must be a positive integer!INGREDIENT index increment is incorrect! Index starts from 1/ than the format
INGREDIENT format is incorrect! and further instructions. in ingredient name
INGREDIENT amount should be a positive rational number! and further instructionsSTEP format is incorrect! and further instructionsSTEP index must be a positive integer!STEP index increment is incorrect! Index starts from 1. in step description:
AllRecipes.txt file
AllRecipes.txt while running/exit. The effect will be reflected in the next run/add, /edit,/exit, a correct AllRecipes.txt will be generated/edit

Please edit in the GUI editor!
Recipe File is missing! Regenerate Recipe File! Please try again!
>>>
/edit
/exit
AllRecipes.txt based on the ModelAllRecipes.txt
AllRecipes.txt
AllRecipes.txt with the stored recipe filesAllRecipes.txt