Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cao Peng] iP #236

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
3b19ba1
Add Gradle support
May 24, 2020
a75fcee
build.gradle: Update version to 8.29
Aug 29, 2020
7a16622
Level-1
Cp-John Jan 21, 2021
ea64e59
Level-2
Cp-John Jan 21, 2021
e495edd
Level-3
Cp-John Jan 21, 2021
73e3146
Level-4
Cp-John Jan 21, 2021
fcc4ab3
Level-4
Cp-John Jan 21, 2021
303035e
Level-5
Cp-John Jan 21, 2021
0067f9d
Level-6
Cp-John Jan 21, 2021
8fc7617
some comment added
Cp-John Jan 21, 2021
39ffa63
Level-7
Cp-John Jan 29, 2021
4a0753b
Complete level 8
Cp-John Jan 30, 2021
8f2c0fe
Merge branch 'branch-Level-7'
Cp-John Jan 30, 2021
1544949
Standardize date format
Cp-John Jan 30, 2021
f3caea8
A-MoreOOP completed
Cp-John Jan 31, 2021
815dc30
Complete A-Packages
Cp-John Jan 31, 2021
fde4727
Add Junit tests
Cp-John Jan 31, 2021
d1a82f3
Add javadoc
Cp-John Jan 31, 2021
fcdd560
Follow the coding standard
Cp-John Jan 31, 2021
d99334b
Finish Level-9
Cp-John Jan 31, 2021
8f3229d
Create jar file
Cp-John Feb 1, 2021
17a87a7
Add varargs
Cp-John Feb 3, 2021
f1060fc
Add assertions
Cp-John Feb 10, 2021
6c910c4
Improve code quality
Cp-John Feb 10, 2021
86d417f
Merge remote-tracking branch 'origin/add-gradle-support'
Cp-John Feb 15, 2021
0bdf504
Add gradle
Cp-John Feb 15, 2021
3d5ec70
Complete GUI
Cp-John Feb 15, 2021
9ad3eb1
Delete unused package
Cp-John Feb 17, 2021
7dabba0
Complete better search and add comment
Cp-John Feb 17, 2021
863725e
Resize header image
Cp-John Feb 18, 2021
501e936
Change switch case statement format
Cp-John Feb 18, 2021
7963ef4
Merge branch 'master' into branch-A-CodeQuality
Cp-John Feb 18, 2021
7d300e3
Finish Ui design
Cp-John Feb 18, 2021
bd02cf9
Change indentation for switch case
Cp-John Feb 21, 2021
57ec9c8
Change the path of screenshot
Cp-John Feb 21, 2021
7096f31
Change the path of screenshot
Cp-John Feb 21, 2021
99365d5
Set theme jekyll-theme-cayman
Cp-John Feb 21, 2021
9dc0f28
Add user guide
Cp-John Feb 21, 2021
97e5396
Merge branch 'master' of https://github.com/Cp-John/ip
Cp-John Feb 21, 2021
03cde79
Format user guide
Cp-John Feb 21, 2021
599c846
Add jar file
Cp-John Feb 21, 2021
4c4b0b8
Add an assertion
Cp-John Feb 22, 2021
1f4a1b5
Merge pull request #3 from Cp-John/branch-A-Assertions
Cp-John Feb 22, 2021
8d54d93
Merge branch 'master' into branch-A-CodeQuality
Cp-John Feb 22, 2021
76d5460
Merge pull request #2 from Cp-John/branch-A-CodeQuality
Cp-John Feb 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Duke project template
# duke.Duke project template

This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.

Expand All @@ -12,7 +12,7 @@ Prerequisites: JDK 11, update Intellij to the most recent version.
1. Select the project directory, and click `OK`.
1. If there are any further prompts, accept the defaults.
1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
1. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()`. If the setup is correct, you should see something like the below:
1. After that, locate the `src/main/java/duke.Duke.java` file, right-click it, and choose `Run duke.Duke.main()`. If the setup is correct, you should see something like the below:
```
Hello from
____ _
Expand Down
1 change: 1 addition & 0 deletions data/duke.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[T][X] homework1
10 changes: 0 additions & 10 deletions src/main/java/Duke.java

