Merge pull request #18 from Kabhal/master

Added importMarkup(markupText, levelOffset)
This commit is contained in:
Robert Winkler
2016-02-23 14:13:11 +01:00
8 changed files with 172 additions and 6 deletions

View File

@@ -23,13 +23,16 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.Normalizer;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.apache.commons.lang3.StringUtils.defaultString;
@@ -47,6 +50,7 @@ public abstract class AbstractMarkupDocBuilder implements MarkupDocBuilder {
private static final Pattern ANCHOR_UNIGNORABLE_PATTERN = Pattern.compile("[^0-9a-zA-Z-_]+");
private static final Pattern ANCHOR_IGNORABLE_PATTERN = Pattern.compile("[\\s@#&(){}\\[\\]!$*%+=/:.;,?\\\\<>|]+");
private static final String ANCHOR_SEPARATION_CHARACTERS = "_-";
private static final int MAX_TITLE_LEVEL = 4;
protected StringBuilder documentBuilder = new StringBuilder();
protected String newLine = System.getProperty("line.separator");
@@ -265,6 +269,46 @@ public abstract class AbstractMarkupDocBuilder implements MarkupDocBuilder {
return this;
}
@Override
public MarkupDocBuilder importMarkup(Reader markupText) throws IOException {
return importMarkup(markupText, 0);
}
protected void importMarkup(Markup titlePrefix, Reader markupText, int levelOffset) throws IOException {
if (levelOffset > MAX_TITLE_LEVEL)
throw new IllegalArgumentException(String.format("Specified levelOffset (%d) > max levelOffset (%d)", levelOffset, MAX_TITLE_LEVEL));
if (levelOffset < -MAX_TITLE_LEVEL)
throw new IllegalArgumentException(String.format("Specified levelOffset (%d) < min levelOffset (%d)", levelOffset, -MAX_TITLE_LEVEL));
final Pattern titlePattern = Pattern.compile(String.format("^(%s{1,%d})\\s+(.*)$", titlePrefix, MAX_TITLE_LEVEL + 1));
StringBuffer leveledText = new StringBuffer();
try (BufferedReader bufferedReader = new BufferedReader(markupText)) {
String readLine;
while ((readLine = bufferedReader.readLine()) != null) {
Matcher titleMatcher = titlePattern.matcher(readLine);
while (titleMatcher.find()) {
int titleLevel = titleMatcher.group(1).length() - 1;
String title = titleMatcher.group(2);
if (titleLevel + levelOffset > MAX_TITLE_LEVEL)
throw new IllegalArgumentException(String.format("Specified levelOffset (%d) set title '%s' level (%d) > max title level (%d)", levelOffset, title, titleLevel, MAX_TITLE_LEVEL));
if (titleLevel + levelOffset < 0)
throw new IllegalArgumentException(String.format("Specified levelOffset (%d) set title '%s' level (%d) < 0", levelOffset, title, titleLevel));
else
titleMatcher.appendReplacement(leveledText, StringUtils.repeat(titlePrefix.toString(), 1 + titleLevel + levelOffset) + " " + title);
}
titleMatcher.appendTail(leveledText);
leveledText.append(newLine);
}
}
documentBuilder.append(newLine);
documentBuilder.append(leveledText.toString());
documentBuilder.append(newLine);
}
@Override
public MarkupDocBuilder table(List<List<String>> cells) {
return tableWithColumnSpecs(null, cells);
@@ -279,6 +323,9 @@ public abstract class AbstractMarkupDocBuilder implements MarkupDocBuilder {
return fileName + "." + markup;
}
/**
* 2 newLines are needed at the end of file for file to be included without protection.
*/
@Override
public void writeToFileWithoutExtension(String directory, String fileName, Charset charset) throws IOException {
Files.createDirectories(Paths.get(directory));

View File

@@ -19,6 +19,7 @@
package io.github.robwin.markup.builder;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.List;
@@ -386,6 +387,29 @@ public interface MarkupDocBuilder {
*/
MarkupDocBuilder newLine(boolean forceLineBreak);
/**
* Import some markup text into this builder.<br/>
* This is an alias for {@link #importMarkup(Reader, int) importMarkup(markupText, 0)}.
* Newlines are normalized in the process.
*
* @param markupText markup reader to read data from
* @return this builder
* @throws IOException if I/O error occurs while reading {@code markupText}
*/
MarkupDocBuilder importMarkup(Reader markupText) throws IOException;
/**
* Import some markup text into this builder.
* Newlines are normalized in the process.
*
* @param markupText markup reader to read data from
* @param levelOffset adapt section leveling by adding {@code levelOffset} [0-5]
* @return this builder
* @throws IllegalArgumentException if levelOffset is too high for the imported markup
* @throws IOException if I/O error occurs while reading {@code markupText}
*/
MarkupDocBuilder importMarkup(Reader markupText, int levelOffset) throws IOException;
/**
* Returns a string representation of the document.
*/

View File

@@ -15,7 +15,8 @@ public class MarkupTableColumn {
}
/**
* Header constructor
* Header constructor.
*
* @param header header name
*/
public MarkupTableColumn(String header) {
@@ -23,7 +24,8 @@ public class MarkupTableColumn {
}
/**
* Header and specifiers constructor
* Header and specifiers constructor.
*
* @param header header name
* @param widthRatio width ratio
*/
@@ -33,7 +35,8 @@ public class MarkupTableColumn {
}
/**
* Set header name for this column
* Set header name for this column.
*
* @param header header name
* @return this builder
*/
@@ -43,7 +46,9 @@ public class MarkupTableColumn {
}
/**
* Set column width ratio for this column
* Set column width ratio for this column.<br/>
* Limited support : Markdown does not support column width specifiers and will ignore {@code widthRatio}.
*
* @param widthRatio width ratio integer value [0-100]. Accept relative width specifiers [0-9] for languages supporting it.
* @return this builder
*/
@@ -53,9 +58,10 @@ public class MarkupTableColumn {
}
/**
* Overrides all other specifiers (for the specified language) with this language-dependent {@code specifiers} string
* Overrides all other specifiers (for the specified language) with this language-dependent {@code specifiers} string.
*
* @param language apply the {@code specifiers} to this language only
* @param specifiers RAW language-dependent specifiers for the column
* @param specifiers RAW language-dependent specifiers string for the column
* @return this builder
*/
public MarkupTableColumn withMarkupSpecifiers(MarkupLanguage language, String specifiers) {

View File

@@ -31,6 +31,7 @@ public enum AsciiDoc implements Markup {
TABLE_COLUMN_DELIMITER_ESCAPE("\\|"), // AsciiDoctor supports both \| and {vbar}
LISTING("----"),
HARDBREAKS("[%hardbreaks]"),
TITLE("="),
DOCUMENT_TITLE("= "),
SECTION_TITLE_LEVEL1("== "),
SECTION_TITLE_LEVEL2("=== "),

View File

@@ -27,6 +27,8 @@ import io.github.robwin.markup.builder.MarkupTableColumn;
import org.apache.commons.collections.CollectionUtils;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -254,6 +256,12 @@ public class AsciiDocBuilder extends AbstractMarkupDocBuilder {
return this;
}
@Override
public MarkupDocBuilder importMarkup(Reader markupText, int levelOffset) throws IOException {
importMarkup(AsciiDoc.TITLE, markupText, levelOffset);
return this;
}
@Override
public String addfileExtension(String fileName) {
return addfileExtension(AsciiDoc.FILE_EXTENSION, fileName);

View File

@@ -29,6 +29,7 @@ public enum Markdown implements Markup {
TABLE_COLUMN_DELIMITER_ESCAPE("\\|"),
TABLE_ROW("-"),
LISTING("```"),
TITLE("#"),
DOCUMENT_TITLE("# "),
SECTION_TITLE_LEVEL1("## "),
SECTION_TITLE_LEVEL2("### "),

View File

@@ -26,9 +26,12 @@ import io.github.robwin.markup.builder.MarkupTableColumn;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import java.io.IOException;
import java.io.Reader;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.join;
@@ -38,6 +41,9 @@ import static org.apache.commons.lang3.StringUtils.join;
*/
public class MarkdownBuilder extends AbstractMarkupDocBuilder
{
private static final int MAX_TITLE_LEVEL = 5;
private static final char TITLE_PREFIX = '#';
private static Pattern TITLE_PATTERN = Pattern.compile(String.format("^%c({1,%d})( .*)$", TITLE_PREFIX, MAX_TITLE_LEVEL));
@Override
public MarkupDocBuilder copy() {
@@ -243,6 +249,12 @@ public class MarkdownBuilder extends AbstractMarkupDocBuilder
return this;
}
@Override
public MarkupDocBuilder importMarkup(Reader markupText, int levelOffset) throws IOException {
importMarkup(Markdown.TITLE, markupText, levelOffset);
return this;
}
@Override
public String addfileExtension(String fileName) {
return addfileExtension(Markdown.FILE_EXTENSION, fileName);

View File

@@ -7,7 +7,11 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import java.io.IOException;
import java.io.StringReader;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
public class AbstractMarkupDocBuilderTest {
@@ -17,6 +21,8 @@ public class AbstractMarkupDocBuilderTest {
@Before
public void setUp() {
builder = mock(AbstractMarkupDocBuilder.class, Mockito.CALLS_REAL_METHODS);
builder.newLine = System.getProperty("line.separator");
builder.documentBuilder = new StringBuilder();
}
private String normalize(Markup markup, String anchor) {
@@ -64,4 +70,65 @@ public class AbstractMarkupDocBuilderTest {
assertNormalization(Markdown.SPACE_ESCAPE, "", " @#&(){}[]!$*%+=/:.;,?\\<>| ");
assertNormalization(Markdown.SPACE_ESCAPE, "sub-action-html-query-value", " /sub/action.html/?query=value ");
}
private void assertImportMarkup(Markup markup, String expected, String text, int levelOffset) throws IOException {
builder.documentBuilder = new StringBuilder();
builder.importMarkup(markup, new StringReader(text), levelOffset);
assertEquals(expected, builder.documentBuilder.toString());
}
private void assertImportMarkupException(Markup markup, String expected, String text, int levelOffset) throws IOException {
builder.documentBuilder = new StringBuilder();
try {
builder.importMarkup(markup, new StringReader(text), levelOffset);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
assertEquals(expected, e.getMessage());
}
}
@Test
public void testImportMarkupAsciiDoc() throws IOException {
assertImportMarkup(AsciiDoc.TITLE, "\n\n", "", 0);
assertImportMarkup(AsciiDoc.TITLE, "\n\n", "", 4);
assertImportMarkupException(AsciiDoc.TITLE, "Specified levelOffset (5) > max levelOffset (4)", "", 5);
assertImportMarkup(AsciiDoc.TITLE, "\n\n", "", -4);
assertImportMarkupException(AsciiDoc.TITLE, "Specified levelOffset (-5) < min levelOffset (-4)", "", -5);
assertImportMarkup(AsciiDoc.TITLE, "\n= title\nline 1\nline 2\n\n", "= title\r\nline 1\r\nline 2", 0);
assertImportMarkup(AsciiDoc.TITLE, "\nline 1\nline 2\n\n", "line 1\nline 2", 0);
assertImportMarkup(AsciiDoc.TITLE, "\nline 1\nline 2\n\n", "line 1\nline 2", 4);
assertImportMarkup(AsciiDoc.TITLE, "\n= title\nline 1\nline 2\n= title 2\nline 3\n\n", "= title\nline 1\nline 2\n= title 2\nline 3", 0);
assertImportMarkup(AsciiDoc.TITLE, "\n===== title\nline 1\nline 2\n\n", "= title\nline 1\nline 2", 4);
assertImportMarkup(AsciiDoc.TITLE, "\n= title\nline 1\nline 2\n\n", "===== title\nline 1\nline 2", -4);
assertImportMarkupException(AsciiDoc.TITLE, "Specified levelOffset (4) set title 'title' level (1) > max title level (4)", "== title\nline 1\nline 2", 4);
assertImportMarkupException(AsciiDoc.TITLE, "Specified levelOffset (-1) set title 'title' level (0) < 0", "= title\nline 1\nline 2", -1);
assertImportMarkupException(AsciiDoc.TITLE, "Specified levelOffset (-3) set title 'title' level (1) < 0", "== title\nline 1\nline 2", -3);
}
@Test
public void testImportMarkupMarkdown() throws IOException {
assertImportMarkup(Markdown.TITLE, "\n\n", "", 0);
assertImportMarkup(Markdown.TITLE, "\n\n", "", 4);
assertImportMarkup(Markdown.TITLE, "\n\n", "", -4);
assertImportMarkupException(Markdown.TITLE, "Specified levelOffset (5) > max levelOffset (4)", "", 5);
assertImportMarkupException(Markdown.TITLE, "Specified levelOffset (-5) < min levelOffset (-4)", "", -5);
assertImportMarkup(Markdown.TITLE, "\n# title\nline 1\nline 2\n\n", "# title\r\nline 1\r\nline 2", 0);
assertImportMarkup(Markdown.TITLE, "\nline 1\nline 2\n\n", "line 1\nline 2", 0);
assertImportMarkup(Markdown.TITLE, "\nline 1\nline 2\n\n", "line 1\nline 2", 4);
assertImportMarkup(Markdown.TITLE, "\n# title\nline 1\nline 2\n# title 2\nline 3\n\n", "# title\nline 1\nline 2\n# title 2\nline 3", 0);
assertImportMarkup(Markdown.TITLE, "\n##### title\nline 1\nline 2\n\n", "# title\nline 1\nline 2", 4);
assertImportMarkup(Markdown.TITLE, "\n# title\nline 1\nline 2\n\n", "##### title\nline 1\nline 2", -4);
assertImportMarkupException(Markdown.TITLE, "Specified levelOffset (4) set title 'title' level (1) > max title level (4)", "## title\nline 1\nline 2", 4);
assertImportMarkupException(Markdown.TITLE, "Specified levelOffset (-1) set title 'title' level (0) < 0", "# title\nline 1\nline 2", -1);
assertImportMarkupException(Markdown.TITLE, "Specified levelOffset (-3) set title 'title' level (1) < 0", "## title\nline 1\nline 2", -3);
}
}