Skip to content

Commit

Permalink
Refactor parsers and add tests (#235)
Browse files Browse the repository at this point in the history
* Update AboutUs.adoc for team members to commit

* Add a newline in AboutUs.adoc

* Add more use cases to Developer Guide

* Fix missing endline

* Update various docs to display TagLine

* Add placeholder image

* Fix minor typo in user guide

* Update Tagline to TagLine

* Update team name

* Fix some typos in user guide and developer guide

* Refactor parsers and add new tests

- Also fixes prefix for groups
  • Loading branch information
tanlk99 committed Nov 10, 2019
1 parent 719db90 commit f3c2c6e
Show file tree
Hide file tree
Showing 36 changed files with 314 additions and 256 deletions.
26 changes: 6 additions & 20 deletions src/main/java/tagline/logic/LogicManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

Expand Down Expand Up @@ -42,26 +43,6 @@ public LogicManager(Model model, Storage storage) {
taglineParser = new TaglineParser();
}

@Override
public CommandResult execute(String commandText) throws CommandException, ParseException {
logger.info("----------------[USER COMMAND][" + commandText + "]");

CommandResult commandResult;
Command command = taglineParser.parseCommand(commandText);
commandResult = command.execute(model);

try {
storage.saveAddressBook(model.getAddressBook());
storage.saveNoteBook(model.getNoteBook());
storage.saveGroupBook(model.getGroupBook());
storage.saveTagBook(model.getTagBook());
} catch (IOException ioe) {
throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe);
}

return commandResult;
}

@Override
public CommandResult execute(String commandText, List<Prompt> filledPrompts)
throws CommandException, ParseException {
Expand All @@ -82,6 +63,11 @@ public CommandResult execute(String commandText, List<Prompt> filledPrompts)
return commandResult;
}

@Override
public CommandResult execute(String commandText) throws CommandException, ParseException {
return execute(commandText, Collections.emptyList());
}