This file was deleted.

3 changes: 3 additions & 0 deletions src/main/java/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: duke.Duke

52 changes: 52 additions & 0 deletions src/main/java/duke/Duke.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package duke;

import duke.command.Command;
import duke.exception.DukeException;

import java.util.ArrayList;

/**
* the agent program to run duke.Duke
*/
public class Duke {
private static final String FILE_PATH = "./data/duke.txt";
private Ui ui;
private TaskList tasks;
private Storage storage;
private Parser parser;

public Duke() {
this.ui = new Ui();
this.parser = new Parser();
this.storage = new Storage(FILE_PATH);

try {
this.tasks = new TaskList(storage.load());
} catch (DukeException e) {
ui.printMsg(e.getMessage());
this.tasks = new TaskList(new ArrayList<>());
}
}

public static void main(String[] args) {
new Duke().run();
}

public void run() {
ui.printGreetingMsg();

boolean isExit = false;
while(!isExit) {
String fullCommand = ui.readCommand();
ui.printLine();
try {
Command command = parser.parseCommand(fullCommand);
command.execute(tasks, ui, storage);
isExit = command.isExit();
} catch (DukeException e) {
ui.printMsg(e.getMessage());
}
ui.printLine();
}
}
}
101 changes: 101 additions & 0 deletions src/main/java/duke/Parser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package duke;

import duke.command.*;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Java coding standards stated that the imported classes should always be listed explicitly. I understand why you have imported * from duke.command package, but to comply with the guideline, would it be better to import explicitly instead?

import duke.exception.DukeException;
import duke.exception.EmptyTodoDescriptionException;
import duke.exception.UnknownCommandException;
import duke.task.Deadline;
import duke.task.Event;
import duke.task.Task;
import duke.task.ToDo;

import java.time.LocalDate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* deals with parsing the user command
*/
public class Parser {

/**
* @param fullCommand the user command
* @return a duke.command.Command object which encapsulates the information of a parsed user command
* @throws DukeException exception when there is an parsing error
*/
Comment on lines +21 to +25

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a short summary of the method could be written as the first sentence for this method header.

public Command parseCommand(String fullCommand) throws DukeException {
if (fullCommand.equals("bye")) {
return new ExitCommand();
} else if (fullCommand.equals("list")) {
return new ListCommand();
} else {
String[] parsedCommand = fullCommand.split(" ");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plural form could be used for this String array to make the variable name sound more like a collection of string values.


try {
switch (parsedCommand[0]) {
case "done", "delete":

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do note that there should be no indentation for case clauses as to adhere to the Java coding standard. I noticed the same issue in the other classes as well. Perhaps consider configuring your IDE to help with this styling?

int taskId = Integer.parseInt(parsedCommand[1]) - 1;
if (parsedCommand[0].equals("done")) {
return new DoneCommand(fullCommand, taskId);
} else {
return new DeleteCommand(fullCommand, taskId);
}
case "find":
return new FindCommand(fullCommand, fullCommand.replaceFirst("find ", ""));
case "todo", "deadline", "event":
Task task = parseTask(parsedCommand[0], fullCommand.replaceFirst(parsedCommand[0] + " ", ""));
return new AddCommand(fullCommand, task);
default:
throw new UnknownCommandException();
}
} catch (DukeException e) {
throw e;
} catch (Exception e) {
throw new DukeException("duke.command.Command parsing error!");
}
}
}

/**
* @param taskType the type of the task
* @param taskStr part of the user command which represents a task
* @return a duke.task.Task object in the user command
* @throws DukeException exception when there is a task parsing error
*/
private Task parseTask(String taskType, String taskStr) throws DukeException {
String pattern;
Pattern r;
Matcher m;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A more meaningful naming suggestion: String input, Pattern pattern, Matcher matcher. I found this issue in the Storage class as well.


if (taskType.equals("todo") && taskStr.isEmpty()) {
throw new EmptyTodoDescriptionException();
}

try {
switch (taskType) {
case "todo":
return new ToDo(taskStr);
case "deadline":
pattern = "(.*) /by (.*)$";
r = Pattern.compile(pattern);
m = r.matcher(taskStr);
if (m.find()) {
return new Deadline(m.group(1), LocalDate.parse(m.group(2)));
}
case "event":
pattern = "(.*) /at (.*)$";
r = Pattern.compile(pattern);
m = r.matcher(taskStr);
if (m.find()) {
return new Event(m.group(1), LocalDate.parse(m.group(2)));
}
default:
throw new UnknownCommandException();
}
} catch (DukeException e) {
throw e;
} catch (Exception e) {
throw new DukeException("duke.task.Task parsing error!");
}
}
}
136 changes: 136 additions & 0 deletions src/main/java/duke/Storage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package duke;

