Merge pull request #18 from Kabhal/master
Added importMarkup(markupText, levelOffset)
This commit is contained in:
@@ -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));
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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("=== "),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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("### "),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user