@Override
public ReadOnlyAddressBook getAddressBook() {
return model.getAddressBook();
Expand Down
10 changes: 7 additions & 3 deletions src/main/java/tagline/logic/parser/ParserUtil.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//@@author tanlk99
package tagline.logic.parser;

import static tagline.commons.util.CollectionUtil.requireAllNonNull;

import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
Expand All @@ -11,16 +13,17 @@
public class ParserUtil {
/**
* Parses an argument {@code String} and a {@code List} of {@code Prompt} objects, to produce
* a {@code String} including the prompt responses.
* a {@code String} including the prompt responses. Parameters must not be null.
*/
public static String getArgsWithFilledPrompts(String args, List<Prompt> filledPrompts) {
requireAllNonNull(args, filledPrompts);
StringBuilder argsBuilder = new StringBuilder(args);
for (Prompt prompt : filledPrompts) {
if (prompt.getArgumentPrefix().isEmpty()) {
argsBuilder.insert(0, " ").insert(0, prompt.getPromptResponse());
} else {
argsBuilder.append(" ").append(prompt.getArgumentPrefix())
.append(" ").append(prompt.getPromptResponse());
.append(prompt.getPromptResponse());
}
}

Expand All @@ -29,9 +32,10 @@ public static String getArgsWithFilledPrompts(String args, List<Prompt> filledPr

/**
* Gets the response corresponding to an argument prefix from a list of {@code Prompt} objects.
* If no such prompt exists, returns an empty string.
* If no such prompt exists, returns an empty string. Parameters must not be null.
*/
public static String getPromptResponseFromPrefix(String prefix, List<Prompt> filledPrompts) {
requireAllNonNull(prefix, filledPrompts);
Optional<Prompt> promptWithPrefix = filledPrompts.stream()
.filter(prompt -> prompt.getArgumentPrefix().equals(prefix))
.findFirst();
Expand Down
51 changes: 13 additions & 38 deletions src/main/java/tagline/logic/parser/TaglineParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static tagline.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static tagline.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;

import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -30,34 +31,37 @@ public class TaglineParser {
*/
private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?s)(?<commandKey>\\S+)(?<commandStr>.*)");

//@@author tanlk99
/**
* Parses user input into command for execution.
* Parses user input into a command for execution, with a list of filled prompts.
*
* @param userInput full user input string
* @param filledPrompts list of filled prompts from the user
* @return the command based on the user input
* @throws ParseException if the user input does not conform the expected format
*/
public Command parseCommand(String userInput) throws ParseException {
public Command parseCommand(String userInput, List<Prompt> filledPrompts) throws ParseException {
final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.stripLeading());
if (!matcher.matches()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
}

final String commandKey = matcher.group("commandKey");
final String commandStr = matcher.group("commandStr");

switch (commandKey) {

case ContactCommand.COMMAND_KEY:
return new ContactCommandParser().parseCommand(commandStr);
return new ContactCommandParser().parseCommand(commandStr, filledPrompts);

case NoteCommand.COMMAND_KEY:
return new NoteCommandParser().parseCommand(commandStr);
return new NoteCommandParser().parseCommand(commandStr, filledPrompts);

case GroupCommand.COMMAND_KEY:
return new GroupCommandParser().parseCommand(commandStr);
return new GroupCommandParser().parseCommand(commandStr, filledPrompts);

case TagCommand.COMMAND_KEY:
return new TagCommandParser().parseCommand(commandStr);
return new TagCommandParser().parseCommand(commandStr); //TagCommand has no prompts

case ExitCommand.COMMAND_KEY:
return new ExitCommand();
Expand All @@ -70,43 +74,14 @@ public Command parseCommand(String userInput) throws ParseException {
}
}

//@@author tanlk99
/**
* Parses user input into command for execution, with a list of filled prompts.
* Parses user input into a command for execution.
*
* @param userInput full user input string
* @param filledPrompts list of filled prompts from the user
* @return the command based on the user input
* @throws ParseException if the user input does not conform the expected format
*/
public Command parseCommand(String userInput, List<Prompt> filledPrompts) throws ParseException {
final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.stripLeading());
if (!matcher.matches()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
}

final String commandKey = matcher.group("commandKey");
final String commandStr = matcher.group("commandStr");

switch (commandKey) {

case ContactCommand.COMMAND_KEY:
return new ContactCommandParser().parseCommand(commandStr, filledPrompts);

case NoteCommand.COMMAND_KEY:
return new NoteCommandParser().parseCommand(commandStr, filledPrompts);

case GroupCommand.COMMAND_KEY:
return new GroupCommandParser().parseCommand(commandStr, filledPrompts);

case ExitCommand.COMMAND_KEY:
return new ExitCommand();

case HelpCommand.COMMAND_KEY:
return new HelpCommand();

default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
public Command parseCommand(String userInput) throws ParseException {
return parseCommand(userInput, Collections.emptyList());
}
}
54 changes: 54 additions & 0 deletions src/main/java/tagline/logic/parser/contact/ClearContactParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//@@author tanlk99
package tagline.logic.parser.contact;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import tagline.logic.commands.contact.ClearContactCommand;
import tagline.logic.parser.Parser;
import tagline.logic.parser.ParserUtil;
import tagline.logic.parser.Prompt;
import tagline.logic.parser.exceptions.ParseException;
import tagline.logic.parser.exceptions.PromptRequestException;

/**
* Parses input arguments and creates a new ClearContactCommand object.
*/
public class ClearContactParser implements Parser<ClearContactCommand> {
public static final String CONTACT_CLEAR_COMMAND_CONFIRM_STRING = "Are you sure you want to clear your contact "
+ "list? Enter 'Y' to continue.";
public static final String CONTACT_CLEAR_COMMAND_ABORTED_STRING = "The current command has been aborted.";
public static final String CONTACT_CLEAR_CONFIRM_STRING = "Y";

/**
* Validates and parses the given {@code String} of arguments and a list of prompts in the context of a
* ClearContactCommand.
*
* @throws PromptRequestException if the prompt list is empty
* @throws ParseException if the prompt response does not match the confirmation string
*/
public ClearContactCommand parse(String args, List<Prompt> promptList) throws ParseException {
if (promptList.isEmpty()) {
throw new PromptRequestException(Arrays.asList(
new Prompt("", CONTACT_CLEAR_COMMAND_CONFIRM_STRING)));
}

if (ParserUtil.getPromptResponseFromPrefix("", promptList)
.equals(CONTACT_CLEAR_CONFIRM_STRING)) {
return new ClearContactCommand();
} else {
throw new ParseException(CONTACT_CLEAR_COMMAND_ABORTED_STRING);
}
}

/**
* @see ClearContactParser#parse(String, List).
*
* Calling this method will always throw a {@code PromptRequestException} containing a single prompt requesting
* confirmation.
*/
public ClearContactCommand parse(String args) throws ParseException {
return parse(args, Collections.emptyList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,66 +20,17 @@
import tagline.logic.parser.ParserUtil;
import tagline.logic.parser.Prompt;
import tagline.logic.parser.exceptions.ParseException;
import tagline.logic.parser.exceptions.PromptRequestException;

/**
* Parses user input.
* Parses user input for contact commands.
*/
public class ContactCommandParser {
public static final String CONTACT_CLEAR_COMMAND_CONFIRM_STRING = "Are you sure you want to clear your contact"
+ " list? Enter 'Y' to continue.";
public static final String CONTACT_CLEAR_COMMAND_ABORTED_STRING = "The current command has been aborted.";
public static final String CONTACT_CLEAR_CONFIRM_CHARACTER = "Y";

/**
* Used for initial separation of command word and args.
*/
private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?<commandWord>\\S+)(?<arguments>.*)");

/**
* Parses user input into a contact command for execution.
*
* @param userInput full user input string
* @return the command based on the user input
* @throws ParseException if the user input does not conform the expected format
*/
public Command parseCommand(String userInput) throws ParseException {
final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.stripLeading());
if (!matcher.matches()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
}

final String commandWord = matcher.group("commandWord");
final String arguments = matcher.group("arguments");
switch (commandWord) {

case CreateContactCommand.COMMAND_WORD:
return new AddContactParser().parse(arguments);

case ShowContactCommand.COMMAND_WORD:
return new ShowContactParser().parse(arguments);

case EditContactCommand.COMMAND_WORD:
return new EditContactParser().parse(arguments);

case DeleteContactCommand.COMMAND_WORD:
return new DeleteContactParser().parse(arguments);

case ClearContactCommand.COMMAND_WORD:
throw new PromptRequestException(Collections.singletonList(
new Prompt("", CONTACT_CLEAR_COMMAND_CONFIRM_STRING)));

case FindContactCommand.COMMAND_WORD:
return new FindContactParser().parse(arguments);

case ListContactCommand.COMMAND_WORD:
return new ListContactCommand();

default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
}

//@@author tanlk99
/**
* Parses user input into a contact command for execution, using a list of filled prompts.
Expand All @@ -89,7 +40,7 @@ public Command parseCommand(String userInput) throws ParseException {
* @throws ParseException if the user input does not conform the expected format
*/
public Command parseCommand(String userInput, List<Prompt> promptList) throws ParseException {
final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.stripLeading());
if (!matcher.matches()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
}
Expand All @@ -101,7 +52,7 @@ public Command parseCommand(String userInput, List<Prompt> promptList) throws Pa
switch (commandWord) {

case CreateContactCommand.COMMAND_WORD:
return new AddContactParser().parse(filledArguments);
return new CreateContactParser().parse(filledArguments);

case EditContactCommand.COMMAND_WORD:
return new EditContactParser().parse(filledArguments);
Expand All @@ -119,15 +70,21 @@ public Command parseCommand(String userInput, List<Prompt> promptList) throws Pa
return new ListContactCommand();

case ClearContactCommand.COMMAND_WORD:
if (ParserUtil.getPromptResponseFromPrefix("", promptList)
.equals(CONTACT_CLEAR_CONFIRM_CHARACTER)) {
return new ClearContactCommand();
} else {
throw new ParseException(CONTACT_CLEAR_COMMAND_ABORTED_STRING);
}
return new ClearContactParser().parse(arguments, promptList);

default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
}

/**
* Parses user input into a contact command for execution.
*
* @param userInput full user input string
* @return the command based on the user input
* @throws ParseException if the user input does not conform the expected format
*/
public Command parseCommand(String userInput) throws ParseException {
return parseCommand(userInput, Collections.emptyList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import tagline.model.contact.Phone;

/**
* Contains utility methods used for parsing strings in the various *Parser classes.
* Contains utility methods used for parsing strings in the various *ContactParser classes.
*/
public class ContactParserUtil {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
import tagline.model.contact.Phone;

/**
* Parses input arguments and creates a new CreateContactCommand object
* Parses input arguments and creates a new CreateContactCommand object.
*/
public class AddContactParser implements Parser<CreateContactCommand> {
public class CreateContactParser implements Parser<CreateContactCommand> {
public static final String ADD_CONTACT_EMPTY_NAME_PROMPT_STRING = "Please enter a name.";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import tagline.model.contact.ContactId;

/**
* Parses input arguments and creates a new DeleteContactCommand object
* Parses input arguments and creates a new DeleteContactCommand object.
*/
public class DeleteContactParser implements Parser<DeleteContactCommand> {
public static final String DELETE_CONTACT_EMPTY_ID_PROMPT_STRING = "Please enter the ID of the contact to delete.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import tagline.model.contact.ContactId;

/**
* Parses input arguments and creates a new EditContactCommand object
* Parses input arguments and creates a new EditContactCommand object.
*/
public class EditContactParser implements Parser<EditContactCommand> {
public static final String EDIT_CONTACT_MISSING_ID_PROMPT_STRING = "Please enter the ID of the contact to edit.";
Expand Down
Loading

0 comments on commit f3c2c6e

Please sign in to comment.