import duke.exception.DukeException;
import duke.task.Deadline;
import duke.task.Event;
import duke.task.Task;
import duke.task.ToDo;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Deals with loading tasks from the file and saving tasks in the file.
*/
public class Storage {
private String filePath;
private String dirPath;

/**
* @param filePath The file path of the file which is used to store task list.
*/
public Storage(String filePath) {
this.filePath = filePath;
parseFilePath();
}

/**
* Extracts directory path from the file path.
*/
public void parseFilePath() {
String pattern = "(.*)/(.*)$";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(filePath);
if (m.find()) {
this.dirPath = m.group(1);
}
}

/**
* Loads task list from the file and returns the task list.
* @return The task list which is loaded from the file.
* @throws DukeException Exception if there is error when loading from the file.
*/
public ArrayList<Task> load() throws DukeException {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this method name be loadTasksFromStorage to explain the method more intuitively?

// create the folder called data if not found
ArrayList<Task> tasks = new ArrayList<>();

File dir = new File(dirPath);
if (!dir.exists() || !dir.isDirectory()) {
dir.mkdir();
}

File file = new File(filePath);
try {
Scanner sc = new Scanner(file);
while (sc.hasNextLine()) {
tasks.add(parseTask(sc.nextLine()));
}
sc.close();
return tasks;
} catch (FileNotFoundException e) {
throw new DukeException("Cannot load from file!");
}
}

/**
* Parses the task string to a duke.task.Task object.
* @param str The string which represents a single task.
* @return A duke.task.Task object which represents a task as the string.
* @throws DukeException Exception if there is error when parsing the task string.
*/
public Task parseTask(String str) throws DukeException {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this method be private instead, because it is independent of the whole program and is only used by the load method from the same class as an encapsulation?

try {
char typeLabel = str.charAt(1);
boolean isDone = str.charAt(4) == 'X';
String body = str.substring(7);
String pattern;
Pattern r;
Matcher m;
switch (typeLabel) {
case 'T':
return new ToDo(body, isDone);
case 'D':
pattern = "(.*) \\(by: (.*)\\)";
r = Pattern.compile(pattern);
m = r.matcher(body);
if (m.find()) {
LocalDate deadline = LocalDate.parse(m.group(2), DateTimeFormatter.ofPattern("MMM dd yyyy"));
return new Deadline(m.group(1), isDone, deadline);
}
case 'E':
pattern = "(.*) \\(at: (.*)\\)";
r = Pattern.compile(pattern);
m = r.matcher(body);
if (m.find()) {
LocalDate time = LocalDate.parse(m.group(2), DateTimeFormatter.ofPattern("MMM dd yyyy"));
return new Event(m.group(1), isDone, time);
}
default:
throw new Exception();
}
} catch (Exception e) {
throw new DukeException("error occurs and loading from file is suspended!");
}
}

/**
* Saves the task list to the file.
* @param tasks The TaskList object whose string representation will be saved to the file.
* @throws DukeException Exception when there is an error when saving task list to the file.
*/
public void save(TaskList tasks) throws DukeException {
// make the data directory if not found
File dir = new File(dirPath);
if (!dir.exists() || !dir.isDirectory()) {
dir.mkdir();
}

try {
FileWriter writer = new FileWriter(filePath);
writer.write(tasks.toString());
writer.flush();
writer.close();
} catch (IOException e) {
throw new DukeException("Save to file error!");
}
}
}
Loading