Skip to content

Commit

Permalink
Add unwrite() to CodeWriter to help with CSVs
Browse files Browse the repository at this point in the history
It's sometimes easier to deal with comma separated values by just always
throwing a ", " at the end of each element in the list, even for the
last element. The unwrite() method allows you to remove the last text
written to the CodeWriter if it matches a given substring. This
allows, for example, ", " to be "unwritten" to removing the trailing
comma without having to first check if the last text written was a
trailing comma. This is similar to Ruby's chomp() method.
  • Loading branch information
mtdowling committed Jan 7, 2022
1 parent 14e6dce commit f8a5d1d
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,49 @@ public final CodeWriter writeOptional(Object content) {
}
}

/**
* Remove the most recent text written to the CodeWriter if and only
* if the last written text is exactly equal to the given expanded
* content string.
*
* <p>This can be useful, for example, for use cases like removing
* trailing commas from lists of values.
*
* <p>For example, the following will remove ", there." from the
* end of the CodeWriter:
*
* <pre>{@code
* CodeWriter writer = new CodeWriter();
* writer.writeInline("Hello, there.");
* writer.unwrite(", there.");
* assert(writer.toString().equals("Hello\n"));
* }</pre>
*
* <p>However, the following call to unwrite will do nothing because
* the last text written to the CodeWriter does not match:
*
* <pre>{@code
* CodeWriter writer = new CodeWriter();
* writer.writeInline("Hello.");
* writer.unwrite("there.");
* assert(writer.toString().equals("Hello.\n"));
* }</pre>
*
* @param content Content to write.
* @param args String arguments to use for formatting.
* @return Returns the CodeWriter.
*/
public final CodeWriter unwrite(Object content, Object... args) {
String value = format(content, args);
int currentLength = currentState.builder.length();

if (currentState.builder.lastIndexOf(value) == currentLength - value.length()) {
currentState.builder.setLength(currentLength - value.length());
}

return this;
}

/**
* Allows calling out to arbitrary code for things like looping or
* conditional writes without breaking method chaining.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -776,4 +776,49 @@ public void sectionWithWriteInline() {

assertThat(writer.toString(), equalTo("inline addition\n"));
}

@Test
public void canUnwriteMatchingStrings() {
CodeWriter writer = new CodeWriter().insertTrailingNewline(false);
writer.writeInline("Hello there");
writer.unwrite(" there");

assertThat(writer.toString(), equalTo("Hello"));
}

@Test
public void unwriteDoesNothingWhenNoMatch() {
CodeWriter writer = new CodeWriter().insertTrailingNewline(false);
writer.writeInline("Hello there");
writer.unwrite(" nope");

assertThat(writer.toString(), equalTo("Hello there"));
}

@Test
public void canUnwriteWhenSubstringTooLong() {
CodeWriter writer = new CodeWriter().insertTrailingNewline(false);
writer.writeInline("");
writer.unwrite("nope");

assertThat(writer.toString(), equalTo(""));
}

@Test
public void canUnwriteWithTemplates() {
CodeWriter writer = new CodeWriter().insertTrailingNewline(false);
writer.writeInline("Hi.Hello");
writer.unwrite("$L", "Hello");

assertThat(writer.toString(), equalTo("Hi."));
}

@Test
public void canUnwriteWithTemplatesThatExpandToNothing() {
CodeWriter writer = new CodeWriter().insertTrailingNewline(false);
writer.writeInline("Hi.Hello");
writer.unwrite("$L", "");

assertThat(writer.toString(), equalTo("Hi.Hello"));
}
}

0 comments on commit f8a5d1d

Please sign in to comment.